Skip to content

Commit

Permalink
add replace item node (#506)
Browse files Browse the repository at this point in the history
  • Loading branch information
mck authored Nov 7, 2024
1 parent abcf467 commit 64d2acd
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/fast-crabs-work.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tokens-studio/graph-engine": minor
---

Add Replace Item node which lets you replace a specific item of an array.
2 changes: 2 additions & 0 deletions packages/graph-engine/src/nodes/array/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -21,6 +22,7 @@ export const nodes = [
indexArray,
inject,
push,
replace,
reverse,
slice,
sort
Expand Down
59 changes: 59 additions & 0 deletions packages/graph-engine/src/nodes/array/replace.ts
Original file line number Diff line number Diff line change
@@ -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<T> 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<void> {
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);
}
}
58 changes: 58 additions & 0 deletions packages/graph-engine/tests/suites/nodes/array/replace.test.ts
Original file line number Diff line number Diff line change
@@ -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]);
});
});

0 comments on commit 64d2acd

Please sign in to comment.