From 24271c0632373afdc3153833ef7ae08bcb26cfde Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Thu, 24 Nov 2022 23:18:53 -0800 Subject: [PATCH 01/15] wip on new packages --- package.json | 3 ++- packages/core/package.json | 14 ++++++++++ packages/core/schema/INodeDefinition.ts | 35 +++++++++++++++++++++++++ yarn.lock | 2 +- 4 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 packages/core/package.json create mode 100644 packages/core/schema/INodeDefinition.ts diff --git a/package.json b/package.json index 24809d2..befd052 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,8 @@ ], "preconstruct": { "packages": [ - "editor" + "editor", + "packages/*" ] } } diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 0000000..678c39e --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,14 @@ +{ + "name": "@interx/core", + "version": "0.0.1", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@behave-graph/core": "^0.9.11" + } +} diff --git a/packages/core/schema/INodeDefinition.ts b/packages/core/schema/INodeDefinition.ts new file mode 100644 index 0000000..76a0a73 --- /dev/null +++ b/packages/core/schema/INodeDefinition.ts @@ -0,0 +1,35 @@ +import { NodeCategory } from '@behave-graph/core'; + +export type SocketValueType = 'flow' | 'boolean' | 'integer' | 'float' | 'string'; + +export interface ISocketDefinition { + valueType: SocketValueType; +} + +export type IHasSockets = { + inputSockets: { + [key: string]: ISocketDefinition; + } + ouptutSockets: { + [key: string]: ISocketDefinition; + } +} + +export interface INodeDefinition extends IHasSockets { + typeName: string, + category: NodeCategory, + label: string, +} + +export type OutputSockets = T["ouptutSockets"]; + +export type TriggeredParams = { + writeOutput: >(param: J, value: any) => void, + readInput: (param: string) => T, + commit: (param: string) => void, +}; + +export interface IFlowNode { + definition: T; + triggered: (params: TriggeredParams) => void; +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index b3c0a96..89c4081 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10657,7 +10657,7 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -undici@5.5.1, undici@^5.4.0: +undici@^5.4.0: version "5.5.1" resolved "https://registry.yarnpkg.com/undici/-/undici-5.5.1.tgz#baaf25844a99eaa0b22e1ef8d205bffe587c8f43" integrity sha512-MEvryPLf18HvlCbLSzCW0U00IMftKGI5udnjrQbC5D4P0Hodwffhv+iGfWuJwg16Y/TK11ZFK8i+BPVW2z/eAw== From dc67ad3dfa41535130d58dc9c64109a419731815 Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Fri, 25 Nov 2022 14:34:15 -0800 Subject: [PATCH 02/15] prototype to create flow socket --- .vscode/settings.json | 5 +- package.json | 2 +- packages/core/package.json | 11 +- packages/core/schema/INodeDefinition.ts | 35 --- packages/core/src/nodes/flow/Branch.ts | 38 +++ .../src/nodes/schema/INodeDefinition.test.ts | 84 ++++++ .../core/src/nodes/schema/INodeDefinition.ts | 92 +++++++ packages/core/src/nodes/schema/testUtils.ts | 11 + packages/core/tsconfig.json | 21 ++ test/package.json | 2 +- yarn.lock | 258 +++++++++++++++++- 11 files changed, 508 insertions(+), 51 deletions(-) delete mode 100644 packages/core/schema/INodeDefinition.ts create mode 100644 packages/core/src/nodes/flow/Branch.ts create mode 100644 packages/core/src/nodes/schema/INodeDefinition.test.ts create mode 100644 packages/core/src/nodes/schema/INodeDefinition.ts create mode 100644 packages/core/src/nodes/schema/testUtils.ts create mode 100644 packages/core/tsconfig.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 8a3d3d8..c8dc691 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "prettier.configPath": ".prettierrc.js", "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true -} \ No newline at end of file + "editor.formatOnSave": true, + "typescript.tsdk": "node_modules/typescript/lib" +} diff --git a/package.json b/package.json index befd052..c26067f 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "prettier": "^2.7.1", "ts-node": ">=8.0.0", "typechain": "^8.1.1", - "typescript": ">=4.5.0" + "typescript": "^4.9.3" }, "resolutions": { "undici": "5.5.1" diff --git a/packages/core/package.json b/packages/core/package.json index 678c39e..ac5a3a5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -9,6 +9,15 @@ "author": "", "license": "ISC", "dependencies": { - "@behave-graph/core": "^0.9.11" + "@behave-graph/core": "^0.9.11", + "chai": "^4.3.7", + "hardhat": "^2.12.2", + "mocha": "^10.1.0", + "typescript": "^4.9.3" + }, + "devDependencies": { + "@types/expect": "^24.3.0", + "@types/mocha": "^10.0.0", + "ts-mocha": "^10.0.0" } } diff --git a/packages/core/schema/INodeDefinition.ts b/packages/core/schema/INodeDefinition.ts deleted file mode 100644 index 76a0a73..0000000 --- a/packages/core/schema/INodeDefinition.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { NodeCategory } from '@behave-graph/core'; - -export type SocketValueType = 'flow' | 'boolean' | 'integer' | 'float' | 'string'; - -export interface ISocketDefinition { - valueType: SocketValueType; -} - -export type IHasSockets = { - inputSockets: { - [key: string]: ISocketDefinition; - } - ouptutSockets: { - [key: string]: ISocketDefinition; - } -} - -export interface INodeDefinition extends IHasSockets { - typeName: string, - category: NodeCategory, - label: string, -} - -export type OutputSockets = T["ouptutSockets"]; - -export type TriggeredParams = { - writeOutput: >(param: J, value: any) => void, - readInput: (param: string) => T, - commit: (param: string) => void, -}; - -export interface IFlowNode { - definition: T; - triggered: (params: TriggeredParams) => void; -} \ No newline at end of file diff --git a/packages/core/src/nodes/flow/Branch.ts b/packages/core/src/nodes/flow/Branch.ts new file mode 100644 index 0000000..72cbb06 --- /dev/null +++ b/packages/core/src/nodes/flow/Branch.ts @@ -0,0 +1,38 @@ +import { IHasSockets, ISocketDefinition, makeFlowNodeDefinition, TriggeredFunction } from "../schema/INodeDefinition"; + +// [new Socket('flow', 'flow'), new Socket('boolean', 'condition')], +// [new Socket('flow', 'true'), new Socket('flow', 'false')] +// ); + +const branchSockets = { + inputSockets: { + flow: { + valueType: 'flow' + }, + condition: { + valueType: 'boolean' + } + }, + outputSockets: { + true: { + valueType: 'flow' + }, + false: { + valueType: 'flow' + } + } +} satisfies IHasSockets; + + +const Branch = makeFlowNodeDefinition({ + socketsDefinition: branchSockets, + triggered: ({ + commit, + readInput + }) => { + const value = readInput('condition'); + commit(value ? 'true' : 'false') + } +}); + +export default Branch; \ No newline at end of file diff --git a/packages/core/src/nodes/schema/INodeDefinition.test.ts b/packages/core/src/nodes/schema/INodeDefinition.test.ts new file mode 100644 index 0000000..c0687d2 --- /dev/null +++ b/packages/core/src/nodes/schema/INodeDefinition.test.ts @@ -0,0 +1,84 @@ +import { + FlowSockets, + IHasSockets, + makeFlowNodeDefinition, + OutputValueType, + readInputFn, + ValueSockets, + ExtractValueType, + ValueTypeNameMapping, +} from './INodeDefinition'; +import { expectType } from './testUtils'; + +describe('TriggeredParams', () => { + describe('writeOutput', () => { + it('can only write output to a socket in the output definition that is a value type', () => { + const vals = { + inputSockets: { + a: { + valueType: 'boolean', + }, + b: { + valueType: 'string', + }, + c: { + valueType: "flow" + } + }, + outputSockets: { + c: { + valueType: 'float', + }, + d: { + valueType: 'integer', + }, + e: { + valueType: 'flow', + }, + f: { + valueType: 'string', + }, + }, + } satisfies IHasSockets; + + const flowNode = makeFlowNodeDefinition({ + socketsDefinition: vals, + triggered: ({ + commit, + readInput, + writeOutput + }) => { + const a = readInput('a'); + + writeOutput("c", a ? 1.0 : 0.0); + } + }) + + expectType>({ + a: { + valueType: 'boolean' + }, + b: { + valueType: 'string' + } + }) + + expectType>({ + c: { + valueType: 'flow' + } + }) + + expectType>(true); + expectType>('asdfasfd'); + expectType>(false); + expectType>(1.0); + expectType>(1n); + expectType>('asdfasfd'); + + + expectType>>(['a']); + expectType>>(['b']); + }); + }); +}); diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts new file mode 100644 index 0000000..9563a12 --- /dev/null +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -0,0 +1,92 @@ +import { NodeCategory } from '@behave-graph/core'; + +export type SocketValueType = 'flow' | 'boolean' | 'integer' | 'float' | 'string' | 'jsonPath'; + +export interface ISocketDefinition { + readonly valueType: SocketValueType; +} + +export type Sockets = { + readonly [key: string]: ISocketDefinition; +}; + +export type IHasSockets = { + readonly inputSockets: Sockets; + readonly outputSockets: Sockets; +}; + +export interface INodeDefinition extends IHasSockets { + typeName: string; + category: NodeCategory; + label: string; +} + +export type ValueTypeNameMapping = { + boolean: boolean; + integer: bigint; + float: number; + string: string; + jsonPath: string; + flow: void; +}[K]; + +type OutputSockets> = T['outputSockets']; +type InputSockets = T['inputSockets']; + +type FlowSocketDef = { + valueType: 'flow'; +}; + +export type ValueSockets = Pick< + T, + { [K in keyof T]-?: T[K] extends FlowSocketDef ? never : K }[keyof T] +>; +export type FlowSockets = Pick< + T, + { [K in keyof T]-?: T[K] extends FlowSocketDef ? K : never }[keyof T] +>; + +export type ExtractValueType = ValueTypeNameMapping; + +export type OutputValueSockets = ValueSockets>; +export type InputValueSockets = ValueSockets>; +export type InputFlowSockets = FlowSockets>; +export type OutputFlowSockets = FlowSockets>; + +export type OutputValueType> = ExtractValueType< + OutputValueSockets, + J +>; + +export type InputValueType> = ExtractValueType< + InputValueSockets, + J +>; + +export type readInputFn = >( + param: J +) => InputValueType; + +export type writeOutputFn = >( + param: J, + value: OutputValueType +) => void; + +export type commitFn = >(param: J) => void; + +export type TriggeredParams = { + writeOutput: writeOutputFn; + readInput: readInputFn; + commit: commitFn; +}; + +export type TriggeredFunction = (params: TriggeredParams) => void; + +export interface IFlowNode { + socketsDefinition: T; + triggered: (params: TriggeredParams) => void; +} + +export function makeFlowNodeDefinition(flowNode: IFlowNode): IFlowNode { + return flowNode; +} diff --git a/packages/core/src/nodes/schema/testUtils.ts b/packages/core/src/nodes/schema/testUtils.ts new file mode 100644 index 0000000..00795e8 --- /dev/null +++ b/packages/core/src/nodes/schema/testUtils.ts @@ -0,0 +1,11 @@ +/** + * Assert parameter is of a specific type. + * + * @param value - Value that should be identical to type `T`. + */ +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function expectType(value: T): void { + // eslint-disable-next-line @typescript-eslint/no-empty-function +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 0000000..59e9518 --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*"], + "compilerOptions": { + "target": "ES2020", + "lib": ["es2019", "dom"], + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "jsx": "react", + "pretty": true, + "strict": true, + "skipLibCheck": true, + "declaration": true, + "removeComments": true, + "emitDeclarationOnly": true, + "resolveJsonModule": true, + "noImplicitThis": false, + "types": ["mocha"] + } +} diff --git a/test/package.json b/test/package.json index a48a177..79f2848 100644 --- a/test/package.json +++ b/test/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "ts-mocha src/**/*.test.ts" }, "author": "", "license": "ISC", diff --git a/yarn.lock b/yarn.lock index 89c4081..9d992b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,7 +22,7 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.5.5": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.5.5": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== @@ -1612,6 +1612,32 @@ dependencies: multiformats "^9.5.4" +"@jest/expect-utils@^29.3.1": + version "29.3.1" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.3.1.tgz#531f737039e9b9e27c42449798acb5bba01935b6" + integrity sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g== + dependencies: + jest-get-type "^29.2.0" + +"@jest/schemas@^29.0.0": + version "29.0.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.0.0.tgz#5f47f5994dd4ef067fb7b4188ceac45f77fe952a" + integrity sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA== + dependencies: + "@sinclair/typebox" "^0.24.1" + +"@jest/types@^29.3.1": + version "29.3.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.3.1.tgz#7c5a80777cb13e703aeec6788d044150341147e3" + integrity sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA== + dependencies: + "@jest/schemas" "^29.0.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" @@ -2429,6 +2455,11 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" +"@sinclair/typebox@^0.24.1": + version "0.24.51" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f" + integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA== + "@solana/buffer-layout@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz#75b1b11adc487234821c81dfae3119b73a5fd734" @@ -2798,6 +2829,13 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== +"@types/expect@^24.3.0": + version "24.3.0" + resolved "https://registry.yarnpkg.com/@types/expect/-/expect-24.3.0.tgz#d7cab8b3c10c2d92a0cbb31981feceb81d3486f1" + integrity sha512-aq5Z+YFBz5o2b6Sp1jigx5nsmoZMK5Ceurjwy6PZmRv7dEi1jLtkARfvB1ME+OXJUG+7TZUDcv3WoCr/aor6dQ== + dependencies: + expect "*" + "@types/form-data@0.0.33": version "0.0.33" resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-0.0.33.tgz#c9ac85b2a5fd18435b8c85d9ecb50e6d6c893ff8" @@ -2818,6 +2856,25 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" @@ -2853,6 +2910,11 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== +"@types/mocha@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.0.tgz#3d9018c575f0e3f7386c1de80ee66cc21fbb7a52" + integrity sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg== + "@types/node@*", "@types/node@>=13.7.0": version "18.11.9" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.9.tgz#02d013de7058cea16d36168ef2fc653464cfbad4" @@ -2969,6 +3031,11 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + "@types/three@^0.146.0": version "0.146.0" resolved "https://registry.yarnpkg.com/@types/three/-/three-0.146.0.tgz#83813ba0d2fff6bdc6d7fda3a77993a932bba45f" @@ -2993,6 +3060,18 @@ dependencies: "@types/node" "*" +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.14" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.14.tgz#0943473052c24bd8cf2d1de25f1a710259327237" + integrity sha512-9Pj7abXoW1RSTcZaL2Hk6G2XyLMlp5ECdVC/Zf2p/KBjC3srijLGgRAXOBjtFrJoIrvxdTKyKDA14bEcbxBaWw== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@^4.26.1": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" @@ -3683,6 +3762,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + antlr4ts@^0.5.0-alpha.4: version "0.5.0-alpha.4" resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" @@ -3801,7 +3885,7 @@ array.prototype.reduce@^1.0.4: es-array-method-boxes-properly "^1.0.0" is-string "^1.0.7" -arrify@^1.0.1: +arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== @@ -4237,7 +4321,7 @@ buffer-fill@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== -buffer-from@^1.0.0, buffer-from@^1.1.1: +buffer-from@^1.0.0, buffer-from@^1.1.0, buffer-from@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== @@ -4383,6 +4467,19 @@ chai@^4.3.6: pathval "^1.1.1" type-detect "^4.0.5" +chai@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" + integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^4.1.2" + get-func-name "^2.0.0" + loupe "^2.3.1" + pathval "^1.1.1" + type-detect "^4.0.5" + chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -4457,6 +4554,11 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.2.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.7.0.tgz#6d01b3696c59915b6ce057e4aa4adfc2fa25f5ef" + integrity sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -4927,6 +5029,13 @@ deep-eql@^4.0.1: dependencies: type-detect "^4.0.0" +deep-eql@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.2.tgz#270ceb902f87724077e6f6449aed81463f42fc1c" + integrity sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w== + dependencies: + type-detect "^4.0.0" + deep-extend@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -5019,7 +5128,12 @@ didyoumean@^1.2.2: resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== -diff@3.5.0: +diff-sequences@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.3.1.tgz#104b5b95fe725932421a9c6e5b4bef84c3f2249e" + integrity sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ== + +diff@3.5.0, diff@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== @@ -5388,6 +5502,11 @@ escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escodegen@1.8.x: version "1.8.1" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" @@ -6055,6 +6174,17 @@ evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +expect@*: + version "29.3.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.3.1.tgz#92877aad3f7deefc2e3f6430dd195b92295554a6" + integrity sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA== + dependencies: + "@jest/expect-utils" "^29.3.1" + jest-get-type "^29.2.0" + jest-matcher-utils "^29.3.1" + jest-message-util "^29.3.1" + jest-util "^29.3.1" + extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -7513,6 +7643,58 @@ jayson@^3.4.4: uuid "^8.3.2" ws "^7.4.5" +jest-diff@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.3.1.tgz#d8215b72fed8f1e647aed2cae6c752a89e757527" + integrity sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.3.1" + jest-get-type "^29.2.0" + pretty-format "^29.3.1" + +jest-get-type@^29.2.0: + version "29.2.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.2.0.tgz#726646f927ef61d583a3b3adb1ab13f3a5036408" + integrity sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA== + +jest-matcher-utils@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz#6e7f53512f80e817dfa148672bd2d5d04914a572" + integrity sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ== + dependencies: + chalk "^4.0.0" + jest-diff "^29.3.1" + jest-get-type "^29.2.0" + pretty-format "^29.3.1" + +jest-message-util@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.3.1.tgz#37bc5c468dfe5120712053dd03faf0f053bd6adb" + integrity sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.3.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.3.1" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-util@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.3.1.tgz#1dda51e378bbcb7e3bc9d8ab651445591ed373e1" + integrity sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ== + dependencies: + "@jest/types" "^29.3.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + jest-worker@^26.3.0: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" @@ -8152,7 +8334,7 @@ mkdirp@0.5.5: dependencies: minimist "^1.2.5" -mkdirp@0.5.x: +mkdirp@0.5.x, mkdirp@^0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -8206,7 +8388,7 @@ mocha@7.1.2: yargs-parser "13.1.2" yargs-unparser "1.6.0" -mocha@^10.0.0: +mocha@^10.0.0, mocha@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.1.0.tgz#dbf1114b7c3f9d0ca5de3133906aea3dfc89ef7a" integrity sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg== @@ -8835,7 +9017,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -8966,6 +9148,15 @@ prettier@^2.3.1, prettier@^2.7.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +pretty-format@^29.3.1: + version "29.3.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.3.1.tgz#1841cac822b02b4da8971dacb03e8a871b4722da" + integrity sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg== + dependencies: + "@jest/schemas" "^29.0.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -9143,6 +9334,11 @@ react-is@^16.13.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -9876,7 +10072,7 @@ source-map-js@^1.0.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map-support@^0.5.13, source-map-support@^0.5.16, source-map-support@~0.5.20: +source-map-support@^0.5.13, source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -9957,6 +10153,13 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + stacktrace-parser@^0.1.10: version "0.1.10" resolved "https://registry.yarnpkg.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" @@ -10441,6 +10644,29 @@ ts-essentials@^7.0.1: resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== +ts-mocha@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-10.0.0.tgz#41a8d099ac90dbbc64b06976c5025ffaebc53cb9" + integrity sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw== + dependencies: + ts-node "7.0.1" + optionalDependencies: + tsconfig-paths "^3.5.0" + +ts-node@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" + integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== + dependencies: + arrify "^1.0.0" + buffer-from "^1.1.0" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.5.6" + yn "^2.0.0" + ts-node@>=8.0.0: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" @@ -10479,7 +10705,7 @@ ts-standard@^11.0.0: pkg-conf "^3.1.0" standard-engine "^14.0.1" -tsconfig-paths@^3.14.1: +tsconfig-paths@^3.14.1, tsconfig-paths@^3.5.0: version "3.14.1" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== @@ -10620,11 +10846,16 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== -typescript@>=4.5.0, typescript@^4.6.4: +typescript@^4.6.4: version "4.8.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== +typescript@^4.9.3: + version "4.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" + integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== + typical@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" @@ -10657,7 +10888,7 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -undici@^5.4.0: +undici@5.5.1, undici@^5.4.0: version "5.5.1" resolved "https://registry.yarnpkg.com/undici/-/undici-5.5.1.tgz#baaf25844a99eaa0b22e1ef8d205bffe587c8f43" integrity sha512-MEvryPLf18HvlCbLSzCW0U00IMftKGI5udnjrQbC5D4P0Hodwffhv+iGfWuJwg16Y/TK11ZFK8i+BPVW2z/eAw== @@ -11210,6 +11441,11 @@ yn@3.1.1: resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" From 9fde4b40e44bdc548f6d8eb22dd4fc50430a8bb4 Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Fri, 25 Nov 2022 15:29:04 -0800 Subject: [PATCH 03/15] added branch and reusable test methods --- packages/core/package.json | 2 +- packages/core/src/nodes/flow/Branch.test.ts | 28 +++++++++++++++++++ packages/core/src/nodes/flow/Branch.ts | 7 +++-- .../core/src/nodes/schema/INodeDefinition.ts | 12 ++++++-- packages/core/src/nodes/schema/testUtils.ts | 26 +++++++++++++++++ 5 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 packages/core/src/nodes/flow/Branch.test.ts diff --git a/packages/core/package.json b/packages/core/package.json index ac5a3a5..2f6a2ee 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "mocha --require ts-node/register 'src/**/*.ts'" }, "author": "", "license": "ISC", diff --git a/packages/core/src/nodes/flow/Branch.test.ts b/packages/core/src/nodes/flow/Branch.test.ts new file mode 100644 index 0000000..6bf53bc --- /dev/null +++ b/packages/core/src/nodes/flow/Branch.test.ts @@ -0,0 +1,28 @@ +import { expect } from 'chai'; +import { buildStubbedTriggeredInvoker } from '../schema/testUtils'; +import Branch, { BranchSocketsDefinition } from './Branch'; + +describe('Branch', () => { + describe('trigger', () => { + it('commits the true output when value is true', () => { + const mockNodeVals = { + condition: true, + }; + + const { triggeredParams, getCommitedNodes } = buildStubbedTriggeredInvoker(mockNodeVals); + Branch.triggered(triggeredParams); + + expect(getCommitedNodes()).to.eql(['true']); + }); + it('commits the true output when value is false', () => { + const mockNodeVals = { + condition: false, + }; + + const { triggeredParams, getCommitedNodes } = buildStubbedTriggeredInvoker(mockNodeVals); + Branch.triggered(triggeredParams); + + expect(getCommitedNodes()).to.eql(['false']); + }); + }); +}); diff --git a/packages/core/src/nodes/flow/Branch.ts b/packages/core/src/nodes/flow/Branch.ts index 72cbb06..c713c99 100644 --- a/packages/core/src/nodes/flow/Branch.ts +++ b/packages/core/src/nodes/flow/Branch.ts @@ -1,10 +1,10 @@ -import { IHasSockets, ISocketDefinition, makeFlowNodeDefinition, TriggeredFunction } from "../schema/INodeDefinition"; +import { IFlowNode, IHasSockets, ISocketDefinition, makeFlowNodeDefinition, TriggeredFunction } from "../schema/INodeDefinition"; // [new Socket('flow', 'flow'), new Socket('boolean', 'condition')], // [new Socket('flow', 'true'), new Socket('flow', 'false')] // ); -const branchSockets = { +export const branchSockets = { inputSockets: { flow: { valueType: 'flow' @@ -23,6 +23,7 @@ const branchSockets = { } } satisfies IHasSockets; +export type BranchSocketsDefinition = typeof branchSockets; const Branch = makeFlowNodeDefinition({ socketsDefinition: branchSockets, @@ -33,6 +34,6 @@ const Branch = makeFlowNodeDefinition({ const value = readInput('condition'); commit(value ? 'true' : 'false') } -}); +}) satisfies IFlowNode; export default Branch; \ No newline at end of file diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index 9563a12..9050451 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -31,7 +31,7 @@ export type ValueTypeNameMapping = { }[K]; type OutputSockets> = T['outputSockets']; -type InputSockets = T['inputSockets']; +type InputSockets> = T['inputSockets']; type FlowSocketDef = { valueType: 'flow'; @@ -49,9 +49,9 @@ export type FlowSockets = Pick< export type ExtractValueType = ValueTypeNameMapping; export type OutputValueSockets = ValueSockets>; -export type InputValueSockets = ValueSockets>; +export type InputValueSockets> = ValueSockets>; export type InputFlowSockets = FlowSockets>; -export type OutputFlowSockets = FlowSockets>; +export type OutputFlowSockets> = FlowSockets>; export type OutputValueType> = ExtractValueType< OutputValueSockets, @@ -87,6 +87,12 @@ export interface IFlowNode { triggered: (params: TriggeredParams) => void; } +export type NodeInputValues> = { + [K in keyof InputValueSockets]: ValueTypeNameMapping[K]['valueType']>; +}; + +export type OutputFlowSocketNames> = keyof OutputFlowSockets; + export function makeFlowNodeDefinition(flowNode: IFlowNode): IFlowNode { return flowNode; } diff --git a/packages/core/src/nodes/schema/testUtils.ts b/packages/core/src/nodes/schema/testUtils.ts index 00795e8..208a45e 100644 --- a/packages/core/src/nodes/schema/testUtils.ts +++ b/packages/core/src/nodes/schema/testUtils.ts @@ -5,7 +5,33 @@ */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore + +import { IHasSockets, NodeInputValues, OutputFlowSocketNames, TriggeredParams } from './INodeDefinition'; + // eslint-disable-next-line @typescript-eslint/no-unused-vars export function expectType(value: T): void { // eslint-disable-next-line @typescript-eslint/no-empty-function } + +export const buildStubbedTriggeredInvoker = (mockState: NodeInputValues) => { + const committedNodes: OutputFlowSocketNames[] = []; + + const getCommitedNodes = () => committedNodes; + + const triggeredParams: TriggeredParams = { + commit: (param) => { + committedNodes.push(param); + }, + readInput: (param) => { + return mockState[param]; + }, + writeOutput: () => { + throw new Error('not implemented'); + }, + }; + + return { + triggeredParams, + getCommitedNodes, + }; +}; From 2e497da22ba3a803c1e83bd4ee4ac5cd3772be3d Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Sat, 26 Nov 2022 07:23:56 -0800 Subject: [PATCH 04/15] need to store state --- packages/core/src/nodes/flow/Branch.test.ts | 28 +++++++--- packages/core/src/nodes/flow/Branch.ts | 4 +- packages/core/src/nodes/flow/Counter.ts | 53 +++++++++++++++++++ .../core/src/nodes/schema/INodeDefinition.ts | 13 +++-- packages/core/src/nodes/schema/testUtils.ts | 39 +++++++++++--- 5 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 packages/core/src/nodes/flow/Counter.ts diff --git a/packages/core/src/nodes/flow/Branch.test.ts b/packages/core/src/nodes/flow/Branch.test.ts index 6bf53bc..53ad08c 100644 --- a/packages/core/src/nodes/flow/Branch.test.ts +++ b/packages/core/src/nodes/flow/Branch.test.ts @@ -1,6 +1,8 @@ import { expect } from 'chai'; -import { buildStubbedTriggeredInvoker } from '../schema/testUtils'; -import Branch, { BranchSocketsDefinition } from './Branch'; +import { buildStubbedTriggeredInvoker, RecordedOutputWrites } from '../schema/testUtils'; +import Branch, { branchSockets } from './Branch'; + +type BranchSocketsDefinition = typeof branchSockets; describe('Branch', () => { describe('trigger', () => { @@ -10,9 +12,16 @@ describe('Branch', () => { }; const { triggeredParams, getCommitedNodes } = buildStubbedTriggeredInvoker(mockNodeVals); - Branch.triggered(triggeredParams); + Branch.triggered(triggeredParams, 'flow'); + + const expected = [ + { + writeType: 'flow', + socketName: 'true', + }, + ]; - expect(getCommitedNodes()).to.eql(['true']); + expect(getCommitedNodes()).to.eql(expected); }); it('commits the true output when value is false', () => { const mockNodeVals = { @@ -20,9 +29,16 @@ describe('Branch', () => { }; const { triggeredParams, getCommitedNodes } = buildStubbedTriggeredInvoker(mockNodeVals); - Branch.triggered(triggeredParams); + Branch.triggered(triggeredParams, 'flow'); + + const expected = [ + { + writeType: 'flow', + socketName: 'false', + }, + ]; - expect(getCommitedNodes()).to.eql(['false']); + expect(getCommitedNodes()).to.eql(expected); }); }); }); diff --git a/packages/core/src/nodes/flow/Branch.ts b/packages/core/src/nodes/flow/Branch.ts index c713c99..eb186e2 100644 --- a/packages/core/src/nodes/flow/Branch.ts +++ b/packages/core/src/nodes/flow/Branch.ts @@ -23,7 +23,7 @@ export const branchSockets = { } } satisfies IHasSockets; -export type BranchSocketsDefinition = typeof branchSockets; +// export type BranchSocketsDefinition = typeof branchSockets; const Branch = makeFlowNodeDefinition({ socketsDefinition: branchSockets, @@ -34,6 +34,6 @@ const Branch = makeFlowNodeDefinition({ const value = readInput('condition'); commit(value ? 'true' : 'false') } -}) satisfies IFlowNode; +}); export default Branch; \ No newline at end of file diff --git a/packages/core/src/nodes/flow/Counter.ts b/packages/core/src/nodes/flow/Counter.ts new file mode 100644 index 0000000..c2a412e --- /dev/null +++ b/packages/core/src/nodes/flow/Counter.ts @@ -0,0 +1,53 @@ +import { IFlowNode, IHasSockets, makeFlowNodeDefinition } from "../schema/INodeDefinition"; + +// [new Socket('flow', 'flow'), new Socket('flow', 'reset')], +// [new Socket('flow', 'flow'), new Socket('integer', 'count')] + +export const counterSockets = { + inputSockets: { + flow: { + valueType: 'flow' + }, + reset: { + valueType: 'flow' + } + }, + outputSockets: { + flow: { + valueType: 'flow', + }, + count: { + valueType: 'integer' + } + } +} satisfies IHasSockets; + +export type CounterSocketsDefinition = typeof counterSockets; + +let count = 0n; + +const Counter = makeFlowNodeDefinition({ + socketsDefinition: counterSockets, + triggered: ({ + commit, + writeOutput + }, triggeringSocketName) => { + + switch (triggeringSocketName) { + case 'flow': { + count++; + writeOutput('count', count); + commit('flow'); + break; + } + case 'reset': { + count++; + break; + } + default: + throw new Error('should not get here'); + } + } +}); + +export default Counter; \ No newline at end of file diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index 9050451..3d1b9bf 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -48,9 +48,9 @@ export type FlowSockets = Pick< export type ExtractValueType = ValueTypeNameMapping; -export type OutputValueSockets = ValueSockets>; +export type OutputValueSockets> = ValueSockets>; export type InputValueSockets> = ValueSockets>; -export type InputFlowSockets = FlowSockets>; +export type InputFlowSockets> = FlowSockets>; export type OutputFlowSockets> = FlowSockets>; export type OutputValueType> = ExtractValueType< @@ -80,11 +80,15 @@ export type TriggeredParams = { commit: commitFn; }; -export type TriggeredFunction = (params: TriggeredParams) => void; +export type InputFlowSocketNames> = keyof InputFlowSockets; +export type TriggeredFunction = ( + params: TriggeredParams, + triggeringSocketName: InputFlowSocketNames +) => void; export interface IFlowNode { socketsDefinition: T; - triggered: (params: TriggeredParams) => void; + triggered: TriggeredFunction; } export type NodeInputValues> = { @@ -92,6 +96,7 @@ export type NodeInputValues> = { }; export type OutputFlowSocketNames> = keyof OutputFlowSockets; +export type OutputValueSocketNames> = keyof OutputValueSockets; export function makeFlowNodeDefinition(flowNode: IFlowNode): IFlowNode { return flowNode; diff --git a/packages/core/src/nodes/schema/testUtils.ts b/packages/core/src/nodes/schema/testUtils.ts index 208a45e..dcd7e72 100644 --- a/packages/core/src/nodes/schema/testUtils.ts +++ b/packages/core/src/nodes/schema/testUtils.ts @@ -6,27 +6,54 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore -import { IHasSockets, NodeInputValues, OutputFlowSocketNames, TriggeredParams } from './INodeDefinition'; +import { + IHasSockets, + NodeInputValues, + OutputFlowSocketNames, + OutputFlowSockets, + OutputValueSocketNames, + TriggeredParams, +} from './INodeDefinition'; // eslint-disable-next-line @typescript-eslint/no-unused-vars export function expectType(value: T): void { // eslint-disable-next-line @typescript-eslint/no-empty-function } +type RecordedOutputWrite = + | { + writeType: 'flow'; + socketName: OutputFlowSocketNames; + } + | { + writeType: 'value'; + socketName: OutputValueSocketNames; + value: any; + }; + +export type RecordedOutputWrites = RecordedOutputWrite[]; + export const buildStubbedTriggeredInvoker = (mockState: NodeInputValues) => { - const committedNodes: OutputFlowSocketNames[] = []; + const outputWrites: RecordedOutputWrites = []; - const getCommitedNodes = () => committedNodes; + const getCommitedNodes = () => outputWrites; const triggeredParams: TriggeredParams = { commit: (param) => { - committedNodes.push(param); + outputWrites.push({ + writeType: 'flow', + socketName: param, + }); }, readInput: (param) => { return mockState[param]; }, - writeOutput: () => { - throw new Error('not implemented'); + writeOutput: (param, value) => { + outputWrites.push({ + writeType: 'value', + socketName: param, + value, + }); }, }; From 4d5bd777c7217082c78b80e2d4e1fd1855370037 Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Sat, 26 Nov 2022 08:23:01 -0800 Subject: [PATCH 05/15] added counter and can have state now --- packages/core/src/nodes/flow/Branch.test.ts | 26 ++++------ packages/core/src/nodes/flow/Branch.ts | 11 ++-- packages/core/src/nodes/flow/Counter.test.ts | 52 +++++++++++++++++++ packages/core/src/nodes/flow/Counter.ts | 23 ++++---- .../src/nodes/schema/INodeDefinition.test.ts | 5 +- .../core/src/nodes/schema/INodeDefinition.ts | 24 +++++---- packages/core/src/nodes/schema/testUtils.ts | 42 ++++++++++++--- 7 files changed, 136 insertions(+), 47 deletions(-) create mode 100644 packages/core/src/nodes/flow/Counter.test.ts diff --git a/packages/core/src/nodes/flow/Branch.test.ts b/packages/core/src/nodes/flow/Branch.test.ts index 53ad08c..4a2dc2b 100644 --- a/packages/core/src/nodes/flow/Branch.test.ts +++ b/packages/core/src/nodes/flow/Branch.test.ts @@ -1,18 +1,14 @@ import { expect } from 'chai'; -import { buildStubbedTriggeredInvoker, RecordedOutputWrites } from '../schema/testUtils'; -import Branch, { branchSockets } from './Branch'; - -type BranchSocketsDefinition = typeof branchSockets; +import { buildStubEngineForFlowNode } from '../schema/testUtils'; +import Branch from './Branch'; describe('Branch', () => { describe('trigger', () => { it('commits the true output when value is true', () => { - const mockNodeVals = { - condition: true, - }; + const { trigger, writeInput, getOutputWrites } = buildStubEngineForFlowNode(Branch); - const { triggeredParams, getCommitedNodes } = buildStubbedTriggeredInvoker(mockNodeVals); - Branch.triggered(triggeredParams, 'flow'); + writeInput('condition', true); + trigger('flow'); const expected = [ { @@ -21,15 +17,13 @@ describe('Branch', () => { }, ]; - expect(getCommitedNodes()).to.eql(expected); + expect(getOutputWrites()).to.eql(expected); }); it('commits the true output when value is false', () => { - const mockNodeVals = { - condition: false, - }; + const { trigger, writeInput, getOutputWrites } = buildStubEngineForFlowNode(Branch); - const { triggeredParams, getCommitedNodes } = buildStubbedTriggeredInvoker(mockNodeVals); - Branch.triggered(triggeredParams, 'flow'); + writeInput('condition', false); + trigger('flow'); const expected = [ { @@ -38,7 +32,7 @@ describe('Branch', () => { }, ]; - expect(getCommitedNodes()).to.eql(expected); + expect(getOutputWrites()).to.eql(expected); }); }); }); diff --git a/packages/core/src/nodes/flow/Branch.ts b/packages/core/src/nodes/flow/Branch.ts index eb186e2..afaf1c3 100644 --- a/packages/core/src/nodes/flow/Branch.ts +++ b/packages/core/src/nodes/flow/Branch.ts @@ -23,9 +23,10 @@ export const branchSockets = { } } satisfies IHasSockets; -// export type BranchSocketsDefinition = typeof branchSockets; +export type BranchSocketsDefinition = typeof branchSockets; +export type BranchState = undefined; -const Branch = makeFlowNodeDefinition({ +const Branch = makeFlowNodeDefinition({ socketsDefinition: branchSockets, triggered: ({ commit, @@ -33,7 +34,9 @@ const Branch = makeFlowNodeDefinition({ }) => { const value = readInput('condition'); commit(value ? 'true' : 'false') - } -}); + return undefined; + }, + initialState: () => undefined +}) satisfies IFlowNode; export default Branch; \ No newline at end of file diff --git a/packages/core/src/nodes/flow/Counter.test.ts b/packages/core/src/nodes/flow/Counter.test.ts new file mode 100644 index 0000000..4b6e83b --- /dev/null +++ b/packages/core/src/nodes/flow/Counter.test.ts @@ -0,0 +1,52 @@ +import { expect } from 'chai'; +import { buildStubEngineForFlowNode, RecordedOutputWrites } from '../schema/testUtils'; +import Counter from './Counter'; + +describe('Branch', () => { + describe('trigger', () => { + it('writes to the output and triggers a flow for each trigger', () => { + const { trigger, getOutputWrites } = buildStubEngineForFlowNode(Counter); + + trigger('flow'); + trigger('flow'); + + const expected: RecordedOutputWrites = [ + { + writeType: 'value', + socketName: 'count', + value: 1n, + }, + { + writeType: 'flow', + socketName: 'flow', + }, + { + writeType: 'value', + socketName: 'count', + value: 2n, + }, + { + writeType: 'flow', + socketName: 'flow', + }, + ]; + + expect(getOutputWrites()).to.eql(expected); + }); + // it('commits the true output when value is false', () => { + // const { trigger, writeInput, getOutputWrites } = buildStubEngineForFlowNode(Counter); + + // writeInput('condition', false); + // trigger('flow'); + + // const expected = [ + // { + // writeType: 'flow', + // socketName: 'false', + // }, + // ]; + + // expect(getOutputWrites()).to.eql(expected); + // }); + }); +}); diff --git a/packages/core/src/nodes/flow/Counter.ts b/packages/core/src/nodes/flow/Counter.ts index c2a412e..caaa7c2 100644 --- a/packages/core/src/nodes/flow/Counter.ts +++ b/packages/core/src/nodes/flow/Counter.ts @@ -1,7 +1,4 @@ -import { IFlowNode, IHasSockets, makeFlowNodeDefinition } from "../schema/INodeDefinition"; - -// [new Socket('flow', 'flow'), new Socket('flow', 'reset')], -// [new Socket('flow', 'flow'), new Socket('integer', 'count')] +import { IHasSockets, makeFlowNodeDefinition } from "../schema/INodeDefinition"; export const counterSockets = { inputSockets: { @@ -24,14 +21,15 @@ export const counterSockets = { export type CounterSocketsDefinition = typeof counterSockets; -let count = 0n; - const Counter = makeFlowNodeDefinition({ socketsDefinition: counterSockets, triggered: ({ commit, - writeOutput + writeOutput, + state }, triggeringSocketName) => { + // duplicate count to not modify the state + let count = state.count + 0n; switch (triggeringSocketName) { case 'flow': { @@ -41,13 +39,20 @@ const Counter = makeFlowNodeDefinition({ break; } case 'reset': { - count++; + count = 0n; break; } default: throw new Error('should not get here'); } - } + + return { + count + }; + }, + initialState: () => ({ + count: 0n + }) }); export default Counter; \ No newline at end of file diff --git a/packages/core/src/nodes/schema/INodeDefinition.test.ts b/packages/core/src/nodes/schema/INodeDefinition.test.ts index c0687d2..6fd2bb3 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.test.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.test.ts @@ -51,7 +51,10 @@ describe('TriggeredParams', () => { const a = readInput('a'); writeOutput("c", a ? 1.0 : 0.0); - } + + return undefined; + }, + initialState: () => undefined }) expectType>({ diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index 3d1b9bf..dd0387b 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -65,7 +65,7 @@ export type InputValueType = >( param: J -) => InputValueType; +) => InputValueType | undefined; export type writeOutputFn = >( param: J, @@ -74,30 +74,34 @@ export type writeOutputFn = = >(param: J) => void; -export type TriggeredParams = { +export type TriggeredParams = { writeOutput: writeOutputFn; readInput: readInputFn; commit: commitFn; + readonly state: TNodeState; }; export type InputFlowSocketNames> = keyof InputFlowSockets; -export type TriggeredFunction = ( - params: TriggeredParams, +export type TriggeredFunction = ( + params: TriggeredParams, triggeringSocketName: InputFlowSocketNames -) => void; +) => TNodeState; -export interface IFlowNode { - socketsDefinition: T; - triggered: TriggeredFunction; +export interface IFlowNode { + socketsDefinition: TSockets; + triggered: TriggeredFunction; + initialState: () => TNodeState; } export type NodeInputValues> = { - [K in keyof InputValueSockets]: ValueTypeNameMapping[K]['valueType']>; + [K in keyof InputValueSockets]?: ValueTypeNameMapping[K]['valueType']>; }; export type OutputFlowSocketNames> = keyof OutputFlowSockets; export type OutputValueSocketNames> = keyof OutputValueSockets; -export function makeFlowNodeDefinition(flowNode: IFlowNode): IFlowNode { +export function makeFlowNodeDefinition( + flowNode: IFlowNode +): IFlowNode { return flowNode; } diff --git a/packages/core/src/nodes/schema/testUtils.ts b/packages/core/src/nodes/schema/testUtils.ts index dcd7e72..30e2d7b 100644 --- a/packages/core/src/nodes/schema/testUtils.ts +++ b/packages/core/src/nodes/schema/testUtils.ts @@ -6,8 +6,14 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore +import { collapseTextChangeRangesAcrossMultipleVersions } from 'typescript'; import { + ExtractValueType, + IFlowNode, IHasSockets, + InputFlowSocketNames, + InputValueSockets, + InputValueType, NodeInputValues, OutputFlowSocketNames, OutputFlowSockets, @@ -33,12 +39,16 @@ type RecordedOutputWrite = export type RecordedOutputWrites = RecordedOutputWrite[]; -export const buildStubbedTriggeredInvoker = (mockState: NodeInputValues) => { - const outputWrites: RecordedOutputWrites = []; +export const buildStubEngineForFlowNode = ( + flowNodeDefinition: IFlowNode +) => { + const outputWrites: RecordedOutputWrites = []; - const getCommitedNodes = () => outputWrites; + const getOutputWrites = () => outputWrites; - const triggeredParams: TriggeredParams = { + let inputValuesState: NodeInputValues = {}; + + const triggeredParams: Omit, 'state'> = { commit: (param) => { outputWrites.push({ writeType: 'flow', @@ -46,7 +56,7 @@ export const buildStubbedTriggeredInvoker = (mockState: N }); }, readInput: (param) => { - return mockState[param]; + return inputValuesState[param]; }, writeOutput: (param, value) => { outputWrites.push({ @@ -57,8 +67,26 @@ export const buildStubbedTriggeredInvoker = (mockState: N }, }; + let nodeState = flowNodeDefinition.initialState(); + + const trigger = (nodeName: InputFlowSocketNames) => { + // trigger node and update the state with the triggered result. + nodeState = flowNodeDefinition.triggered( + { + ...triggeredParams, + state: nodeState, + }, + nodeName + ); + }; + + const writeInput = >(param: J, value: InputValueType) => { + inputValuesState[param] = value; + }; + return { - triggeredParams, - getCommitedNodes, + getOutputWrites, + trigger, + writeInput, }; }; From 86dd73206b9e7e27909b6cc1a7fe16f3dd087c9e Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Sat, 26 Nov 2022 08:24:56 -0800 Subject: [PATCH 06/15] made it easy to test the flow node --- packages/core/src/nodes/flow/Counter.test.ts | 50 ++++++++++++++----- packages/core/src/nodes/flow/Counter.ts | 5 +- .../src/nodes/schema/INodeDefinition.test.ts | 6 +-- .../core/src/nodes/schema/INodeDefinition.ts | 40 +++++++++------ packages/core/src/nodes/schema/testUtils.ts | 16 +++--- 5 files changed, 76 insertions(+), 41 deletions(-) diff --git a/packages/core/src/nodes/flow/Counter.test.ts b/packages/core/src/nodes/flow/Counter.test.ts index 4b6e83b..1fd8ae2 100644 --- a/packages/core/src/nodes/flow/Counter.test.ts +++ b/packages/core/src/nodes/flow/Counter.test.ts @@ -33,20 +33,46 @@ describe('Branch', () => { expect(getOutputWrites()).to.eql(expected); }); - // it('commits the true output when value is false', () => { - // const { trigger, writeInput, getOutputWrites } = buildStubEngineForFlowNode(Counter); + it('resets the value to 0 but doesnt write the update on reset', () => { + const { trigger, getOutputWrites } = buildStubEngineForFlowNode(Counter); - // writeInput('condition', false); - // trigger('flow'); + trigger('flow'); + trigger('flow'); + trigger('reset'); + trigger('flow'); - // const expected = [ - // { - // writeType: 'flow', - // socketName: 'false', - // }, - // ]; + const expected: RecordedOutputWrites = [ + { + writeType: 'value', + socketName: 'count', + value: 1n, + }, + { + writeType: 'flow', + socketName: 'flow', + }, + { + writeType: 'value', + socketName: 'count', + value: 2n, + }, + { + writeType: 'flow', + socketName: 'flow', + }, + // reset triggered - goes back to 0 but value isnt emitted + { + writeType: 'value', + socketName: 'count', + value: 1n, + }, + { + writeType: 'flow', + socketName: 'flow', + }, + ]; - // expect(getOutputWrites()).to.eql(expected); - // }); + expect(getOutputWrites()).to.eql(expected); + }); }); }); diff --git a/packages/core/src/nodes/flow/Counter.ts b/packages/core/src/nodes/flow/Counter.ts index caaa7c2..808fdc5 100644 --- a/packages/core/src/nodes/flow/Counter.ts +++ b/packages/core/src/nodes/flow/Counter.ts @@ -26,8 +26,9 @@ const Counter = makeFlowNodeDefinition({ triggered: ({ commit, writeOutput, - state - }, triggeringSocketName) => { + state, + triggeringSocketName + }) => { // duplicate count to not modify the state let count = state.count + 0n; diff --git a/packages/core/src/nodes/schema/INodeDefinition.test.ts b/packages/core/src/nodes/schema/INodeDefinition.test.ts index 6fd2bb3..61c5cfc 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.test.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.test.ts @@ -3,7 +3,7 @@ import { IHasSockets, makeFlowNodeDefinition, OutputValueType, - readInputFn, + readNodeInputFn, ValueSockets, ExtractValueType, ValueTypeNameMapping, @@ -80,8 +80,8 @@ describe('TriggeredParams', () => { expectType>('asdfasfd'); - expectType>>(['a']); - expectType>>(['b']); + expectType>>(['a']); + expectType>>(['b']); }); }); }); diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index dd0387b..e93f24a 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -53,6 +53,14 @@ export type InputValueSockets> = Val export type InputFlowSockets> = FlowSockets>; export type OutputFlowSockets> = FlowSockets>; +export type InputFlowSocketNames> = keyof InputFlowSockets; +export type OutputFlowSocketNames> = keyof OutputFlowSockets; +export type OutputValueSocketNames> = keyof OutputValueSockets; + +export type NodeInputValues> = { + [K in keyof InputValueSockets]?: ValueTypeNameMapping[K]['valueType']>; +}; + export type OutputValueType> = ExtractValueType< OutputValueSockets, J @@ -63,43 +71,45 @@ export type InputValueType; -export type readInputFn = >( +/** Node Engine Access Functions */ + +export type readNodeInputFn = >( param: J ) => InputValueType | undefined; -export type writeOutputFn = >( +export type writeNodeOutputFn = >( param: J, value: OutputValueType ) => void; export type commitFn = >(param: J) => void; +/** Flow Node Definitions */ + +/** Arguments for the triggered function on a flow node */ export type TriggeredParams = { - writeOutput: writeOutputFn; - readInput: readInputFn; + /** writes to an output node */ + writeOutput: writeNodeOutputFn; + /** reads a value from an input node */ + readInput: readNodeInputFn; + /** commits a trigger to a flow node */ commit: commitFn; + /** The local node's state */ readonly state: TNodeState; + /** The name of the flow input socket that was triggered */ + triggeringSocketName: InputFlowSocketNames; }; -export type InputFlowSocketNames> = keyof InputFlowSockets; export type TriggeredFunction = ( - params: TriggeredParams, - triggeringSocketName: InputFlowSocketNames + params: TriggeredParams ) => TNodeState; export interface IFlowNode { socketsDefinition: TSockets; + /** Called when an input flow node is triggered */ triggered: TriggeredFunction; initialState: () => TNodeState; } - -export type NodeInputValues> = { - [K in keyof InputValueSockets]?: ValueTypeNameMapping[K]['valueType']>; -}; - -export type OutputFlowSocketNames> = keyof OutputFlowSockets; -export type OutputValueSocketNames> = keyof OutputValueSockets; - export function makeFlowNodeDefinition( flowNode: IFlowNode ): IFlowNode { diff --git a/packages/core/src/nodes/schema/testUtils.ts b/packages/core/src/nodes/schema/testUtils.ts index 30e2d7b..89e55bc 100644 --- a/packages/core/src/nodes/schema/testUtils.ts +++ b/packages/core/src/nodes/schema/testUtils.ts @@ -48,7 +48,7 @@ export const buildStubEngineForFlowNode = let inputValuesState: NodeInputValues = {}; - const triggeredParams: Omit, 'state'> = { + const triggeredParams: Omit, 'state' | 'triggeringSocketName'> = { commit: (param) => { outputWrites.push({ writeType: 'flow', @@ -69,15 +69,13 @@ export const buildStubEngineForFlowNode = let nodeState = flowNodeDefinition.initialState(); - const trigger = (nodeName: InputFlowSocketNames) => { + const trigger = (triggeringSocketName: InputFlowSocketNames) => { // trigger node and update the state with the triggered result. - nodeState = flowNodeDefinition.triggered( - { - ...triggeredParams, - state: nodeState, - }, - nodeName - ); + nodeState = flowNodeDefinition.triggered({ + ...triggeredParams, + state: nodeState, + triggeringSocketName, + }); }; const writeInput = >(param: J, value: InputValueType) => { From e68cc177af64cdd404247d67908d5142b82eb6dd Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Sun, 27 Nov 2022 11:50:08 -0800 Subject: [PATCH 07/15] have in-out-nodes defined with some casting --- .../core/src/nodes/schema/INodeDefinition.ts | 129 +++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index e93f24a..a533aa0 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -22,6 +22,7 @@ export interface INodeDefinition extends IHasSockets { } export type ValueTypeNameMapping = { + boolean: boolean; integer: bigint; float: number; @@ -30,6 +31,8 @@ export type ValueTypeNameMapping = { flow: void; }[K]; +export type OptionalValueTypeMapping = ValueTypeNameMapping | undefined; + type OutputSockets> = T['outputSockets']; type InputSockets> = T['inputSockets']; @@ -86,12 +89,15 @@ export type commitFn = = { +export type ReadWriteToNodeParams = { /** writes to an output node */ writeOutput: writeNodeOutputFn; /** reads a value from an input node */ readInput: readNodeInputFn; +} + +/** Arguments for the triggered function on a flow node */ +export type TriggeredParams = ReadWriteToNodeParams & { /** commits a trigger to a flow node */ commit: commitFn; /** The local node's state */ @@ -115,3 +121,122 @@ export function makeFlowNodeDefinition { return flowNode; } + +type ImmediateExecFn = ( + params: ReadWriteToNodeParams +) => void; + +export interface IImmediateNode { + socketsDefinition: T; + exec: ImmediateExecFn; +} + +export function makeImmediateNodeDefinition( + immediateNode: IImmediateNode +) { + return immediateNode; +} + +export function makeIn1Out1FuncNode({ + inputValueType, + outputValueType, + unaryEvalFunc, +}: { + inputValueType: TIn; + outputValueType: TOut; + unaryEvalFunc: (a: ValueTypeNameMapping) => ValueTypeNameMapping; +}) { + const socketsDefinition = { + inputSockets: { + a: { + valueType: inputValueType, + }, + }, + outputSockets: { + result: { + valueType: outputValueType, + }, + }, + } satisfies IHasSockets; + + return makeImmediateNodeDefinition({ + socketsDefinition, + exec: ({ readInput, writeOutput }) => { + const input = readInput('a') as OptionalValueTypeMapping; + if (typeof input !== 'undefined') { + writeOutput('result', unaryEvalFunc(input)); + } + }, + }); +} + +// export const makeSocketsDefinition = ( +// hasSockets: IHasSockets +// ) => hasSockets; + +function makeSockets(sockets: T): T { + return sockets; +} + +export function makeIn2Out1FuncNode< + TIn1 extends SocketValueType, + TIn2 extends SocketValueType, + TOut extends SocketValueType +>({ + inputValueTypes, + outputValueType, + unaryEvalFunc, +}: { + inputValueTypes: [TIn1, TIn2]; + outputValueType: TOut; + unaryEvalFunc: (a: ValueTypeNameMapping, b: ValueTypeNameMapping) => ValueTypeNameMapping; +}) { + const socketsDefinition = { + inputSockets: { + a: { + valueType: inputValueTypes[0], + }, + b: { + valueType: inputValueTypes[1], + }, + }, + outputSockets: { + result: { + valueType: outputValueType, + }, + }, + } satisfies IHasSockets; + + return makeImmediateNodeDefinition({ + socketsDefinition, + exec: ({ readInput, writeOutput }) => { + const inputA = readInput('a') as OptionalValueTypeMapping; + const inputB = readInput('b') as OptionalValueTypeMapping; + if (typeof inputA !== 'undefined' && typeof inputB !== 'undefined') { + writeOutput('result', unaryEvalFunc(inputA, inputB)); + } + }, + }); +} + +// function recordFromEntries(entries: [K, V][]): Record { +// return Object.fromEntries(entries) as Record; +// } + +// function makeObjectExtractor(keyA: string) { +// const fromEntries = recordFromEntries([[keyA, 4]]); +// const toExtractFrom = { +// keyB: 5, +// ...recordFromEntries([[keyA, 4]]), +// }; + +// function getIncrementedVal(param: keyof typeof toExtractFrom) { +// return toExtractFrom[param] + 1; +// } + +// return getIncrementedVal; +// } + +// const extractor = makeObjectExtractor('g'); + +// extractor('asdfasdf'); From f1334ab7e5bd1e6982de2d2e48f1ed9e245d6eba Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Sun, 27 Nov 2022 15:51:19 -0800 Subject: [PATCH 08/15] wip on single fn in out node --- .../core/src/nodes/schema/INodeDefinition.ts | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index a533aa0..b4a721f 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -219,6 +219,61 @@ export function makeIn2Out1FuncNode< }); } + +// type LengthOfArray> = T.length; + + +type ValueTypeNameMappings = { + [TValue in TValues]: + } + + +export function makeInNOutNodes< + TIn extends SocketValueType[], + TOut extends SocketValueType +>({ + inputValueTypes, + outputValueType, + unaryEvalFunc, +}: { + inputValueTypes: TIn + outputValueType: TOut + unaryEvalFunc: (...params: TIn) => ValueTypeNameMapping; +}) { + const socketsDefinition = { + inputSockets: { + a: { + valueType: inputValueTypes[0], + }, + b: { + valueType: inputValueTypes[1], + }, + }, + outputSockets: { + result: { + valueType: outputValueType, + }, + }, + } satisfies IHasSockets; + + return makeImmediateNodeDefinition({ + socketsDefinition, + exec: ({ readInput, writeOutput }) => { + const inputA = readInput('a') as OptionalValueTypeMapping; + const inputB = readInput('b') as OptionalValueTypeMapping; + if (typeof inputA !== 'undefined' && typeof inputB !== 'undefined') { + writeOutput('result', unaryEvalFunc(inputA, inputB)); + } + }, + }); +} + + + + // function recordFromEntries(entries: [K, V][]): Record { // return Object.fromEntries(entries) as Record; // } From ca3f7576dbc497c59aea921ed56b032f4c0873bb Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Sun, 27 Nov 2022 20:56:51 -0800 Subject: [PATCH 09/15] wip on list for sockets --- package.json | 10 +- packages/core/package.json | 3 +- .../src/nodes/schema/INodeDefinition.test.ts | 64 +++-- .../core/src/nodes/schema/INodeDefinition.ts | 255 +++++++++++------- yarn.lock | 12 +- 5 files changed, 227 insertions(+), 117 deletions(-) diff --git a/package.json b/package.json index c26067f..432a7b1 100644 --- a/package.json +++ b/package.json @@ -19,16 +19,16 @@ "url": "https://github.com/bhouston/behave-graph" }, "devDependencies": { - "@openzeppelin/contracts": "^4.7.3", - "@preconstruct/cli": "^2.2.2", - "@typechain/ethers-v5": "^10.1.1", - "@typechain/hardhat": "^6.1.4", "@babel/core": "^7.17.10", "@babel/preset-env": "^7.17.10", "@babel/preset-react": "^7.16.7", "@babel/preset-typescript": "^7.16.7", + "@openzeppelin/contracts": "^4.7.3", + "@preconstruct/cli": "^2.2.2", + "@typechain/ethers-v5": "^10.1.1", + "@typechain/hardhat": "^6.1.4", "dotenv": "^16.0.3", - "prettier": "^2.7.1", + "prettier": "^2.8.0", "ts-node": ">=8.0.0", "typechain": "^8.1.1", "typescript": "^4.9.3" diff --git a/packages/core/package.json b/packages/core/package.json index 2f6a2ee..3599478 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -18,6 +18,7 @@ "devDependencies": { "@types/expect": "^24.3.0", "@types/mocha": "^10.0.0", - "ts-mocha": "^10.0.0" + "ts-mocha": "^10.0.0", + "type-fest": "^3.2.0" } } diff --git a/packages/core/src/nodes/schema/INodeDefinition.test.ts b/packages/core/src/nodes/schema/INodeDefinition.test.ts index 61c5cfc..e064bb5 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.test.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.test.ts @@ -7,6 +7,11 @@ import { ValueSockets, ExtractValueType, ValueTypeNameMapping, + SocketSpec, + SocketsFromSpec, + makeSocketsFromSpec, + ToObjectsArray, + UnionToIntersection, } from './INodeDefinition'; import { expectType } from './testUtils'; @@ -22,8 +27,8 @@ describe('TriggeredParams', () => { valueType: 'string', }, c: { - valueType: "flow" - } + valueType: 'flow', + }, }, outputSockets: { c: { @@ -43,34 +48,30 @@ describe('TriggeredParams', () => { const flowNode = makeFlowNodeDefinition({ socketsDefinition: vals, - triggered: ({ - commit, - readInput, - writeOutput - }) => { + triggered: ({ commit, readInput, writeOutput }) => { const a = readInput('a'); - writeOutput("c", a ? 1.0 : 0.0); - + writeOutput('c', a ? 1.0 : 0.0); + return undefined; }, - initialState: () => undefined - }) + initialState: () => undefined, + }); expectType>({ a: { - valueType: 'boolean' + valueType: 'boolean', }, b: { - valueType: 'string' - } - }) + valueType: 'string', + }, + }); expectType>({ c: { - valueType: 'flow' - } - }) + valueType: 'flow', + }, + }); expectType>(true); expectType>('asdfasfd'); @@ -79,9 +80,34 @@ describe('TriggeredParams', () => { expectType>(1n); expectType>('asdfasfd'); - expectType>>(['a']); expectType>>(['b']); }); }); + describe('Function generation', () => { + const socketDefs = [ + { name: 'a', valueType: 'float' }, + { name: 'g', valueType: 'string' }, + ] as const; + + // const socketSpecs = makeSocketsFromSpec([ + // { name: 'a', valueType: 'float' }, + // { name: 'g', valueType: 'string' } + // ] as const); + + // socketSpecs['a']; + + type x = typeof socketDefs; + + type y = SocketsFromSpec; + + expectType({ + a: { + valueType: 'float', + }, + g: { + valueType: 'string', + }, + }); + }); }); diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index b4a721f..5f98fae 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -1,14 +1,14 @@ -import { NodeCategory } from '@behave-graph/core'; +import { FlowNode, NodeCategory, Socket } from '@behave-graph/core'; +import { UnionToIntersection } from 'type-fest'; export type SocketValueType = 'flow' | 'boolean' | 'integer' | 'float' | 'string' | 'jsonPath'; export interface ISocketDefinition { + readonly name: string; readonly valueType: SocketValueType; } -export type Sockets = { - readonly [key: string]: ISocketDefinition; -}; +export type Sockets = readonly ISocketDefinition[]; export type IHasSockets = { readonly inputSockets: Sockets; @@ -22,7 +22,6 @@ export interface INodeDefinition extends IHasSockets { } export type ValueTypeNameMapping = { - boolean: boolean; integer: bigint; float: number; @@ -40,10 +39,9 @@ type FlowSocketDef = { valueType: 'flow'; }; -export type ValueSockets = Pick< - T, - { [K in keyof T]-?: T[K] extends FlowSocketDef ? never : K }[keyof T] ->; +export type ValueSockets = { + [K in keyof T]-?: T[K] extends FlowSocketDef ? never : T[K]; +}; export type FlowSockets = Pick< T, { [K in keyof T]-?: T[K] extends FlowSocketDef ? K : never }[keyof T] @@ -76,9 +74,9 @@ export type InputValueType = >( - param: J -) => InputValueType | undefined; +export type readNodeInputFn = [number], J extends keyof TIn>( + param: TIn[number][J] +) => undefined; export type writeNodeOutputFn = >( param: J, @@ -94,7 +92,7 @@ export type ReadWriteToNodeParams = { writeOutput: writeNodeOutputFn; /** reads a value from an input node */ readInput: readNodeInputFn; -} +}; /** Arguments for the triggered function on a flow node */ export type TriggeredParams = ReadWriteToNodeParams & { @@ -122,18 +120,14 @@ export function makeFlowNodeDefinition = ( - params: ReadWriteToNodeParams -) => void; +type ImmediateExecFn = (params: ReadWriteToNodeParams) => void; export interface IImmediateNode { socketsDefinition: T; exec: ImmediateExecFn; } -export function makeImmediateNodeDefinition( - immediateNode: IImmediateNode -) { +export function makeImmediateNodeDefinition(immediateNode: IImmediateNode) { return immediateNode; } @@ -178,90 +172,164 @@ function makeSockets(sockets: T): T { return sockets; } -export function makeIn2Out1FuncNode< - TIn1 extends SocketValueType, - TIn2 extends SocketValueType, - TOut extends SocketValueType ->({ - inputValueTypes, - outputValueType, - unaryEvalFunc, -}: { - inputValueTypes: [TIn1, TIn2]; - outputValueType: TOut; - unaryEvalFunc: (a: ValueTypeNameMapping, b: ValueTypeNameMapping) => ValueTypeNameMapping; -}) { - const socketsDefinition = { - inputSockets: { - a: { - valueType: inputValueTypes[0], - }, - b: { - valueType: inputValueTypes[1], - }, - }, - outputSockets: { - result: { - valueType: outputValueType, - }, - }, - } satisfies IHasSockets; +// type LengthOfArray> = T.length; - return makeImmediateNodeDefinition({ - socketsDefinition, - exec: ({ readInput, writeOutput }) => { - const inputA = readInput('a') as OptionalValueTypeMapping; - const inputB = readInput('b') as OptionalValueTypeMapping; - if (typeof inputA !== 'undefined' && typeof inputB !== 'undefined') { - writeOutput('result', unaryEvalFunc(inputA, inputB)); - } - }, - }); -} +// type ValueTypeMapping = { +// "string": string, +// "boolean": boolean, +// "float": number, +// "integer": number +// } +// type ValueType = keyof ValueTypeMapping; -// type LengthOfArray> = T.length; +type ValuesForValueTypes = { + [K in keyof T]: ValueTypeNameMapping; +}; + +type unaryEvalFunction = ( + ...params: ValuesForValueTypes +) => ValueTypeNameMapping; + +// type SocketSpec = [string, SocketValueType]; + +// type ValueTypeFromSockets = { +// [V in keyof T]: T[V]['valueType'] +// } + +// type ToObject = T extends readonly [infer Key, infer Func] +// ? Key extends PropertyKey +// ? { [P in Key]: Func } +// : never +// : never; + +// type ToObjectsArray = { +// [I in keyof T]: ToObject; +// }; + +// type UnionToIntersection = +// (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; + +export type SocketSpec = { + name: string; + valueType: SocketValueType; +}; +export type SocketNames = { + [K in keyof T]: T[K]['name']; +}; + +type ToSocket = { + [P in T['name']]: { + valueType: T['valueType']; + }; +}; + +export type ToObjectsArray = { + [I in keyof T]: ToSocket; +}; + +type Known = Exclude; + +// export type UnionToIntersection = // `extends unknown` is always going to be the case and is used to convert the +// // `Union` into a [distributive conditional +// // type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types). +// ( +// Union extends unknown +// ? // The union type is used as the only argument to a function since the union +// // of function arguments is an intersection. +// (distributedUnion: Union) => void +// : // This won't happen. +// never +// ) extends // Infer the `Intersection` type since TypeScript represents the positional +// // arguments of unions of functions as an intersection of the union. +// (mergedIntersection: infer Intersection) => void +// ? Intersection +// : never; + +export type SocketsFromSpec = Known[number]>>; + +// type Params = [{ name: 'a'; valueType: 'float' }, { name: 'b'; valueType: 'string' }]; + +// type mapped = SocketsFromSpec; + +// type x = mapped['a']; + +// type SocketsForSpec = T extends readonly [infer Key, infer SocketValueType] +// ? Key extends PropertyKey +// ? { [P in Key]: SocketValueType } +// : never +// : never; -type ValueTypeNameMappings = { - [TValue in TValues]: - } +// type SocketsForSpec = { +// [V in keyof T as `${V}`]: T[V]['valueType'] +// } + +// type MapKey = BaseType extends Map ? KeyType : never; +// type MapValue = BaseType extends Map ? ValueType : never; +// type MapEntry = [MapKey, MapValue]; +// type Entries = Array> + +// type SocketsForValuesType> = { +// [K in keyof J]: J[K] +// } + +// type x = SocketsForValuesType<{ +// a: 'string', +// b: 'float' +// }>; + +// test +// const fn: unaryEvalFunction<['string', 'float'], 'float'> = (a, b) => { +// return 5; +// }; -export function makeInNOutNodes< - TIn extends SocketValueType[], - TOut extends SocketValueType ->({ +export function makeSocketsFromSpec(socketSpecs: TSockets) { + const sockets: any = {}; + + for (const { name, valueType } of socketSpecs) { + sockets[name] = { valueType } satisfies ISocketDefinition; + } + + return sockets as SocketsFromSpec; +} + +type immediateReadIn = ( + key: socket['name'] +) => ValueTypeNameMapping; + +export function makeInNOutNodes({ inputValueTypes, outputValueType, unaryEvalFunc, }: { - inputValueTypes: TIn - outputValueType: TOut - unaryEvalFunc: (...params: TIn) => ValueTypeNameMapping; + inputValueTypes: TIn; + outputValueType: TOut; + unaryEvalFunc: unaryEvalFunction; }) { - const socketsDefinition = { - inputSockets: { - a: { - valueType: inputValueTypes[0], - }, - b: { - valueType: inputValueTypes[1], - }, - }, - outputSockets: { - result: { - valueType: outputValueType, - }, - }, - } satisfies IHasSockets; + const inputSockets = makeSocketsFromSpec(inputValueTypes) satisfies Sockets; + const outputSockets = makeSocketsFromSpec([outputValueType]) satisfies Sockets; return makeImmediateNodeDefinition({ - socketsDefinition, + socketsDefinition: { + inputSockets, + outputSockets, + }, exec: ({ readInput, writeOutput }) => { + const iputVals: any[] = []; + + // if (inputValueTypes.length > 0) { + // const firstName = inputValueTypes[0].name; + // readInput(firstName) + for (const { name } of inputValueTypes) { + const x = name satisfies keyof typeof inputSockets; + + const inputVal = readInput(name satisfies keyof typeof inputSockets); + // } + } + + const inputVals = [inputType in inputValueTypes]; const inputA = readInput('a') as OptionalValueTypeMapping; const inputB = readInput('b') as OptionalValueTypeMapping; if (typeof inputA !== 'undefined' && typeof inputB !== 'undefined') { @@ -271,9 +339,6 @@ export function makeInNOutNodes< }); } - - - // function recordFromEntries(entries: [K, V][]): Record { // return Object.fromEntries(entries) as Record; // } @@ -295,3 +360,11 @@ export function makeInNOutNodes< // const extractor = makeObjectExtractor('g'); // extractor('asdfasdf'); + +// type FnForSpecific = (...params: ForSpecific) => { + +// } + +// type ValuesForValueTypes = [ +// [K in T]: ValueTypeMapping[K] +// ] diff --git a/yarn.lock b/yarn.lock index 9d992b6..87ed632 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9143,11 +9143,16 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== -prettier@^2.3.1, prettier@^2.7.1: +prettier@^2.3.1: version "2.7.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== +prettier@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.0.tgz#c7df58393c9ba77d6fba3921ae01faf994fb9dc9" + integrity sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA== + pretty-format@^29.3.1: version "29.3.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.3.1.tgz#1841cac822b02b4da8971dacb03e8a871b4722da" @@ -10818,6 +10823,11 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.2.0.tgz#2c8b49e775d9e314a73ea6fcee0b2e8549d5f886" + integrity sha512-Il3wdLRzWvbAEtocgxGQA9YOoRVeVUGOMBtel5LdEpNeEAol6GJTLw8GbX6Z8EIMfvfhoOXs2bwOijtAZdK5og== + typechain@^8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.1.1.tgz#9c2e8012c2c4c586536fc18402dcd7034c4ff0bd" From 2f724e26b3c679389b6ee38b3d655ed1d64ec769 Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Sun, 27 Nov 2022 21:43:38 -0800 Subject: [PATCH 10/15] wrote some more tests and sample code aroud ndoe defs --- .../src/nodes/schema/INodeDefinition.test.ts | 29 +-- .../core/src/nodes/schema/INodeDefinition.ts | 206 +++++------------- 2 files changed, 57 insertions(+), 178 deletions(-) diff --git a/packages/core/src/nodes/schema/INodeDefinition.test.ts b/packages/core/src/nodes/schema/INodeDefinition.test.ts index e064bb5..de25e74 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.test.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.test.ts @@ -8,10 +8,8 @@ import { ExtractValueType, ValueTypeNameMapping, SocketSpec, - SocketsFromSpec, - makeSocketsFromSpec, - ToObjectsArray, - UnionToIntersection, + SocketValueTypes, + SocketNames, } from './INodeDefinition'; import { expectType } from './testUtils'; @@ -46,7 +44,7 @@ describe('TriggeredParams', () => { }, } satisfies IHasSockets; - const flowNode = makeFlowNodeDefinition({ + makeFlowNodeDefinition({ socketsDefinition: vals, triggered: ({ commit, readInput, writeOutput }) => { const a = readInput('a'); @@ -90,24 +88,9 @@ describe('TriggeredParams', () => { { name: 'g', valueType: 'string' }, ] as const; - // const socketSpecs = makeSocketsFromSpec([ - // { name: 'a', valueType: 'float' }, - // { name: 'g', valueType: 'string' } - // ] as const); + const outputSocketDef = { name: 'c', valueType: 'float' } satisfies SocketSpec; - // socketSpecs['a']; - - type x = typeof socketDefs; - - type y = SocketsFromSpec; - - expectType({ - a: { - valueType: 'float', - }, - g: { - valueType: 'string', - }, - }); + expectType>([1.0, '6']); + expectType>(['a', 'g']); }); }); diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index 5f98fae..34312ef 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -4,11 +4,12 @@ import { UnionToIntersection } from 'type-fest'; export type SocketValueType = 'flow' | 'boolean' | 'integer' | 'float' | 'string' | 'jsonPath'; export interface ISocketDefinition { - readonly name: string; readonly valueType: SocketValueType; } -export type Sockets = readonly ISocketDefinition[]; +export type Sockets = { + readonly [key: string]: ISocketDefinition; +}; export type IHasSockets = { readonly inputSockets: Sockets; @@ -39,9 +40,11 @@ type FlowSocketDef = { valueType: 'flow'; }; -export type ValueSockets = { - [K in keyof T]-?: T[K] extends FlowSocketDef ? never : T[K]; -}; +export type ValueSockets = Pick< + T, + { [K in keyof T]-?: T[K] extends FlowSocketDef ? never : K }[keyof T] +>; + export type FlowSockets = Pick< T, { [K in keyof T]-?: T[K] extends FlowSocketDef ? K : never }[keyof T] @@ -74,9 +77,9 @@ export type InputValueType = [number], J extends keyof TIn>( - param: TIn[number][J] -) => undefined; +export type readNodeInputFn = >( + param: J +) => InputValueType; export type writeNodeOutputFn = >( param: J, @@ -120,75 +123,44 @@ export function makeFlowNodeDefinition = (params: ReadWriteToNodeParams) => void; +export type immediateReadIn = < + S extends Known>, + K extends keyof S +>( + key: K +) => S[K]; -export interface IImmediateNode { - socketsDefinition: T; - exec: ImmediateExecFn; -} +export type immediateWriteOut = ( + key: TSocket['name'], + value: ValueTypeNameMapping +) => void; -export function makeImmediateNodeDefinition(immediateNode: IImmediateNode) { - return immediateNode; -} +type ImmediateExecParams = { + readInput: immediateReadIn; + writeOutput: immediateWriteOut; +}; -export function makeIn1Out1FuncNode({ - inputValueType, - outputValueType, - unaryEvalFunc, -}: { - inputValueType: TIn; - outputValueType: TOut; - unaryEvalFunc: (a: ValueTypeNameMapping) => ValueTypeNameMapping; -}) { - const socketsDefinition = { - inputSockets: { - a: { - valueType: inputValueType, - }, - }, - outputSockets: { - result: { - valueType: outputValueType, - }, - }, - } satisfies IHasSockets; +type ImmediateExecFn = ( + params: ImmediateExecParams +) => void; - return makeImmediateNodeDefinition({ - socketsDefinition, - exec: ({ readInput, writeOutput }) => { - const input = readInput('a') as OptionalValueTypeMapping; - if (typeof input !== 'undefined') { - writeOutput('result', unaryEvalFunc(input)); - } - }, - }); +export interface IImmediateNode { + socketsDefinition: T; + exec: ImmediateExecFn; } -// export const makeSocketsDefinition = ( -// hasSockets: IHasSockets -// ) => hasSockets; - -function makeSockets(sockets: T): T { - return sockets; +function makeImmediateNodeDefinition( + node: IImmediateNode +) { + return node; } -// type LengthOfArray> = T.length; - -// type ValueTypeMapping = { -// "string": string, -// "boolean": boolean, -// "float": number, -// "integer": number -// } - -// type ValueType = keyof ValueTypeMapping; - -type ValuesForValueTypes = { +export type SocketValueTypes = { [K in keyof T]: ValueTypeNameMapping; }; type unaryEvalFunction = ( - ...params: ValuesForValueTypes + ...params: SocketValueTypes ) => ValueTypeNameMapping; // type SocketSpec = [string, SocketValueType]; @@ -249,42 +221,6 @@ type Known = Exclude; export type SocketsFromSpec = Known[number]>>; -// type Params = [{ name: 'a'; valueType: 'float' }, { name: 'b'; valueType: 'string' }]; - -// type mapped = SocketsFromSpec; - -// type x = mapped['a']; - -// type SocketsForSpec = T extends readonly [infer Key, infer SocketValueType] -// ? Key extends PropertyKey -// ? { [P in Key]: SocketValueType } -// : never -// : never; - -// type SocketsForSpec = { -// [V in keyof T as `${V}`]: T[V]['valueType'] -// } - -// type MapKey = BaseType extends Map ? KeyType : never; -// type MapValue = BaseType extends Map ? ValueType : never; -// type MapEntry = [MapKey, MapValue]; -// type Entries = Array> - -// type SocketsForValuesType> = { -// [K in keyof J]: J[K] -// } - -// type x = SocketsForValuesType<{ -// a: 'string', -// b: 'float' -// }>; - -// test - -// const fn: unaryEvalFunction<['string', 'float'], 'float'> = (a, b) => { -// return 5; -// }; - export function makeSocketsFromSpec(socketSpecs: TSockets) { const sockets: any = {}; @@ -295,10 +231,6 @@ export function makeSocketsFromSpec(sock return sockets as SocketsFromSpec; } -type immediateReadIn = ( - key: socket['name'] -) => ValueTypeNameMapping; - export function makeInNOutNodes({ inputValueTypes, outputValueType, @@ -311,60 +243,24 @@ export function makeInNOutNodes = (param) => {}; + + const exec: ImmediateExecFn = ({ readInput, writeOutput }) => { + // let args: any[] = []; + const names = inputValueTypes.map(({ name }) => name) as SocketNames; + + const inputValues = names.map((x) => readInput(x)) as unknown as SocketValueTypes; + + const result = unaryEvalFunc(...inputValues); + + writeOutput(outputValueType['name'], result); + }; + return makeImmediateNodeDefinition({ socketsDefinition: { inputSockets, outputSockets, }, - exec: ({ readInput, writeOutput }) => { - const iputVals: any[] = []; - - // if (inputValueTypes.length > 0) { - // const firstName = inputValueTypes[0].name; - // readInput(firstName) - for (const { name } of inputValueTypes) { - const x = name satisfies keyof typeof inputSockets; - - const inputVal = readInput(name satisfies keyof typeof inputSockets); - // } - } - - const inputVals = [inputType in inputValueTypes]; - const inputA = readInput('a') as OptionalValueTypeMapping; - const inputB = readInput('b') as OptionalValueTypeMapping; - if (typeof inputA !== 'undefined' && typeof inputB !== 'undefined') { - writeOutput('result', unaryEvalFunc(inputA, inputB)); - } - }, + exec, }); } - -// function recordFromEntries(entries: [K, V][]): Record { -// return Object.fromEntries(entries) as Record; -// } - -// function makeObjectExtractor(keyA: string) { -// const fromEntries = recordFromEntries([[keyA, 4]]); -// const toExtractFrom = { -// keyB: 5, -// ...recordFromEntries([[keyA, 4]]), -// }; - -// function getIncrementedVal(param: keyof typeof toExtractFrom) { -// return toExtractFrom[param] + 1; -// } - -// return getIncrementedVal; -// } - -// const extractor = makeObjectExtractor('g'); - -// extractor('asdfasdf'); - -// type FnForSpecific = (...params: ForSpecific) => { - -// } - -// type ValuesForValueTypes = [ -// [K in T]: ValueTypeMapping[K] -// ] From 18a8606f395e0df762d30ebcc23dd91854f6b8f5 Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Mon, 28 Nov 2022 14:57:28 -0800 Subject: [PATCH 11/15] made shared common number things --- packages/core/src/nodes/flow/Branch.ts | 58 ++-- packages/core/src/nodes/flow/Counter.ts | 59 ++-- .../core/src/nodes/schema/INodeDefinition.ts | 47 +-- .../core/src/nodes/values/BooleanNodes.ts | 41 +++ packages/core/src/nodes/values/FloatNodes.ts | 294 ++++++++++++++++++ packages/core/src/nodes/values/Shared.ts | 59 ++++ 6 files changed, 448 insertions(+), 110 deletions(-) create mode 100644 packages/core/src/nodes/values/BooleanNodes.ts create mode 100644 packages/core/src/nodes/values/FloatNodes.ts create mode 100644 packages/core/src/nodes/values/Shared.ts diff --git a/packages/core/src/nodes/flow/Branch.ts b/packages/core/src/nodes/flow/Branch.ts index afaf1c3..4a20e17 100644 --- a/packages/core/src/nodes/flow/Branch.ts +++ b/packages/core/src/nodes/flow/Branch.ts @@ -1,42 +1,30 @@ -import { IFlowNode, IHasSockets, ISocketDefinition, makeFlowNodeDefinition, TriggeredFunction } from "../schema/INodeDefinition"; +import { makeFlowNodeDefinition } from '../schema/INodeDefinition'; -// [new Socket('flow', 'flow'), new Socket('boolean', 'condition')], -// [new Socket('flow', 'true'), new Socket('flow', 'false')] -// ); - -export const branchSockets = { - inputSockets: { - flow: { - valueType: 'flow' +const Branch = makeFlowNodeDefinition({ + socketsDefinition: { + inputSockets: { + flow: { + valueType: 'flow', + }, + condition: { + valueType: 'boolean', + }, }, - condition: { - valueType: 'boolean' - } - }, - outputSockets: { - true: { - valueType: 'flow' + outputSockets: { + true: { + valueType: 'flow', + }, + false: { + valueType: 'flow', + }, }, - false: { - valueType: 'flow' - } - } -} satisfies IHasSockets; - -export type BranchSocketsDefinition = typeof branchSockets; -export type BranchState = undefined; - -const Branch = makeFlowNodeDefinition({ - socketsDefinition: branchSockets, - triggered: ({ - commit, - readInput - }) => { + }, + triggered: ({ commit, readInput }) => { const value = readInput('condition'); - commit(value ? 'true' : 'false') + commit(value ? 'true' : 'false'); return undefined; }, - initialState: () => undefined -}) satisfies IFlowNode; + initialState: () => undefined, +}); -export default Branch; \ No newline at end of file +export default Branch; diff --git a/packages/core/src/nodes/flow/Counter.ts b/packages/core/src/nodes/flow/Counter.ts index 808fdc5..642823a 100644 --- a/packages/core/src/nodes/flow/Counter.ts +++ b/packages/core/src/nodes/flow/Counter.ts @@ -1,37 +1,28 @@ -import { IHasSockets, makeFlowNodeDefinition } from "../schema/INodeDefinition"; +import { makeFlowNodeDefinition } from '../schema/INodeDefinition'; -export const counterSockets = { - inputSockets: { - flow: { - valueType: 'flow' +const Counter = makeFlowNodeDefinition({ + socketsDefinition: { + inputSockets: { + flow: { + valueType: 'flow', + }, + reset: { + valueType: 'flow', + }, }, - reset: { - valueType: 'flow' - } - }, - outputSockets: { - flow: { - valueType: 'flow', + outputSockets: { + flow: { + valueType: 'flow', + }, + count: { + valueType: 'integer', + }, }, - count: { - valueType: 'integer' - } - } -} satisfies IHasSockets; - -export type CounterSocketsDefinition = typeof counterSockets; - -const Counter = makeFlowNodeDefinition({ - socketsDefinition: counterSockets, - triggered: ({ - commit, - writeOutput, - state, - triggeringSocketName - }) => { + }, + triggered: ({ commit, writeOutput, state, triggeringSocketName }) => { // duplicate count to not modify the state let count = state.count + 0n; - + switch (triggeringSocketName) { case 'flow': { count++; @@ -46,14 +37,14 @@ const Counter = makeFlowNodeDefinition({ default: throw new Error('should not get here'); } - + return { - count + count, }; }, initialState: () => ({ - count: 0n - }) + count: 0n, + }), }); -export default Counter; \ No newline at end of file +export default Counter; diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index 34312ef..e5b98e1 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -144,13 +144,13 @@ type ImmediateExecFn params: ImmediateExecParams ) => void; -export interface IImmediateNode { - socketsDefinition: T; +export interface IImmediateNode { + socketsDefinition: IHasSockets; exec: ImmediateExecFn; } -function makeImmediateNodeDefinition( - node: IImmediateNode +function makeImmediateNodeDefinition( + node: IImmediateNode ) { return node; } @@ -163,25 +163,6 @@ type unaryEvalFunction ) => ValueTypeNameMapping; -// type SocketSpec = [string, SocketValueType]; - -// type ValueTypeFromSockets = { -// [V in keyof T]: T[V]['valueType'] -// } - -// type ToObject = T extends readonly [infer Key, infer Func] -// ? Key extends PropertyKey -// ? { [P in Key]: Func } -// : never -// : never; - -// type ToObjectsArray = { -// [I in keyof T]: ToObject; -// }; - -// type UnionToIntersection = -// (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never; - export type SocketSpec = { name: string; valueType: SocketValueType; @@ -203,22 +184,6 @@ export type ToObjectsArray = { type Known = Exclude; -// export type UnionToIntersection = // `extends unknown` is always going to be the case and is used to convert the -// // `Union` into a [distributive conditional -// // type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types). -// ( -// Union extends unknown -// ? // The union type is used as the only argument to a function since the union -// // of function arguments is an intersection. -// (distributedUnion: Union) => void -// : // This won't happen. -// never -// ) extends // Infer the `Intersection` type since TypeScript represents the positional -// // arguments of unions of functions as an intersection of the union. -// (mergedIntersection: infer Intersection) => void -// ? Intersection -// : never; - export type SocketsFromSpec = Known[number]>>; export function makeSocketsFromSpec(socketSpecs: TSockets) { @@ -231,7 +196,7 @@ export function makeSocketsFromSpec(sock return sockets as SocketsFromSpec; } -export function makeInNOutNodes({ +export function makeImmediateInNOutNode({ inputValueTypes, outputValueType, unaryEvalFunc, @@ -239,7 +204,7 @@ export function makeInNOutNodes; -}) { +}): IImmediateNode { const inputSockets = makeSocketsFromSpec(inputValueTypes) satisfies Sockets; const outputSockets = makeSocketsFromSpec([outputValueType]) satisfies Sockets; diff --git a/packages/core/src/nodes/values/BooleanNodes.ts b/packages/core/src/nodes/values/BooleanNodes.ts new file mode 100644 index 0000000..656af8d --- /dev/null +++ b/packages/core/src/nodes/values/BooleanNodes.ts @@ -0,0 +1,41 @@ +import { makeImmediateInNOutNode, SocketSpec, SocketValueType } from '../schema/INodeDefinition'; +import { makeConstant, makeEqual } from './Shared'; + +const makeOutputNode = (t: T) => ({ name: 'result', valueType: t }); + +const booleans = (['a', 'b', 'c', 'd'] as const).map((name) => ({ + name, + valueType: 'boolean', +})) satisfies SocketSpec[]; + +const singleBoolean = [booleans[0]] as const; +const doubleBoolean = [booleans[0], booleans[1]] as const; +const outputBoolean = makeOutputNode('boolean'); + +export const Constant = makeConstant('boolean'); + +export const And = makeImmediateInNOutNode({ + inputValueTypes: doubleBoolean, + outputValueType: outputBoolean, + unaryEvalFunc: (a, b) => a && b, +}); + +export const Or = makeImmediateInNOutNode({ + inputValueTypes: doubleBoolean, + outputValueType: outputBoolean, + unaryEvalFunc: (a, b) => a || b, +}); + +export const Not = makeImmediateInNOutNode({ + inputValueTypes: singleBoolean, + outputValueType: outputBoolean, + unaryEvalFunc: (a) => !a, +}); + +export const ToFloat = makeImmediateInNOutNode({ + inputValueTypes: singleBoolean, + outputValueType: makeOutputNode('float'), + unaryEvalFunc: (a) => (a ? 1 : 0), +}); + +export const Equal = makeEqual('boolean'); diff --git a/packages/core/src/nodes/values/FloatNodes.ts b/packages/core/src/nodes/values/FloatNodes.ts new file mode 100644 index 0000000..90ae7be --- /dev/null +++ b/packages/core/src/nodes/values/FloatNodes.ts @@ -0,0 +1,294 @@ +import { makeImmediateInNOutNode, SocketSpec, SocketValueType } from '../schema/INodeDefinition'; +import { makeAdd, makeConstant, makeEqual, makeNegate, makeSub } from './Shared'; +import * as FloatNodes from '@behave-graph/core/src/Profiles/Core/Values/FloatNodes'; +import { Graph } from '@behave-graph/core'; + +// Unreal Engine Blueprint Float nodes: https://docs.unrealengine.com/4.27/en-US/BlueprintAPI/Math/Float/ + +// FloatNodes.Abs.factory(FloatNodes.Abs).inputSockets; + +const makeOutputNode = (t: T) => ({ name: 'result', valueType: t }); + +const floats = (['a', 'b', 'c', 'd'] as const).map((name) => ({ + name, + valueType: 'float', +})) satisfies SocketSpec[]; + +const singleFloat = [floats[0]] as const; +const doubleFloat = [floats[0], floats[1]] as const; +const outputFloat = makeOutputNode('float'); + +export const Constant = makeConstant('float'); +export const Equal = makeEqual('float'); +export const Add = makeAdd('float'); +export const Subtract = makeSub('float'); +export const Negate = makeNegate('float'); + +// export const Multiply = new NodeDescription( +// 'math/multiply/float', +// 'Logic', +// '×', +// (description, graph) => +// new In2Out1FuncNode(description, graph, ['float', 'float'], 'float', (a: number, b: number) => a * b) +// ); +// export const Divide = new NodeDescription( +// 'math/divide/float', +// 'Logic', +// '÷', +// (description, graph) => +// new In2Out1FuncNode(description, graph, ['float', 'float'], 'float', (a: number, b: number) => a / b) +// ); +// export const Modulus = new NodeDescription( +// 'math/modulus/float', +// 'Logic', +// 'MOD', +// (description, graph) => +// new In2Out1FuncNode(description, graph, ['float', 'float'], 'float', (a: number, b: number) => a % b) +// ); + +// export const Power = new NodeDescription( +// 'math/pow/float', +// 'Logic', +// 'POW', +// (description, graph) => new In2Out1FuncNode(description, graph, ['float', 'float'], 'float', Math.pow) +// ); +// export const SquareRoot = new NodeDescription( +// 'math/sqrt/float', +// 'Logic', +// '√', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.sqrt) +// ); + +// export const E = new NodeDescription( +// 'math/e/float', +// 'Logic', +// '𝑒', +// (description, graph) => new In0Out1FuncNode(description, graph, 'float', () => Math.E) +// ); +// export const Exp = new NodeDescription( +// 'math/exp/float', +// 'Logic', +// 'EXP', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.exp) +// ); +// export const Ln = new NodeDescription( +// 'math/ln/float', +// 'Logic', +// 'LN', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.log) +// ); +// export const Log2 = new NodeDescription( +// 'math/log2/float', +// 'Logic', +// 'LOG2', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.log2) +// ); +// export const Log10 = new NodeDescription( +// 'math/log10/float', +// 'Logic', +// 'LOG10', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.log10) +// ); + +// export const PI = new NodeDescription( +// 'math/pi/float', +// 'Logic', +// 'π', +// (description, graph) => new In0Out1FuncNode(description, graph, 'float', () => Math.PI) +// ); +// export const Sin = new NodeDescription( +// 'math/sin/float', +// 'Logic', +// 'SIN', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.sin) +// ); +// export const Asin = new NodeDescription( +// 'math/asin/float', +// 'Logic', +// 'ASIN', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.asin) +// ); +// export const Cos = new NodeDescription( +// 'math/cos/float', +// 'Logic', +// 'COS', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.cos) +// ); +// export const Acos = new NodeDescription( +// 'math/acos/float', +// 'Logic', +// 'ACOS', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.acos) +// ); +// export const Tan = new NodeDescription( +// 'math/tan/float', +// 'Logic', +// 'TAN', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.tan) +// ); +// export const Atan = new NodeDescription( +// 'math/atan/float', +// 'Logic', +// 'ATAN', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.atan) +// ); + +// export const Mix = new NodeDescription( +// 'math/mix/float', +// 'Logic', +// 'MIX', +// (description, graph) => +// new In3Out1FuncNode( +// description, +// graph, +// ['float', 'float', 'float'], +// 'float', +// (a: number, b: number, t: number) => { +// const s = 1 - t; +// return a * s + b * t; +// }, +// ['a', 'b', 't'] +// ) +// ); + +// export const ToFloat = new NodeDescription( +// 'math/toFloat/float', +// 'Logic', +// 'To Float', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', (a: number) => Number(a)) +// ); + +// export const Min = new NodeDescription( +// 'math/min/float', +// 'Logic', +// 'MIN', +// (description, graph) => +// new In2Out1FuncNode( +// description, +// graph, +// ['float', 'float'], +// 'float', +// (a: number, b: number) => Math.min(a, b) // TODO: can I jsut pass in Math.min? +// ) +// ); +// export const Max = new NodeDescription( +// 'math/max/float', +// 'Logic', +// 'MAX', +// (description, graph) => +// new In2Out1FuncNode( +// description, +// graph, +// ['float', 'float'], +// 'float', +// (a: number, b: number) => Math.max(a, b) // TODO: can I jsut pass in Math.max? +// ) +// ); +// export const Clamp = new NodeDescription( +// 'math/clamp/float', +// 'Logic', +// 'CLAMP', +// (description, graph) => +// new In3Out1FuncNode( +// description, +// graph, +// ['float', 'float', 'float'], +// 'float', +// (value: number, min: number, max: number) => (value < min ? min : value > max ? max : value), +// ['value', 'min', 'max'] +// ) +// ); + +// export const Abs = new NodeDescription( +// 'math/abs/float', +// 'Logic', +// 'ABS', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.abs) +// ); +// export const Sign = new NodeDescription( +// 'math/sign/float', +// 'Logic', +// 'SIGN', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.sign) +// ); + +// export const Floor = new NodeDescription( +// 'math/floor/float', +// 'Logic', +// 'FLOOR', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.floor) +// ); +// export const Ceil = new NodeDescription( +// 'math/ceil/float', +// 'Logic', +// 'CEIL', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.ceil) +// ); +// export const Round = new NodeDescription( +// 'math/round/float', +// 'Logic', +// 'ROUND', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.round) +// ); +// export const Trunc = new NodeDescription( +// 'math/trunc/float', +// 'Logic', +// 'TRUNC', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'float', Math.trunc) +// ); + +// export const Random = new NodeDescription( +// 'math/random/float', +// 'Logic', +// 'RANDOM', +// (description, graph) => new In0Out1FuncNode(description, graph, 'float', Math.random) +// ); + +// export const GreaterThan = new NodeDescription( +// 'math/greaterThan/float', +// 'Logic', +// '>', +// (description, graph) => +// new In2Out1FuncNode(description, graph, ['float', 'float'], 'boolean', (a: number, b: number) => a > b) +// ); +// export const GreaterThanOrEqual = new NodeDescription( +// 'math/greaterThanOrEqual/float', +// 'Logic', +// '≥', +// (description, graph) => +// new In2Out1FuncNode(description, graph, ['float', 'float'], 'boolean', (a: number, b: number) => a >= b) +// ); +// export const LessThan = new NodeDescription( +// 'math/lessThan/float', +// 'Logic', +// '<', +// (description, graph) => +// new In2Out1FuncNode(description, graph, ['float', 'float'], 'boolean', (a: number, b: number) => a < b) +// ); +// export const LessThanOrEqual = new NodeDescription( +// 'math/lessThanOrEqual/float', +// 'Logic', +// '≤', +// (description, graph) => +// new In2Out1FuncNode(description, graph, ['float', 'float'], 'boolean', (a: number, b: number) => a <= b) +// ); + +// export const IsNaN = new NodeDescription( +// 'math/isNaN/float', +// 'Logic', +// 'isNaN', +// (description, graph) => new In1Out1FuncNode(description, graph, ['float'], 'boolean', Number.isNaN) +// ); +// export const IsInf = new NodeDescription( +// 'math/isInf/float', +// 'Logic', +// 'isInf', +// (description, graph) => +// new In1Out1FuncNode( +// description, +// graph, +// ['float'], +// 'boolean', +// (a: number) => !Number.isFinite(a) && !Number.isNaN(a) +// ) +// ); diff --git a/packages/core/src/nodes/values/Shared.ts b/packages/core/src/nodes/values/Shared.ts new file mode 100644 index 0000000..4ee1d69 --- /dev/null +++ b/packages/core/src/nodes/values/Shared.ts @@ -0,0 +1,59 @@ +import { makeImmediateInNOutNode, SocketValueType } from '../schema/INodeDefinition'; + +export function makeConstant(valueType: TValueType) { + return makeImmediateInNOutNode({ + inputValueTypes: [{ name: 'a', valueType }], + outputValueType: { name: 'result', valueType: valueType }, + unaryEvalFunc: (a) => a, + }); +} + +export function makeEqual(valueType: TValueType) { + return makeImmediateInNOutNode({ + inputValueTypes: [ + { name: 'a', valueType }, + { name: 'b', valueType }, + ] as const, + outputValueType: { name: 'result', valueType: 'boolean' }, + unaryEvalFunc: (a, b) => a === b, + }); +} + +type NumberSocketValueTypes = Extract; + +export function makeAdd(valueType: TValueType) { + return makeImmediateInNOutNode({ + inputValueTypes: [ + { name: 'a', valueType }, + { name: 'b', valueType }, + ] as const, + outputValueType: { name: 'result', valueType }, + unaryEvalFunc: (a, b) => + // @ts-ignore + a + b, + }); +} + +export function makeSub(valueType: TValueType) { + const inputTypes = [ + { name: 'a', valueType }, + { name: 'b', valueType }, + ] as const; + return makeImmediateInNOutNode({ + inputValueTypes: inputTypes, + outputValueType: { name: 'result', valueType }, + unaryEvalFunc: (a, b) => + // @ts-ignore + a - b, + }); +} + +export function makeNegate(valueType: TValueType) { + return makeImmediateInNOutNode({ + inputValueTypes: [{ name: 'a', valueType }] as const, + outputValueType: { name: 'result', valueType }, + unaryEvalFunc: (a) => + // @ts-ignore + -a, + }); +} From e22523c0ec5c2f662b763d283851e58111a597e1 Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Mon, 28 Nov 2022 15:34:09 -0800 Subject: [PATCH 12/15] fixed some immediate nodes --- packages/core/src/nodes/flow/Branch.ts | 2 +- packages/core/src/nodes/flow/Counter.ts | 2 +- packages/core/src/nodes/schema/FlowNodes.ts | 56 +++++ .../src/nodes/schema/INodeDefinition.test.ts | 5 +- .../core/src/nodes/schema/INodeDefinition.ts | 224 +----------------- .../core/src/nodes/schema/ImmediateNodes.ts | 80 +++++++ packages/core/src/nodes/schema/Sockets.ts | 108 +++++++++ 7 files changed, 249 insertions(+), 228 deletions(-) create mode 100644 packages/core/src/nodes/schema/FlowNodes.ts create mode 100644 packages/core/src/nodes/schema/ImmediateNodes.ts create mode 100644 packages/core/src/nodes/schema/Sockets.ts diff --git a/packages/core/src/nodes/flow/Branch.ts b/packages/core/src/nodes/flow/Branch.ts index 4a20e17..0cd6c4b 100644 --- a/packages/core/src/nodes/flow/Branch.ts +++ b/packages/core/src/nodes/flow/Branch.ts @@ -1,4 +1,4 @@ -import { makeFlowNodeDefinition } from '../schema/INodeDefinition'; +import { makeFlowNodeDefinition } from '../schema/FlowNodes'; const Branch = makeFlowNodeDefinition({ socketsDefinition: { diff --git a/packages/core/src/nodes/flow/Counter.ts b/packages/core/src/nodes/flow/Counter.ts index 642823a..3df93c2 100644 --- a/packages/core/src/nodes/flow/Counter.ts +++ b/packages/core/src/nodes/flow/Counter.ts @@ -1,4 +1,4 @@ -import { makeFlowNodeDefinition } from '../schema/INodeDefinition'; +import { makeFlowNodeDefinition } from '../schema/FlowNodes'; const Counter = makeFlowNodeDefinition({ socketsDefinition: { diff --git a/packages/core/src/nodes/schema/FlowNodes.ts b/packages/core/src/nodes/schema/FlowNodes.ts new file mode 100644 index 0000000..8cb9f24 --- /dev/null +++ b/packages/core/src/nodes/schema/FlowNodes.ts @@ -0,0 +1,56 @@ +import { + IHasSockets, + InputFlowSocketNames, + InputValueSockets, + InputValueType, + OutputFlowSockets, + OutputValueSockets, + OutputValueType, +} from './Sockets'; +/** Node Engine Access Functions */ + +export type readNodeInputFn = >( + param: J +) => InputValueType; + +export type writeNodeOutputFn = >( + param: J, + value: OutputValueType +) => void; + +export type commitFn = >(param: J) => void; + +/** Flow Node Definitions */ + +export type ReadWriteToNodeParams = { + /** writes to an output node */ + writeOutput: writeNodeOutputFn; + /** reads a value from an input node */ + readInput: readNodeInputFn; +}; + +/** Arguments for the triggered function on a flow node */ +export type TriggeredParams = ReadWriteToNodeParams & { + /** commits a trigger to a flow node */ + commit: commitFn; + /** The local node's state */ + readonly state: TNodeState; + /** The name of the flow input socket that was triggered */ + triggeringSocketName: InputFlowSocketNames; +}; + +export type TriggeredFunction = ( + params: TriggeredParams +) => TNodeState; + +export interface IFlowNode { + socketsDefinition: TSockets; + /** Called when an input flow node is triggered */ + triggered: TriggeredFunction; + initialState: () => TNodeState; +} +export function makeFlowNodeDefinition( + flowNode: IFlowNode +): IFlowNode { + return flowNode; +} diff --git a/packages/core/src/nodes/schema/INodeDefinition.test.ts b/packages/core/src/nodes/schema/INodeDefinition.test.ts index de25e74..1b8a2b0 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.test.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.test.ts @@ -1,16 +1,15 @@ +import { makeFlowNodeDefinition, readNodeInputFn } from './FlowNodes'; import { FlowSockets, IHasSockets, - makeFlowNodeDefinition, OutputValueType, - readNodeInputFn, ValueSockets, ExtractValueType, ValueTypeNameMapping, SocketSpec, SocketValueTypes, SocketNames, -} from './INodeDefinition'; +} from './Sockets'; import { expectType } from './testUtils'; describe('TriggeredParams', () => { diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index e5b98e1..3a4f516 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -1,231 +1,9 @@ import { FlowNode, NodeCategory, Socket } from '@behave-graph/core'; import { UnionToIntersection } from 'type-fest'; - -export type SocketValueType = 'flow' | 'boolean' | 'integer' | 'float' | 'string' | 'jsonPath'; - -export interface ISocketDefinition { - readonly valueType: SocketValueType; -} - -export type Sockets = { - readonly [key: string]: ISocketDefinition; -}; - -export type IHasSockets = { - readonly inputSockets: Sockets; - readonly outputSockets: Sockets; -}; +import { IHasSockets } from './Sockets'; export interface INodeDefinition extends IHasSockets { typeName: string; category: NodeCategory; label: string; } - -export type ValueTypeNameMapping = { - boolean: boolean; - integer: bigint; - float: number; - string: string; - jsonPath: string; - flow: void; -}[K]; - -export type OptionalValueTypeMapping = ValueTypeNameMapping | undefined; - -type OutputSockets> = T['outputSockets']; -type InputSockets> = T['inputSockets']; - -type FlowSocketDef = { - valueType: 'flow'; -}; - -export type ValueSockets = Pick< - T, - { [K in keyof T]-?: T[K] extends FlowSocketDef ? never : K }[keyof T] ->; - -export type FlowSockets = Pick< - T, - { [K in keyof T]-?: T[K] extends FlowSocketDef ? K : never }[keyof T] ->; - -export type ExtractValueType = ValueTypeNameMapping; - -export type OutputValueSockets> = ValueSockets>; -export type InputValueSockets> = ValueSockets>; -export type InputFlowSockets> = FlowSockets>; -export type OutputFlowSockets> = FlowSockets>; - -export type InputFlowSocketNames> = keyof InputFlowSockets; -export type OutputFlowSocketNames> = keyof OutputFlowSockets; -export type OutputValueSocketNames> = keyof OutputValueSockets; - -export type NodeInputValues> = { - [K in keyof InputValueSockets]?: ValueTypeNameMapping[K]['valueType']>; -}; - -export type OutputValueType> = ExtractValueType< - OutputValueSockets, - J ->; - -export type InputValueType> = ExtractValueType< - InputValueSockets, - J ->; - -/** Node Engine Access Functions */ - -export type readNodeInputFn = >( - param: J -) => InputValueType; - -export type writeNodeOutputFn = >( - param: J, - value: OutputValueType -) => void; - -export type commitFn = >(param: J) => void; - -/** Flow Node Definitions */ - -export type ReadWriteToNodeParams = { - /** writes to an output node */ - writeOutput: writeNodeOutputFn; - /** reads a value from an input node */ - readInput: readNodeInputFn; -}; - -/** Arguments for the triggered function on a flow node */ -export type TriggeredParams = ReadWriteToNodeParams & { - /** commits a trigger to a flow node */ - commit: commitFn; - /** The local node's state */ - readonly state: TNodeState; - /** The name of the flow input socket that was triggered */ - triggeringSocketName: InputFlowSocketNames; -}; - -export type TriggeredFunction = ( - params: TriggeredParams -) => TNodeState; - -export interface IFlowNode { - socketsDefinition: TSockets; - /** Called when an input flow node is triggered */ - triggered: TriggeredFunction; - initialState: () => TNodeState; -} -export function makeFlowNodeDefinition( - flowNode: IFlowNode -): IFlowNode { - return flowNode; -} - -export type immediateReadIn = < - S extends Known>, - K extends keyof S ->( - key: K -) => S[K]; - -export type immediateWriteOut = ( - key: TSocket['name'], - value: ValueTypeNameMapping -) => void; - -type ImmediateExecParams = { - readInput: immediateReadIn; - writeOutput: immediateWriteOut; -}; - -type ImmediateExecFn = ( - params: ImmediateExecParams -) => void; - -export interface IImmediateNode { - socketsDefinition: IHasSockets; - exec: ImmediateExecFn; -} - -function makeImmediateNodeDefinition( - node: IImmediateNode -) { - return node; -} - -export type SocketValueTypes = { - [K in keyof T]: ValueTypeNameMapping; -}; - -type unaryEvalFunction = ( - ...params: SocketValueTypes -) => ValueTypeNameMapping; - -export type SocketSpec = { - name: string; - valueType: SocketValueType; -}; - -export type SocketNames = { - [K in keyof T]: T[K]['name']; -}; - -type ToSocket = { - [P in T['name']]: { - valueType: T['valueType']; - }; -}; - -export type ToObjectsArray = { - [I in keyof T]: ToSocket; -}; - -type Known = Exclude; - -export type SocketsFromSpec = Known[number]>>; - -export function makeSocketsFromSpec(socketSpecs: TSockets) { - const sockets: any = {}; - - for (const { name, valueType } of socketSpecs) { - sockets[name] = { valueType } satisfies ISocketDefinition; - } - - return sockets as SocketsFromSpec; -} - -export function makeImmediateInNOutNode({ - inputValueTypes, - outputValueType, - unaryEvalFunc, -}: { - inputValueTypes: TIn; - outputValueType: TOut; - unaryEvalFunc: unaryEvalFunction; -}): IImmediateNode { - const inputSockets = makeSocketsFromSpec(inputValueTypes) satisfies Sockets; - const outputSockets = makeSocketsFromSpec([outputValueType]) satisfies Sockets; - - // const x: immediateReadIn = (param) => {}; - - const exec: ImmediateExecFn = ({ readInput, writeOutput }) => { - // let args: any[] = []; - const names = inputValueTypes.map(({ name }) => name) as SocketNames; - - const inputValues = names.map((x) => readInput(x)) as unknown as SocketValueTypes; - - const result = unaryEvalFunc(...inputValues); - - writeOutput(outputValueType['name'], result); - }; - - return makeImmediateNodeDefinition({ - socketsDefinition: { - inputSockets, - outputSockets, - }, - exec, - }); -} diff --git a/packages/core/src/nodes/schema/ImmediateNodes.ts b/packages/core/src/nodes/schema/ImmediateNodes.ts new file mode 100644 index 0000000..bc5cb55 --- /dev/null +++ b/packages/core/src/nodes/schema/ImmediateNodes.ts @@ -0,0 +1,80 @@ +import { + IHasSockets, + Known, + makeSocketsFromSpec, + SocketNames, + Sockets, + SocketsFromSpec, + SocketSpec, + SocketValueTypes, + ValueTypeNameMapping, +} from './Sockets'; + +export type unaryEvalFunction = ( + ...params: SocketValueTypes +) => SocketValueTypes; + +export type immediateReadIn = < + S extends Known>, + K extends keyof S +>( + key: K +) => S[K]; + +export type immediateWriteOut = < + S extends Known>, + K extends keyof S +>( + key: K, + value: S[K] +) => void; + +type ImmediateExecParams = { + readInput: immediateReadIn; + writeOutput: immediateWriteOut; +}; + +type ImmediateExecFn = ( + params: ImmediateExecParams +) => void; + +export interface IImmediateNode { + inputSockets: TIn; + outputSockets: TOut; + exec: ImmediateExecFn; +} + +export function makeImmediateInNOutNodeDefinition< + TIn extends readonly SocketSpec[], + TOut extends readonly SocketSpec[] +>({ + inputValueTypes, + outputValueTypes, + unaryEvalFunc, +}: { + inputValueTypes: TIn; + outputValueTypes: TOut; + unaryEvalFunc: unaryEvalFunction; +}): IImmediateNode { + const exec: ImmediateExecFn = ({ readInput, writeOutput }) => { + const inputNames = inputValueTypes.map(({ name }) => name) as SocketNames; + const outputNames = outputValueTypes.map(({ name }) => name) as SocketNames; + + const inputValues = inputNames.map((x) => readInput(x)) as unknown as SocketValueTypes; + + const outputValues = unaryEvalFunc(...inputValues) as unknown as SocketValueTypes; + + outputNames.forEach((outputName, i) => { + // @ts-ignore + writeOutput(outputName, outputValues[i]); + }); + }; + + const node: IImmediateNode = { + inputSockets: inputValueTypes, + outputSockets: outputValueTypes, + exec, + }; + + return node; +} diff --git a/packages/core/src/nodes/schema/Sockets.ts b/packages/core/src/nodes/schema/Sockets.ts new file mode 100644 index 0000000..86605eb --- /dev/null +++ b/packages/core/src/nodes/schema/Sockets.ts @@ -0,0 +1,108 @@ +import { UnionToIntersection } from 'type-fest'; + +export type SocketValueType = 'flow' | 'boolean' | 'integer' | 'float' | 'string' | 'jsonPath'; + +export type ValueTypeNameMapping = { + boolean: boolean; + integer: bigint; + float: number; + string: string; + jsonPath: string; + flow: void; +}[K]; + +export type OptionalValueTypeMapping = ValueTypeNameMapping | undefined; + +export interface ISocketDefinition { + readonly valueType: SocketValueType; +} + +export type Sockets = { + readonly [key: string]: ISocketDefinition; +}; + +export type OutputSockets> = T['outputSockets']; +export type InputSockets> = T['inputSockets']; + +type FlowSocketDef = { + valueType: 'flow'; +}; + +export type ValueSockets = Pick< + T, + { [K in keyof T]-?: T[K] extends FlowSocketDef ? never : K }[keyof T] +>; + +export type FlowSockets = Pick< + T, + { [K in keyof T]-?: T[K] extends FlowSocketDef ? K : never }[keyof T] +>; + +/** IHasSockets Utils */ + +export type IHasSockets = { + readonly inputSockets: Sockets; + readonly outputSockets: Sockets; +}; + +export type ExtractValueType = ValueTypeNameMapping; + +export type OutputValueSockets> = ValueSockets>; +export type InputValueSockets> = ValueSockets>; +export type InputFlowSockets> = FlowSockets>; +export type OutputFlowSockets> = FlowSockets>; + +export type InputFlowSocketNames> = keyof InputFlowSockets; +export type OutputFlowSocketNames> = keyof OutputFlowSockets; +export type OutputValueSocketNames> = keyof OutputValueSockets; + +export type NodeInputValues> = { + [K in keyof InputValueSockets]?: ValueTypeNameMapping[K]['valueType']>; +}; + +export type OutputValueType> = ExtractValueType< + OutputValueSockets, + J +>; + +export type InputValueType> = ExtractValueType< + InputValueSockets, + J +>; + +export type SocketValueTypes = { + [K in keyof T]: ValueTypeNameMapping; +}; + +export type SocketSpec = { + name: string; + valueType: SocketValueType; +}; + +export type SocketNames = { + [K in keyof T]: T[K]['name']; +}; + +type ToSocket = { + [P in T['name']]: { + valueType: T['valueType']; + }; +}; + +export type ToObjectsArray = { + [I in keyof T]: ToSocket; +}; + +export type Known = Exclude; + +export type SocketsFromSpec = Known[number]>>; + +export function makeSocketsFromSpec(socketSpecs: TSockets) { + const sockets: any = {}; + + for (const { name, valueType } of socketSpecs) { + sockets[name] = { valueType } satisfies ISocketDefinition; + } + + return sockets as SocketsFromSpec; +} From c3d1ae3494c92689d91762f90d7d6a71ba15c044 Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Mon, 28 Nov 2022 19:58:41 -0800 Subject: [PATCH 13/15] have definition system working --- packages/core/src/nodes/flow/Branch.ts | 28 ++-- packages/core/src/nodes/flow/Counter.ts | 28 ++-- packages/core/src/nodes/schema/FlowNodes.ts | 55 ++++---- .../src/nodes/schema/INodeDefinition.test.ts | 47 ++----- .../core/src/nodes/schema/INodeDefinition.ts | 13 +- .../core/src/nodes/schema/ImmediateNodes.ts | 126 +++++++++--------- packages/core/src/nodes/schema/Sockets.ts | 38 ++---- .../core/src/nodes/values/BooleanNodes.ts | 74 ++++++---- packages/core/src/nodes/values/FloatNodes.ts | 18 --- packages/core/src/nodes/values/Shared.ts | 77 ++++++----- 10 files changed, 228 insertions(+), 276 deletions(-) diff --git a/packages/core/src/nodes/flow/Branch.ts b/packages/core/src/nodes/flow/Branch.ts index 0cd6c4b..6654d5c 100644 --- a/packages/core/src/nodes/flow/Branch.ts +++ b/packages/core/src/nodes/flow/Branch.ts @@ -1,22 +1,20 @@ import { makeFlowNodeDefinition } from '../schema/FlowNodes'; const Branch = makeFlowNodeDefinition({ - socketsDefinition: { - inputSockets: { - flow: { - valueType: 'flow', - }, - condition: { - valueType: 'boolean', - }, + inputSockets: { + flow: { + valueType: 'flow', }, - outputSockets: { - true: { - valueType: 'flow', - }, - false: { - valueType: 'flow', - }, + condition: { + valueType: 'boolean', + }, + }, + outputSockets: { + true: { + valueType: 'flow', + }, + false: { + valueType: 'flow', }, }, triggered: ({ commit, readInput }) => { diff --git a/packages/core/src/nodes/flow/Counter.ts b/packages/core/src/nodes/flow/Counter.ts index 3df93c2..f3488f1 100644 --- a/packages/core/src/nodes/flow/Counter.ts +++ b/packages/core/src/nodes/flow/Counter.ts @@ -1,22 +1,20 @@ import { makeFlowNodeDefinition } from '../schema/FlowNodes'; const Counter = makeFlowNodeDefinition({ - socketsDefinition: { - inputSockets: { - flow: { - valueType: 'flow', - }, - reset: { - valueType: 'flow', - }, + inputSockets: { + flow: { + valueType: 'flow', }, - outputSockets: { - flow: { - valueType: 'flow', - }, - count: { - valueType: 'integer', - }, + reset: { + valueType: 'flow', + }, + }, + outputSockets: { + flow: { + valueType: 'flow', + }, + count: { + valueType: 'integer', }, }, triggered: ({ commit, writeOutput, state, triggeringSocketName }) => { diff --git a/packages/core/src/nodes/schema/FlowNodes.ts b/packages/core/src/nodes/schema/FlowNodes.ts index 8cb9f24..4fc1eee 100644 --- a/packages/core/src/nodes/schema/FlowNodes.ts +++ b/packages/core/src/nodes/schema/FlowNodes.ts @@ -1,56 +1,53 @@ -import { - IHasSockets, - InputFlowSocketNames, - InputValueSockets, - InputValueType, - OutputFlowSockets, - OutputValueSockets, - OutputValueType, -} from './Sockets'; +import { FlowSocketNames, FlowSockets, IHasSockets, Sockets, ValueSockets, ValueTypeNameMapping } from './Sockets'; /** Node Engine Access Functions */ -export type readNodeInputFn = >( +export type readNodeInputFn = , J extends keyof V>( param: J -) => InputValueType; +) => ValueTypeNameMapping; -export type writeNodeOutputFn = >( +export type writeNodeOutputFn = , J extends keyof V>( param: J, - value: OutputValueType + value: ValueTypeNameMapping ) => void; -export type commitFn = >(param: J) => void; +export type commitFn = >(param: J) => void; /** Flow Node Definitions */ -export type ReadWriteToNodeParams = { - /** writes to an output node */ - writeOutput: writeNodeOutputFn; +export type ReadWriteToNodeParams = { /** reads a value from an input node */ - readInput: readNodeInputFn; + readInput: readNodeInputFn; + /** writes to an output node */ + writeOutput: writeNodeOutputFn; }; /** Arguments for the triggered function on a flow node */ -export type TriggeredParams = ReadWriteToNodeParams & { +export type TriggeredParams = ReadWriteToNodeParams< + TInput, + TOutput +> & { /** commits a trigger to a flow node */ - commit: commitFn; + commit: commitFn; /** The local node's state */ readonly state: TNodeState; /** The name of the flow input socket that was triggered */ - triggeringSocketName: InputFlowSocketNames; + triggeringSocketName: FlowSocketNames; }; -export type TriggeredFunction = ( - params: TriggeredParams +export type TriggeredFunction = ( + params: TriggeredParams ) => TNodeState; -export interface IFlowNode { - socketsDefinition: TSockets; +export interface IFlowNode + extends IHasSockets { /** Called when an input flow node is triggered */ - triggered: TriggeredFunction; + triggered: TriggeredFunction; initialState: () => TNodeState; } -export function makeFlowNodeDefinition( - flowNode: IFlowNode -): IFlowNode { +export function makeFlowNodeDefinition< + TInputSockets extends Sockets, + TOutputSockets extends Sockets, + TNodeState = void +>(flowNode: IFlowNode) { return flowNode; } diff --git a/packages/core/src/nodes/schema/INodeDefinition.test.ts b/packages/core/src/nodes/schema/INodeDefinition.test.ts index 1b8a2b0..c149c7a 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.test.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.test.ts @@ -1,21 +1,11 @@ import { makeFlowNodeDefinition, readNodeInputFn } from './FlowNodes'; -import { - FlowSockets, - IHasSockets, - OutputValueType, - ValueSockets, - ExtractValueType, - ValueTypeNameMapping, - SocketSpec, - SocketValueTypes, - SocketNames, -} from './Sockets'; +import { FlowSockets, ValueSockets, ExtractValueType, ValueTypeNameMapping, Sockets } from './Sockets'; import { expectType } from './testUtils'; describe('TriggeredParams', () => { describe('writeOutput', () => { it('can only write output to a socket in the output definition that is a value type', () => { - const vals = { + const flowDef = makeFlowNodeDefinition({ inputSockets: { a: { valueType: 'boolean', @@ -41,21 +31,19 @@ describe('TriggeredParams', () => { valueType: 'string', }, }, - } satisfies IHasSockets; - - makeFlowNodeDefinition({ - socketsDefinition: vals, triggered: ({ commit, readInput, writeOutput }) => { const a = readInput('a'); writeOutput('c', a ? 1.0 : 0.0); + commit('e'); + return undefined; }, initialState: () => undefined, }); - expectType>({ + expectType>({ a: { valueType: 'boolean', }, @@ -64,7 +52,7 @@ describe('TriggeredParams', () => { }, }); - expectType>({ + expectType>({ c: { valueType: 'flow', }, @@ -72,24 +60,13 @@ describe('TriggeredParams', () => { expectType>(true); expectType>('asdfasfd'); - expectType>(false); - expectType>(1.0); - expectType>(1n); - expectType>('asdfasfd'); + expectType>(false); + // expectType>(1.0); + // expectType>(1n); + // expectType>('asdfasfd'); - expectType>>(['a']); - expectType>>(['b']); + expectType>>(['a']); + expectType>>(['b']); }); }); - describe('Function generation', () => { - const socketDefs = [ - { name: 'a', valueType: 'float' }, - { name: 'g', valueType: 'string' }, - ] as const; - - const outputSocketDef = { name: 'c', valueType: 'float' } satisfies SocketSpec; - - expectType>([1.0, '6']); - expectType>(['a', 'g']); - }); }); diff --git a/packages/core/src/nodes/schema/INodeDefinition.ts b/packages/core/src/nodes/schema/INodeDefinition.ts index 3a4f516..5974f7e 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.ts @@ -1,9 +1,8 @@ -import { FlowNode, NodeCategory, Socket } from '@behave-graph/core'; -import { UnionToIntersection } from 'type-fest'; +import { NodeCategory } from '@behave-graph/core'; import { IHasSockets } from './Sockets'; -export interface INodeDefinition extends IHasSockets { - typeName: string; - category: NodeCategory; - label: string; -} +// export interface INodeDefinition extends IHasSockets { +// typeName: string; +// category: NodeCategory; +// label: string; +// } diff --git a/packages/core/src/nodes/schema/ImmediateNodes.ts b/packages/core/src/nodes/schema/ImmediateNodes.ts index bc5cb55..9015db6 100644 --- a/packages/core/src/nodes/schema/ImmediateNodes.ts +++ b/packages/core/src/nodes/schema/ImmediateNodes.ts @@ -1,80 +1,78 @@ -import { - IHasSockets, - Known, - makeSocketsFromSpec, - SocketNames, - Sockets, - SocketsFromSpec, - SocketSpec, - SocketValueTypes, - ValueTypeNameMapping, -} from './Sockets'; +import { ReadWriteToNodeParams } from './FlowNodes'; +import { Sockets } from './Sockets'; -export type unaryEvalFunction = ( - ...params: SocketValueTypes -) => SocketValueTypes; +// type PickSocket = TSockets[k]; -export type immediateReadIn = < - S extends Known>, - K extends keyof S ->( - key: K -) => S[K]; +// type PickValueTypes = { +// readonly [K in keyof inputOrder]: ValueTypeNameMapping['valueType']>; +// }; -export type immediateWriteOut = < - S extends Known>, - K extends keyof S ->( - key: K, - value: S[K] -) => void; - -type ImmediateExecParams = { - readInput: immediateReadIn; - writeOutput: immediateWriteOut; -}; +// type unaryEvalFunction< +// TInput extends Sockets, +// TOutputs extends Sockets, +// inputOrder extends readonly (keyof TInput)[], +// outputOrder extends readonly (keyof TOutputs)[] +// > = (...params: PickValueTypes) => PickValueTypes; -type ImmediateExecFn = ( - params: ImmediateExecParams +export type ImmediateExecFn = ( + params: ReadWriteToNodeParams ) => void; -export interface IImmediateNode { +export interface IImmediateNode { inputSockets: TIn; outputSockets: TOut; exec: ImmediateExecFn; } -export function makeImmediateInNOutNodeDefinition< - TIn extends readonly SocketSpec[], - TOut extends readonly SocketSpec[] ->({ - inputValueTypes, - outputValueTypes, - unaryEvalFunc, -}: { - inputValueTypes: TIn; - outputValueTypes: TOut; - unaryEvalFunc: unaryEvalFunction; -}): IImmediateNode { - const exec: ImmediateExecFn = ({ readInput, writeOutput }) => { - const inputNames = inputValueTypes.map(({ name }) => name) as SocketNames; - const outputNames = outputValueTypes.map(({ name }) => name) as SocketNames; +export function makeImmediateNodeDefinition( + nodeDefinition: IImmediateNode +) { + return nodeDefinition; +} + +export function makeExec(exec: ImmediateExecFn) { + return exec; +} - const inputValues = inputNames.map((x) => readInput(x)) as unknown as SocketValueTypes; +// export function makeImmediateInNOutNodeDefinition< +// TIn extends Sockets, +// TOut extends Sockets, +// inputOrder extends (keyof TIn)[], +// outputOrder extends (keyof TOut)[] +// >({ +// inputValueTypes, +// outputValueTypes, +// unaryEvalFunc, +// }: { +// inputValueTypes: TIn; +// outputValueTypes: TOut; +// inputOrder: keyof TIn[]; +// outputOrder: keyof TOut[]; +// unaryEvalFunc: unaryEvalFunction; +// }): IImmediateNode { +// const exec: ReadWriteToNodeParams = ({ readInput }) => { +// return; +// }; - const outputValues = unaryEvalFunc(...inputValues) as unknown as SocketValueTypes; +// // = ({ readInput, writeOutput }) => { +// // const inputNames = inputValueTypes.map(({ name }) => name) as SocketNames; +// // const outputNames = outputValueTypes.map(({ name }) => name) as SocketNames; - outputNames.forEach((outputName, i) => { - // @ts-ignore - writeOutput(outputName, outputValues[i]); - }); - }; +// // const inputValues = inputNames.map((x) => readInput(x)) as unknown as SocketValueTypes; - const node: IImmediateNode = { - inputSockets: inputValueTypes, - outputSockets: outputValueTypes, - exec, - }; +// // const outputValues = unaryEvalFunc(...inputValues) as unknown as SocketValueTypes; - return node; -} +// // outputNames.forEach((outputName, i) => { +// // // @ts-ignore +// // writeOutput(outputName, outputValues[i]); +// // }); +// // }; + +// const node: IImmediateNode = { +// inputSockets: inputValueTypes, +// outputSockets: outputValueTypes, +// exec, +// }; + +// return node; +// } diff --git a/packages/core/src/nodes/schema/Sockets.ts b/packages/core/src/nodes/schema/Sockets.ts index 86605eb..9552e2b 100644 --- a/packages/core/src/nodes/schema/Sockets.ts +++ b/packages/core/src/nodes/schema/Sockets.ts @@ -11,6 +11,10 @@ export type ValueTypeNameMapping = { flow: void; }[K]; +export type ValueTypeMappings = { + [K in keyof SocketValueTypes]: ValueTypeNameMapping; +}; + export type OptionalValueTypeMapping = ValueTypeNameMapping | undefined; export interface ISocketDefinition { @@ -21,9 +25,6 @@ export type Sockets = { readonly [key: string]: ISocketDefinition; }; -export type OutputSockets> = T['outputSockets']; -export type InputSockets> = T['inputSockets']; - type FlowSocketDef = { valueType: 'flow'; }; @@ -38,38 +39,17 @@ export type FlowSockets = Pick< { [K in keyof T]-?: T[K] extends FlowSocketDef ? K : never }[keyof T] >; +export type FlowSocketNames = keyof FlowSockets; + /** IHasSockets Utils */ -export type IHasSockets = { - readonly inputSockets: Sockets; - readonly outputSockets: Sockets; +export type IHasSockets = { + readonly inputSockets: TInputSockets; + readonly outputSockets: TOutputSockets; }; export type ExtractValueType = ValueTypeNameMapping; -export type OutputValueSockets> = ValueSockets>; -export type InputValueSockets> = ValueSockets>; -export type InputFlowSockets> = FlowSockets>; -export type OutputFlowSockets> = FlowSockets>; - -export type InputFlowSocketNames> = keyof InputFlowSockets; -export type OutputFlowSocketNames> = keyof OutputFlowSockets; -export type OutputValueSocketNames> = keyof OutputValueSockets; - -export type NodeInputValues> = { - [K in keyof InputValueSockets]?: ValueTypeNameMapping[K]['valueType']>; -}; - -export type OutputValueType> = ExtractValueType< - OutputValueSockets, - J ->; - -export type InputValueType> = ExtractValueType< - InputValueSockets, - J ->; - export type SocketValueTypes = { [K in keyof T]: ValueTypeNameMapping; }; diff --git a/packages/core/src/nodes/values/BooleanNodes.ts b/packages/core/src/nodes/values/BooleanNodes.ts index 656af8d..d6ae5ff 100644 --- a/packages/core/src/nodes/values/BooleanNodes.ts +++ b/packages/core/src/nodes/values/BooleanNodes.ts @@ -1,41 +1,61 @@ -import { makeImmediateInNOutNode, SocketSpec, SocketValueType } from '../schema/INodeDefinition'; +import { makeImmediateNodeDefinition } from '../schema/ImmediateNodes'; +import { Sockets, SocketSpec } from '../schema/Sockets'; import { makeConstant, makeEqual } from './Shared'; -const makeOutputNode = (t: T) => ({ name: 'result', valueType: t }); - -const booleans = (['a', 'b', 'c', 'd'] as const).map((name) => ({ - name, - valueType: 'boolean', -})) satisfies SocketSpec[]; - -const singleBoolean = [booleans[0]] as const; -const doubleBoolean = [booleans[0], booleans[1]] as const; -const outputBoolean = makeOutputNode('boolean'); +const singleBoolean = { + a: { + valueType: 'boolean', + }, +} satisfies Sockets; +const doubleBoolean = { + ...singleBoolean, + b: { + valueType: 'boolean', + }, +} satisfies Sockets; + +const singleOutput = { + result: { + valueType: 'boolean', + }, +} satisfies Sockets; export const Constant = makeConstant('boolean'); -export const And = makeImmediateInNOutNode({ - inputValueTypes: doubleBoolean, - outputValueType: outputBoolean, - unaryEvalFunc: (a, b) => a && b, +export const And = makeImmediateNodeDefinition({ + inputSockets: doubleBoolean, + outputSockets: singleOutput, + exec: ({ readInput, writeOutput }) => { + writeOutput('result', readInput('a') && readInput('b')); + }, }); -export const Or = makeImmediateInNOutNode({ - inputValueTypes: doubleBoolean, - outputValueType: outputBoolean, - unaryEvalFunc: (a, b) => a || b, +export const Or = makeImmediateNodeDefinition({ + inputSockets: doubleBoolean, + outputSockets: singleOutput, + exec: ({ readInput, writeOutput }) => { + writeOutput('result', readInput('a') || readInput('b')); + }, }); -export const Not = makeImmediateInNOutNode({ - inputValueTypes: singleBoolean, - outputValueType: outputBoolean, - unaryEvalFunc: (a) => !a, +export const Not = makeImmediateNodeDefinition({ + inputSockets: singleBoolean, + outputSockets: singleOutput, + exec: ({ readInput, writeOutput }) => { + writeOutput('result', !readInput('a')); + }, }); -export const ToFloat = makeImmediateInNOutNode({ - inputValueTypes: singleBoolean, - outputValueType: makeOutputNode('float'), - unaryEvalFunc: (a) => (a ? 1 : 0), +export const ToFloat = makeImmediateNodeDefinition({ + inputSockets: singleBoolean, + outputSockets: { + result: { + valueType: 'float', + }, + }, + exec: ({ readInput, writeOutput }) => { + writeOutput('result', readInput('a') ? 1 : 0); + }, }); export const Equal = makeEqual('boolean'); diff --git a/packages/core/src/nodes/values/FloatNodes.ts b/packages/core/src/nodes/values/FloatNodes.ts index 90ae7be..628a25d 100644 --- a/packages/core/src/nodes/values/FloatNodes.ts +++ b/packages/core/src/nodes/values/FloatNodes.ts @@ -1,22 +1,4 @@ -import { makeImmediateInNOutNode, SocketSpec, SocketValueType } from '../schema/INodeDefinition'; import { makeAdd, makeConstant, makeEqual, makeNegate, makeSub } from './Shared'; -import * as FloatNodes from '@behave-graph/core/src/Profiles/Core/Values/FloatNodes'; -import { Graph } from '@behave-graph/core'; - -// Unreal Engine Blueprint Float nodes: https://docs.unrealengine.com/4.27/en-US/BlueprintAPI/Math/Float/ - -// FloatNodes.Abs.factory(FloatNodes.Abs).inputSockets; - -const makeOutputNode = (t: T) => ({ name: 'result', valueType: t }); - -const floats = (['a', 'b', 'c', 'd'] as const).map((name) => ({ - name, - valueType: 'float', -})) satisfies SocketSpec[]; - -const singleFloat = [floats[0]] as const; -const doubleFloat = [floats[0], floats[1]] as const; -const outputFloat = makeOutputNode('float'); export const Constant = makeConstant('float'); export const Equal = makeEqual('float'); diff --git a/packages/core/src/nodes/values/Shared.ts b/packages/core/src/nodes/values/Shared.ts index 4ee1d69..be7df80 100644 --- a/packages/core/src/nodes/values/Shared.ts +++ b/packages/core/src/nodes/values/Shared.ts @@ -1,59 +1,62 @@ -import { makeImmediateInNOutNode, SocketValueType } from '../schema/INodeDefinition'; +import { makeImmediateNodeDefinition } from '../schema/ImmediateNodes'; +import { Sockets, SocketValueType } from '../schema/Sockets'; export function makeConstant(valueType: TValueType) { - return makeImmediateInNOutNode({ - inputValueTypes: [{ name: 'a', valueType }], - outputValueType: { name: 'result', valueType: valueType }, - unaryEvalFunc: (a) => a, + return makeImmediateNodeDefinition({ + inputSockets: { a: { valueType } } satisfies Sockets, + outputSockets: { result: { valueType } } satisfies Sockets, + exec: ({ readInput, writeOutput }) => { + writeOutput('result', readInput('a')); + }, }); } export function makeEqual(valueType: TValueType) { - return makeImmediateInNOutNode({ - inputValueTypes: [ - { name: 'a', valueType }, - { name: 'b', valueType }, - ] as const, - outputValueType: { name: 'result', valueType: 'boolean' }, - unaryEvalFunc: (a, b) => a === b, + return makeImmediateNodeDefinition({ + inputSockets: { a: { valueType }, b: { valueType } } satisfies Sockets, + outputSockets: { result: { valueType } } satisfies Sockets, + exec: ({ readInput, writeOutput }) => { + writeOutput('result', readInput('a') === readInput('b')); + }, }); } type NumberSocketValueTypes = Extract; export function makeAdd(valueType: TValueType) { - return makeImmediateInNOutNode({ - inputValueTypes: [ - { name: 'a', valueType }, - { name: 'b', valueType }, - ] as const, - outputValueType: { name: 'result', valueType }, - unaryEvalFunc: (a, b) => - // @ts-ignore - a + b, + return makeImmediateNodeDefinition({ + inputSockets: { a: { valueType }, b: { valueType } } satisfies Sockets, + outputSockets: { result: { valueType } } satisfies Sockets, + exec: ({ readInput, writeOutput }) => { + writeOutput( + 'result', + // @ts-ignore + readInput('a') + readInput('b') + ); + }, }); } export function makeSub(valueType: TValueType) { - const inputTypes = [ - { name: 'a', valueType }, - { name: 'b', valueType }, - ] as const; - return makeImmediateInNOutNode({ - inputValueTypes: inputTypes, - outputValueType: { name: 'result', valueType }, - unaryEvalFunc: (a, b) => - // @ts-ignore - a - b, + return makeImmediateNodeDefinition({ + inputSockets: { a: { valueType }, b: { valueType } } satisfies Sockets, + outputSockets: { result: { valueType } } satisfies Sockets, + exec: ({ readInput, writeOutput }) => { + writeOutput( + 'result', + // @ts-ignore + readInput('a') - readInput('b') + ); + }, }); } export function makeNegate(valueType: TValueType) { - return makeImmediateInNOutNode({ - inputValueTypes: [{ name: 'a', valueType }] as const, - outputValueType: { name: 'result', valueType }, - unaryEvalFunc: (a) => - // @ts-ignore - -a, + return makeImmediateNodeDefinition({ + inputSockets: { a: { valueType } } satisfies Sockets, + outputSockets: { result: { valueType } } satisfies Sockets, + exec: ({ readInput, writeOutput }) => { + writeOutput('result', -readInput('a')); + }, }); } From b0def3c13a672f3ff25c2622d82c69758fbba38a Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Mon, 28 Nov 2022 20:10:39 -0800 Subject: [PATCH 14/15] fixed tests --- packages/core/src/nodes/flow/Counter.test.ts | 4 +- packages/core/src/nodes/schema/FlowNodes.ts | 9 ++- .../src/nodes/schema/INodeDefinition.test.ts | 3 - packages/core/src/nodes/schema/testUtils.ts | 58 ++++++++----------- 4 files changed, 33 insertions(+), 41 deletions(-) diff --git a/packages/core/src/nodes/flow/Counter.test.ts b/packages/core/src/nodes/flow/Counter.test.ts index 1fd8ae2..ce52a97 100644 --- a/packages/core/src/nodes/flow/Counter.test.ts +++ b/packages/core/src/nodes/flow/Counter.test.ts @@ -10,7 +10,7 @@ describe('Branch', () => { trigger('flow'); trigger('flow'); - const expected: RecordedOutputWrites = [ + const expected: RecordedOutputWrites = [ { writeType: 'value', socketName: 'count', @@ -41,7 +41,7 @@ describe('Branch', () => { trigger('reset'); trigger('flow'); - const expected: RecordedOutputWrites = [ + const expected: RecordedOutputWrites = [ { writeType: 'value', socketName: 'count', diff --git a/packages/core/src/nodes/schema/FlowNodes.ts b/packages/core/src/nodes/schema/FlowNodes.ts index 4fc1eee..6bbcefa 100644 --- a/packages/core/src/nodes/schema/FlowNodes.ts +++ b/packages/core/src/nodes/schema/FlowNodes.ts @@ -1,9 +1,12 @@ import { FlowSocketNames, FlowSockets, IHasSockets, Sockets, ValueSockets, ValueTypeNameMapping } from './Sockets'; /** Node Engine Access Functions */ -export type readNodeInputFn = , J extends keyof V>( - param: J -) => ValueTypeNameMapping; +export type readNodeInputFn = < + TValueSockets extends ValueSockets, + KValueSocket extends keyof TValueSockets +>( + param: KValueSocket +) => ValueTypeNameMapping; export type writeNodeOutputFn = , J extends keyof V>( param: J, diff --git a/packages/core/src/nodes/schema/INodeDefinition.test.ts b/packages/core/src/nodes/schema/INodeDefinition.test.ts index c149c7a..ea41df0 100644 --- a/packages/core/src/nodes/schema/INodeDefinition.test.ts +++ b/packages/core/src/nodes/schema/INodeDefinition.test.ts @@ -61,9 +61,6 @@ describe('TriggeredParams', () => { expectType>(true); expectType>('asdfasfd'); expectType>(false); - // expectType>(1.0); - // expectType>(1n); - // expectType>('asdfasfd'); expectType>>(['a']); expectType>>(['b']); diff --git a/packages/core/src/nodes/schema/testUtils.ts b/packages/core/src/nodes/schema/testUtils.ts index 89e55bc..5469df4 100644 --- a/packages/core/src/nodes/schema/testUtils.ts +++ b/packages/core/src/nodes/schema/testUtils.ts @@ -1,54 +1,40 @@ +import { IFlowNode, TriggeredParams } from './FlowNodes'; +import { FlowSocketNames, Sockets, ValueSockets, ValueTypeNameMapping } from './Sockets'; + /** * Assert parameter is of a specific type. * * @param value - Value that should be identical to type `T`. */ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore - -import { collapseTextChangeRangesAcrossMultipleVersions } from 'typescript'; -import { - ExtractValueType, - IFlowNode, - IHasSockets, - InputFlowSocketNames, - InputValueSockets, - InputValueType, - NodeInputValues, - OutputFlowSocketNames, - OutputFlowSockets, - OutputValueSocketNames, - TriggeredParams, -} from './INodeDefinition'; - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export function expectType(value: T): void { - // eslint-disable-next-line @typescript-eslint/no-empty-function -} +export function expectType(value: T): void {} -type RecordedOutputWrite = +type RecordedOutputWrite = | { writeType: 'flow'; - socketName: OutputFlowSocketNames; + socketName: FlowSocketNames; } | { writeType: 'value'; - socketName: OutputValueSocketNames; + socketName: keyof ValueSockets; value: any; }; -export type RecordedOutputWrites = RecordedOutputWrite[]; +type NodeInputValues = { + [K in keyof TSockets]?: ValueTypeNameMapping; +}; + +export type RecordedOutputWrites = RecordedOutputWrite[]; -export const buildStubEngineForFlowNode = ( - flowNodeDefinition: IFlowNode +export const buildStubEngineForFlowNode = ( + flowNodeDefinition: IFlowNode ) => { - const outputWrites: RecordedOutputWrites = []; + const outputWrites: RecordedOutputWrites = []; const getOutputWrites = () => outputWrites; - let inputValuesState: NodeInputValues = {}; + let inputValuesState: NodeInputValues> = {}; - const triggeredParams: Omit, 'state' | 'triggeringSocketName'> = { + const triggeredParams: Omit, 'state' | 'triggeringSocketName'> = { commit: (param) => { outputWrites.push({ writeType: 'flow', @@ -56,11 +42,13 @@ export const buildStubEngineForFlowNode = }); }, readInput: (param) => { + // @ts-ignore return inputValuesState[param]; }, writeOutput: (param, value) => { outputWrites.push({ writeType: 'value', + // @ts-ignore socketName: param, value, }); @@ -69,7 +57,7 @@ export const buildStubEngineForFlowNode = let nodeState = flowNodeDefinition.initialState(); - const trigger = (triggeringSocketName: InputFlowSocketNames) => { + const trigger = (triggeringSocketName: FlowSocketNames) => { // trigger node and update the state with the triggered result. nodeState = flowNodeDefinition.triggered({ ...triggeredParams, @@ -78,7 +66,11 @@ export const buildStubEngineForFlowNode = }); }; - const writeInput = >(param: J, value: InputValueType) => { + const writeInput = , J extends keyof TValueSockets>( + param: J, + value: ValueTypeNameMapping + ) => { + // @ts-ignore inputValuesState[param] = value; }; From fe161b94fd2d4c3b6ed6d9b71d9429719955081e Mon Sep 17 00:00:00 2001 From: Dan Oved Date: Mon, 28 Nov 2022 20:28:02 -0800 Subject: [PATCH 15/15] allow trigger to not return anything --- packages/core/src/nodes/flow/Branch.ts | 1 - packages/core/src/nodes/schema/FlowNodes.ts | 12 ++++++++---- packages/core/src/nodes/schema/testUtils.ts | 6 +++++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/core/src/nodes/flow/Branch.ts b/packages/core/src/nodes/flow/Branch.ts index 6654d5c..21b9a5a 100644 --- a/packages/core/src/nodes/flow/Branch.ts +++ b/packages/core/src/nodes/flow/Branch.ts @@ -20,7 +20,6 @@ const Branch = makeFlowNodeDefinition({ triggered: ({ commit, readInput }) => { const value = readInput('condition'); commit(value ? 'true' : 'false'); - return undefined; }, initialState: () => undefined, }); diff --git a/packages/core/src/nodes/schema/FlowNodes.ts b/packages/core/src/nodes/schema/FlowNodes.ts index 6bbcefa..d6e61ad 100644 --- a/packages/core/src/nodes/schema/FlowNodes.ts +++ b/packages/core/src/nodes/schema/FlowNodes.ts @@ -37,9 +37,13 @@ export type TriggeredParams; }; -export type TriggeredFunction = ( - params: TriggeredParams -) => TNodeState; +export type TriggeredFunction< + TInput extends Sockets, + TOutput extends Sockets, + TNodeState +> = TNodeState extends undefined + ? (params: TriggeredParams) => void + : (params: TriggeredParams) => TNodeState; export interface IFlowNode extends IHasSockets { @@ -50,7 +54,7 @@ export interface IFlowNode(flowNode: IFlowNode) { return flowNode; } diff --git a/packages/core/src/nodes/schema/testUtils.ts b/packages/core/src/nodes/schema/testUtils.ts index 5469df4..3b9eec6 100644 --- a/packages/core/src/nodes/schema/testUtils.ts +++ b/packages/core/src/nodes/schema/testUtils.ts @@ -59,17 +59,21 @@ export const buildStubEngineForFlowNode = ) => { // trigger node and update the state with the triggered result. - nodeState = flowNodeDefinition.triggered({ + const result = flowNodeDefinition.triggered({ ...triggeredParams, state: nodeState, triggeringSocketName, }); + // if there is no node state, result will be undefined + // so then we know that we dont need to update the node state + if (typeof result !== 'undefined') nodeState = result; }; const writeInput = , J extends keyof TValueSockets>( param: J, value: ValueTypeNameMapping ) => { + // build fake write input fn that stores the write to an interval value store // @ts-ignore inputValuesState[param] = value; };