From 64d2acd892a8fd1be1d95e1ad049e37c49a95c87 Mon Sep 17 00:00:00 2001 From: Marco Christian Krenn Date: Thu, 7 Nov 2024 12:51:14 +0100 Subject: [PATCH] add replace item node (#506) --- .changeset/fast-crabs-work.md | 5 ++ .../graph-engine/src/nodes/array/index.ts | 2 + .../graph-engine/src/nodes/array/replace.ts | 59 +++++++++++++++++++ .../tests/suites/nodes/array/replace.test.ts | 58 ++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 .changeset/fast-crabs-work.md create mode 100644 packages/graph-engine/src/nodes/array/replace.ts create mode 100644 packages/graph-engine/tests/suites/nodes/array/replace.test.ts diff --git a/.changeset/fast-crabs-work.md b/.changeset/fast-crabs-work.md new file mode 100644 index 00000000..73de27fa --- /dev/null +++ b/.changeset/fast-crabs-work.md @@ -0,0 +1,5 @@ +--- +"@tokens-studio/graph-engine": minor +--- + +Add Replace Item node which lets you replace a specific item of an array. diff --git a/packages/graph-engine/src/nodes/array/index.ts b/packages/graph-engine/src/nodes/array/index.ts index d67e87e8..579d9ef0 100644 --- a/packages/graph-engine/src/nodes/array/index.ts +++ b/packages/graph-engine/src/nodes/array/index.ts @@ -7,6 +7,7 @@ import flatten from './flatten.js'; import indexArray from './indexArray.js'; import inject from './inject.js'; import push from './push.js'; +import replace from './replace.js'; import reverse from './reverse.js'; import slice from './slice.js'; import sort from './sort.js'; @@ -21,6 +22,7 @@ export const nodes = [ indexArray, inject, push, + replace, reverse, slice, sort diff --git a/packages/graph-engine/src/nodes/array/replace.ts b/packages/graph-engine/src/nodes/array/replace.ts new file mode 100644 index 00000000..528b593e --- /dev/null +++ b/packages/graph-engine/src/nodes/array/replace.ts @@ -0,0 +1,59 @@ +import { + AnyArraySchema, + AnySchema, + NumberSchema +} from '../../schemas/index.js'; +import { INodeDefinition, ToInput, ToOutput } from '../../index.js'; +import { Node } from '../../programmatic/node.js'; + +export default class NodeDefinition extends Node { + static title = 'Replace Item'; + static type = 'studio.tokens.array.replace'; + static description = 'Replaces an item in an array at a specified index.'; + + declare inputs: ToInput<{ + array: T[]; + item: T; + index: number; + }>; + + declare outputs: ToOutput<{ + array: T[]; + }>; + + constructor(props: INodeDefinition) { + super(props); + this.addInput('array', { + type: AnyArraySchema + }); + this.addInput('item', { + type: AnySchema + }); + this.addInput('index', { + type: NumberSchema + }); + this.addOutput('array', { + type: AnyArraySchema + }); + } + + execute(): void | Promise { + const { item, index, array } = this.getAllInputs(); + const arrayType = this.inputs.array.type; + this.inputs.item.setType(arrayType.items); + + // Create a copy of the array value + const result = [...array]; + + if (index >= 0 && index < result.length) { + result[index] = item; + } else if (index < 0 && Math.abs(index) <= result.length) { + // Handle negative indices by counting from the end + const actualIndex = result.length + index; + result[actualIndex] = item; + } + + // Set the output using the modified result and the original array type + this.outputs.array.set(result, arrayType); + } +} diff --git a/packages/graph-engine/tests/suites/nodes/array/replace.test.ts b/packages/graph-engine/tests/suites/nodes/array/replace.test.ts new file mode 100644 index 00000000..458e72b5 --- /dev/null +++ b/packages/graph-engine/tests/suites/nodes/array/replace.test.ts @@ -0,0 +1,58 @@ +import { Graph } from '../../../../src/graph/graph.js'; +import { describe, expect, test } from 'vitest'; +import Node from '../../../../src/nodes/array/replace.js'; + +describe('array/replace', () => { + test('replaces an item at a positive index', async () => { + const graph = new Graph(); + const node = new Node({ graph }); + + node.inputs.array.setValue([1, 2, 3]); + node.inputs.item.setValue(4); + node.inputs.index.setValue(1); + + await node.execute(); + + expect(node.outputs.array.value).to.eql([1, 4, 3]); + }); + + test('replaces an item at a negative index', async () => { + const graph = new Graph(); + const node = new Node({ graph }); + + node.inputs.array.setValue([1, 2, 3]); + node.inputs.item.setValue(4); + node.inputs.index.setValue(-2); + + await node.execute(); + + expect(node.outputs.array.value).to.eql([1, 4, 3]); + }); + + test('does not modify array when index is out of bounds', async () => { + const graph = new Graph(); + const node = new Node({ graph }); + + node.inputs.array.setValue([1, 2, 3]); + node.inputs.item.setValue(4); + node.inputs.index.setValue(5); + + await node.execute(); + + expect(node.outputs.array.value).to.eql([1, 2, 3]); + }); + + test('does not mutate the original array', async () => { + const graph = new Graph(); + const node = new Node({ graph }); + + const originalArray = [1, 2, 3]; + node.inputs.array.setValue(originalArray); + node.inputs.item.setValue(4); + node.inputs.index.setValue(1); + + await node.execute(); + + expect(originalArray).to.eql([1, 2, 3]); + }); +});