From 6994cb64c56bff440e235a3823f508f396b83e57 Mon Sep 17 00:00:00 2001 From: Chris Dumas Date: Tue, 21 Jul 2026 10:51:20 +0000 Subject: [PATCH] Add Dumas JSON array iterator node --- README.md | 13 +++++++++++ dumas_json_nodes.py | 42 ++++++++++++++++++++++++++++++++++ tests/test_dumas_json_nodes.py | 36 +++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/README.md b/README.md index 3475ff0..c82bd61 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,11 @@ - Output: `INT` - Returns the length of a JSON array. +- `Dumas JSON Array Iterator` + - Inputs: `json_input`, `index`, `mode` + - Outputs: `item`, `current_index`, `total_items` + - Returns the current array item and position, with `mode` set to `fixed`, `incr`, or `decr`. + All nodes live in the `Dumas/JSON` category. ## Installation @@ -77,6 +82,14 @@ settings.render.width {"enabled": true, "retries": 3} ``` +`Dumas JSON Array Iterator` clamps to valid bounds: + +```text +fixed -> use index as-is +incr -> use index + 1 +decr -> use index - 1 +``` + ## Roadmap This repo is intended to grow into a broader set of Dumas-branded generic utility nodes, including JSON helpers and adjacent data-manipulation tools. diff --git a/dumas_json_nodes.py b/dumas_json_nodes.py index 1f17bd6..044e7c1 100644 --- a/dumas_json_nodes.py +++ b/dumas_json_nodes.py @@ -86,6 +86,18 @@ def _merge_json_objects(base_object, overlay_object): return merged +def _resolve_iteration_index(index, mode, total_items): + if total_items <= 0: + return -1 + + if mode == "incr": + index += 1 + elif mode == "decr": + index -= 1 + + return max(0, min(index, total_items - 1)) + + class DumasJSONStringToObjectNode: CATEGORY = "Dumas/JSON" RETURN_TYPES = ("JSON",) @@ -230,6 +242,34 @@ class DumasJSONArrayLengthNode: return (len(json_array),) +class DumasJSONArrayIteratorNode: + CATEGORY = "Dumas/JSON" + RETURN_TYPES = ("JSON", "INT", "INT") + RETURN_NAMES = ("item", "current_index", "total_items") + FUNCTION = "iterate" + + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "json_input": ("JSON",), + "index": ("INT", {"default": 0, "min": 0, "step": 1}), + "mode": (["fixed", "incr", "decr"], {"default": "fixed"}), + } + } + + def iterate(self, json_input, index, mode): + if not isinstance(json_input, list): + return (None, -1, 0) + + total_items = len(json_input) + if total_items == 0: + return (None, -1, 0) + + current_index = _resolve_iteration_index(index, mode, total_items) + return (json_input[current_index], current_index, total_items) + + NODE_CLASS_MAPPINGS = { "DumasJSONStringToObject": DumasJSONStringToObjectNode, "DumasJSONObjectToString": DumasJSONObjectToStringNode, @@ -238,6 +278,7 @@ NODE_CLASS_MAPPINGS = { "DumasJSONMergeObjects": DumasJSONMergeObjectsNode, "DumasJSONKeys": DumasJSONKeysNode, "DumasJSONArrayLength": DumasJSONArrayLengthNode, + "DumasJSONArrayIterator": DumasJSONArrayIteratorNode, } NODE_DISPLAY_NAME_MAPPINGS = { @@ -248,4 +289,5 @@ NODE_DISPLAY_NAME_MAPPINGS = { "DumasJSONMergeObjects": "Dumas JSON Merge Objects", "DumasJSONKeys": "Dumas JSON Keys", "DumasJSONArrayLength": "Dumas JSON Array Length", + "DumasJSONArrayIterator": "Dumas JSON Array Iterator", } diff --git a/tests/test_dumas_json_nodes.py b/tests/test_dumas_json_nodes.py index 02e0190..c55c61a 100644 --- a/tests/test_dumas_json_nodes.py +++ b/tests/test_dumas_json_nodes.py @@ -2,6 +2,7 @@ import unittest from dumas_json_nodes import ( DumasJSONArrayLengthNode, + DumasJSONArrayIteratorNode, DumasJSONGetValueNode, DumasJSONKeysNode, DumasJSONMergeObjectsNode, @@ -73,6 +74,41 @@ class DumasJSONNodeTests(unittest.TestCase): self.assertEqual(result, (4,)) + def test_array_iterator_fixed_mode_uses_given_index(self): + node = DumasJSONArrayIteratorNode() + + result = node.iterate(["a", "b", "c"], 1, "fixed") + + self.assertEqual(result, ("b", 1, 3)) + + def test_array_iterator_incr_mode_advances_index(self): + node = DumasJSONArrayIteratorNode() + + result = node.iterate(["a", "b", "c"], 1, "incr") + + self.assertEqual(result, ("c", 2, 3)) + + def test_array_iterator_decr_mode_decrements_index(self): + node = DumasJSONArrayIteratorNode() + + result = node.iterate(["a", "b", "c"], 1, "decr") + + self.assertEqual(result, ("a", 0, 3)) + + def test_array_iterator_clamps_out_of_range_index(self): + node = DumasJSONArrayIteratorNode() + + result = node.iterate(["a", "b", "c"], 99, "fixed") + + self.assertEqual(result, ("c", 2, 3)) + + def test_array_iterator_handles_empty_arrays(self): + node = DumasJSONArrayIteratorNode() + + result = node.iterate([], 0, "fixed") + + self.assertEqual(result, (None, -1, 0)) + if __name__ == "__main__": unittest.main()