diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md deleted file mode 100644 index ac78082..0000000 --- a/.planning/codebase/ARCHITECTURE.md +++ /dev/null @@ -1,168 +0,0 @@ -# Architecture - -**Analysis Date:** 2026-03-03 - -## Pattern Overview - -**Overall:** Node-based plugin architecture for ComfyUI - -**Key Characteristics:** -- Modular node design where each node implements ComfyUI's node interface -- Each node is a standalone class with INPUT_TYPES, RETURN_TYPES, and execution methods -- Nodes are registered in a central registry for ComfyUI framework discovery -- String processing operations implemented using Python's `re` module for regex patterns -- No external dependencies beyond Python standard library -- Plugin loaded via `__init__.py` which exports node mappings - -## Layers - -**Node Layer:** -- Purpose: Implements individual string manipulation operations -- Location: Root directory - `string_textbox_node.py`, `string_strip_node.py`, `string_multi_replace_node.py`, `string_preview_node.py`, `string_conditional_append_node.py`, `string_contains_any_node.py` -- Contains: Node classes inheriting ComfyUI's node interface -- Depends on: Python `re` module for regex operations -- Used by: ComfyUI framework (loads via NODE_CLASS_MAPPINGS) - -**Plugin Registry Layer:** -- Purpose: Provides node discovery and registration for ComfyUI -- Location: `__init__.py` -- Contains: NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS, WEB_DIRECTORY exports -- Depends on: All node modules -- Used by: ComfyUI framework at startup - -**Testing Layer:** -- Purpose: Unit tests for all node functionalities -- Location: `test_string_nodes.py` -- Contains: unittest.TestCase subclass with comprehensive test suites -- Depends on: All node classes -- Used by: Developers running tests locally - -## Data Flow - -**String Processing Pipeline:** - -1. Input received via `INPUT_TYPES` - user specifies string and processing parameters -2. ComfyUI calls node's FUNCTION method (e.g., `string_strip`, `string_replace`) -3. Processing method performs regex-based transformations -4. Optional cleanup via `cleanup_text()` if `remove_extra_spaces` is True -5. Return processed string(s) via RETURN_TYPES tuple - -**Example - StringStripNode flow:** -1. User provides `input_string` and `strings_to_remove` (multiline) -2. `string_strip()` method parses removal list, sorted by length (longest first) -3. Regex patterns compiled with case sensitivity flags -4. Patterns applied sequentially to input string -5. Cleanup normalizes whitespace if enabled -6. Result returned as single-element tuple - -**Example - StringConditionalAppendNode flow:** -1. User provides `input_string` and `strings_to_check` (multiline) -2. `conditional_append()` parses check list -3. Each string checked for presence in result (with case sensitivity option) -4. Missing strings appended at specified position (beginning/end) -5. Returns tuple of (modified_string, was_appended boolean) - -**State Management:** -- Stateless nodes - each execution independent -- No shared state between invocations -- Only state change: modifying the input string passed through - -## Key Abstractions - -**Node Interface Pattern:** -- Purpose: Standardizes how nodes interact with ComfyUI framework -- Examples: `StringTextboxNode` (`string_textbox_node.py`), `StringStripNode` (`string_strip_node.py`) -- Pattern: Each node class implements three key class attributes: - - `INPUT_TYPES()` classmethod - declares input parameters and their types - - `RETURN_TYPES` tuple - declares output types - - `FUNCTION` string - method name to call for execution - - Execution method - performs actual processing and returns tuple - -**Text Processing Pattern:** -- Purpose: Shared approach for string matching and replacement across nodes -- Examples: `string_strip_node.py`, `string_multi_replace_node.py` -- Pattern: Uses `re.compile()` with configurable flags (IGNORECASE), patterns include: - - Word boundary matching: `\b` for whole word matching - - Punctuation handling: conditional patterns with `(?:[,;:.])` for preservation/removal - - Regex escaping: `re.escape()` to treat user input as literals - -**Text Cleanup Pattern:** -- Purpose: Normalize whitespace after text modifications -- Examples: `cleanup_text()` method in `string_strip_node.py`, `string_multi_replace_node.py` -- Pattern: Two-step regex approach: - 1. Remove spaces before punctuation: `r'\s+([,;:.])'` → `r'\1'` - 2. Normalize multiple spaces: `r'\s{2,}'` → `' '` - 3. Strip leading/trailing whitespace - -**Multi-value Processing Pattern:** -- Purpose: Handle comma-separated or line-separated lists of values -- Examples: All nodes with multiline string inputs -- Pattern: `.splitlines()` to split input, `.strip()` to clean each line, filter empty strings - -## Entry Points - -**ComfyUI Framework Loading:** -- Location: `__init__.py` -- Triggers: ComfyUI startup/refresh -- Responsibilities: - - Imports all node classes - - Exports NODE_CLASS_MAPPINGS for framework discovery - - Exports NODE_DISPLAY_NAME_MAPPINGS for UI display names - - Exports WEB_DIRECTORY for any client-side assets - -**Individual Node Execution:** -- Location: Each node's FUNCTION method (e.g., `string_strip()` in `string_strip_node.py`) -- Triggers: ComfyUI workflow execution when node is evaluated -- Responsibilities: - - Accept parameters from INPUT_TYPES - - Perform string processing - - Return results as tuple matching RETURN_TYPES - -**Output Display:** -- Location: `string_preview_node.py` - StringPreviewNode -- Triggers: Workflow execution -- Responsibilities: - - Display string output in UI via `preview_string()` method - - Force re-evaluation on every execution via `IS_CHANGED()` returning NaN - - Return both UI display data and result tuple - -## Error Handling - -**Strategy:** Defensive programming - validate and handle edge cases gracefully - -**Patterns:** -- Empty input handling: All nodes check for empty strings and return sensible defaults - - Example: `string_contains_any_node.py` line 40-41 returns `(False, "")` for empty substrings - - Example: `string_conditional_append_node.py` line 44-45 returns unchanged input if no strings to check -- Line parsing robustness: `.strip()` applied to each line, whitespace-only lines filtered - - Example: `string_strip_node.py` line 36-38 skips empty/whitespace lines in removal list -- Regex compilation safety: `re.escape()` used to prevent regex injection from user input - - Example: `string_strip_node.py` line 55, 62 escape user strings before pattern compilation -- Delimiter handling: Split with `maxsplit=1` to allow delimiter characters in replacement text - - Example: `string_multi_replace_node.py` line 42 uses `split(delimiter, 1)` to preserve right side - -## Cross-Cutting Concerns - -**Logging:** Not implemented - ComfyUI framework handles logging - -**Validation:** -- User input validation occurs at parsing stage (splitlines, strip, filter empty) -- Type validation handled by ComfyUI framework via INPUT_TYPES/RETURN_TYPES declarations -- No explicit validation errors thrown; nodes handle edge cases gracefully - -**Authentication:** Not applicable - nodes are part of ComfyUI plugin - -**Case Sensitivity:** -- All text nodes support configurable case-sensitive matching via `match_case` boolean parameter -- Implemented via `re.IGNORECASE` flag when `match_case=False` -- Example: `string_strip_node.py` line 47 sets `flags = 0 if match_case else re.IGNORECASE` - -**Punctuation Handling:** -- Special feature introduced to preserve punctuation adjacent to matched text -- Controlled by `preserve_punctuation` boolean parameter -- Enabled by default in most nodes for safe prompt/syntax handling -- Example: `string_strip_node.py` lines 53-65 show pattern variants for punctuation preservation - ---- - -*Architecture analysis: 2026-03-03* diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md deleted file mode 100644 index 06ec53f..0000000 --- a/.planning/codebase/CONCERNS.md +++ /dev/null @@ -1,165 +0,0 @@ -# Codebase Concerns - -**Analysis Date:** 2026-03-03 - -## Code Duplication - -**Regex pattern compilation duplicated across node classes:** -- Issue: Both `StringStripNode` and `StringMultiReplaceNode` implement nearly identical regex pattern building logic for `match_whole_string` and `preserve_punctuation` combinations. -- Files: `string_strip_node.py` lines 52-72, `string_multi_replace_node.py` lines 59-75 -- Impact: If regex patterns need adjustment (e.g., for new punctuation marks), changes must be made in multiple places, increasing maintenance burden and risk of inconsistency. -- Fix approach: Extract shared regex pattern building logic into a utility module `string_utils.py` with a function like `build_replacement_pattern(search_str, match_whole_string, preserve_punctuation)` that both nodes can use. - -**Text cleanup logic duplicated:** -- Issue: `cleanup_text()` method is defined identically in both `StringStripNode` and `StringMultiReplaceNode`. -- Files: `string_strip_node.py` lines 27-30, `string_multi_replace_node.py` lines 29-32 -- Impact: Bug fixes to space normalization or punctuation handling require changes in two places. -- Fix approach: Move `cleanup_text()` to a shared utility module. - -## Input Validation Gaps - -**No validation of `replacement_delimiter` parameter:** -- Issue: `StringMultiReplaceNode.string_replace()` accepts any string as `replacement_delimiter`, including empty strings or strings not present in replacement_pairs. -- Files: `string_multi_replace_node.py` lines 34-80 -- Impact: Empty delimiter could cause silent failures or unexpected behavior. No error message guides users on correct format. -- Fix approach: Add validation to check if `replacement_delimiter` is non-empty and is actually present in at least one line of `replacement_pairs` when non-empty pairs are provided. Return error message if invalid. - -**No null/None input handling:** -- Issue: All nodes assume string inputs are valid. If ComfyUI passes `None` or unexpected types, nodes will crash with unhelpful error messages. -- Files: All node classes (e.g., `string_strip_node.py` line 32) -- Impact: Silent failures in ComfyUI workflows without clear error reporting. -- Fix approach: Add type checking and explicit error handling at method entry points. - -**Missing handling of extremely long strings:** -- Issue: Regex operations on very large strings (e.g., multi-megabyte text) could cause performance issues or regex complexity bombs. -- Files: All regex-based nodes (`string_strip_node.py`, `string_multi_replace_node.py`, `string_contains_any_node.py`) -- Impact: Workflows processing large text files could hang or crash unexpectedly. -- Fix approach: Add length checks and document maximum recommended input size. - -## Pattern Matching Edge Cases - -**Incomplete word boundary handling:** -- Issue: The `\b` word boundary in regex (lines 55, 62 in `string_strip_node.py`) doesn't work correctly at string boundaries with Unicode characters, accented characters, or special symbols. -- Files: `string_strip_node.py` lines 52-72, `string_multi_replace_node.py` lines 59-75 -- Impact: Matching whole words in non-English text or with special characters produces unexpected results. -- Fix approach: Document this limitation or switch to a more robust word boundary detection method that handles Unicode properly. - -**Regex special characters not escaped in `match_whole_string=False`:** -- Issue: In `preserve_punctuation=False` mode, the pattern `re.escape(search_str) + r'(?:[,;:.])?'` (line 72 in `string_multi_replace_node.py`) may not handle all edge cases where the search string itself contains pattern-matching characters. -- Files: `string_multi_replace_node.py` lines 70-72, `string_strip_node.py` lines 64-65 -- Impact: While `re.escape()` is used, the added `(?:[,;:.])?` pattern creates assumptions about which punctuation marks follow matches. Other punctuation or symbols would not be handled. -- Fix approach: Either document the supported punctuation list or provide an option to make punctuation removal more flexible. - -## Error Reporting - -**No error messages returned to user:** -- Issue: Invalid inputs (malformed replacement pairs, empty delimiters, etc.) fail silently or with generic Python exceptions. -- Files: All node classes -- Impact: Users get no feedback about what went wrong. Debugging workflows is difficult. -- Fix approach: Return structured error messages or use ComfyUI's error reporting mechanism. - -**Regex compilation errors not caught:** -- Issue: If a user's input accidentally creates an invalid regex pattern, the `re.compile()` call (lines 74 in `string_multi_replace_node.py`, line 67 in `string_strip_node.py`) will raise an exception that crashes the node without a helpful message. -- Files: `string_strip_node.py` line 67, `string_multi_replace_node.py` line 74 -- Impact: Even simple typos in user input cause workflow failures with unhelpful error messages. -- Fix approach: Wrap `re.compile()` in try-except block and return meaningful error message. - -## Performance Considerations - -**Regex patterns compiled multiple times per execution:** -- Issue: In `StringStripNode.string_strip()`, patterns are compiled in a loop (line 67) and compiled separately in a list for each method call. For large lists of removals, this is inefficient. -- Files: `string_strip_node.py` lines 50-71 -- Impact: Repeated calls with same removal patterns waste CPU cycles on recompilation. -- Fix approach: Consider memoizing compiled patterns if the same `strings_to_remove` is used repeatedly, or compile once and reuse within a single call. - -**Sorting by length every execution:** -- Issue: Strings are sorted by length on every method call (lines 44 in `string_strip_node.py`, line 52 in `string_multi_replace_node.py`). This is necessary for correctness but could be optimized with caching if patterns are reused. -- Files: `string_strip_node.py` line 44, `string_multi_replace_node.py` line 52 -- Impact: Minor performance impact for large replacement lists on repeated calls. -- Fix approach: Document the O(n log n) sorting behavior; consider caching if needed. - -## Testing Coverage Gaps - -**No tests for regex compilation failures:** -- What's not tested: Invalid regex patterns that would cause `re.compile()` to raise an exception. -- Files: `string_strip_node.py` line 67, `string_multi_replace_node.py` line 74, `test_string_nodes.py` -- Risk: Unexpected regex patterns from user input could crash the node without warning. -- Priority: Medium - -**No tests for Unicode or special character handling:** -- What's not tested: Input strings with emoji, accented characters, or multi-byte Unicode. -- Files: `test_string_nodes.py` -- Risk: Real-world prompts with special characters may behave unexpectedly. -- Priority: Medium - -**No tests for extreme input sizes:** -- What's not tested: Very long strings (megabytes), very long replacement lists, very long individual replacement pairs. -- Files: `test_string_nodes.py` -- Risk: Performance issues or stack overflow on large inputs would not be detected. -- Priority: Low - -**No tests for StringTextboxNode:** -- What's not tested: The `StringTextboxNode.pass_string()` method has zero test coverage. -- Files: `string_textbox_node.py`, `test_string_nodes.py` -- Risk: Changes to this node's behavior would go undetected. -- Priority: Low (simple pass-through, but should be covered) - -**No tests for StringPreviewNode:** -- What's not tested: The `StringPreviewNode.preview_string()` method and its special `IS_CHANGED()` behavior. -- Files: `string_preview_node.py`, `test_string_nodes.py` -- Risk: The `float("nan")` return value in `IS_CHANGED()` is unusual and not validated. -- Priority: Medium - -## Architecture Concerns - -**No base class for shared functionality:** -- Issue: Six independent node classes with duplicated methods and patterns indicate missing abstraction. -- Files: All `*_node.py` files -- Impact: Adding features (e.g., logging, input validation) requires changes to multiple files. -- Fix approach: Create a `BaseStringNode` class with shared validation, error handling, and utility methods. - -**Inconsistent parameter naming:** -- Issue: `StringStripNode` uses `strings_to_remove`, `StringMultiReplaceNode` uses `replacement_pairs`, etc. Inconsistent naming makes workflows harder to understand and API harder to learn. -- Files: All node classes -- Impact: Users must remember different parameter names for similar operations. -- Fix approach: Standardize parameter names across nodes or document the reasoning for differences. - -## Missing Features - -**No logging of transformations:** -- Issue: Nodes silently perform transformations with no audit trail or debug output. -- Files: All node classes -- Impact: Users cannot see what replacements were actually made or debug complex workflows. -- Fix approach: Add optional debug output or logging parameter. - -**No reuse of previous results:** -- Issue: Each node independently processes input; there's no way to chain results with visibility into intermediate states. -- Files: All output nodes -- Impact: Complex text processing requires many separate nodes instead of a single configurable pipeline. -- Fix approach: Consider a single "Text Processing Pipeline" node that chains multiple operations. - -## Potential Security Concerns - -**Regular expression denial of service (ReDoS) risk:** -- Issue: User-provided input in `strings_to_remove`, `replacement_pairs`, and `substrings` are used directly in regex patterns after `re.escape()`. While `re.escape()` prevents most ReDoS, deeply nested or pathological patterns could still cause issues. -- Files: `string_strip_node.py` lines 52-72, `string_multi_replace_node.py` lines 59-75, `string_contains_any_node.py` (simple substring search, low risk) -- Impact: Malicious or accidental input could cause CPU spike and freeze workflows. -- Fix approach: Add timeout to regex operations or limit complexity of patterns accepted. - -## Known Limitations - -**Word boundary matching fails with Unicode:** -- The `\b` anchor in regex patterns doesn't correctly identify word boundaries in non-ASCII text. -- Workaround: Test thoroughly with non-English text; consider providing separate "ASCII-only" and "Unicode-aware" modes. - -**Punctuation handling is opinionated:** -- The hardcoded punctuation list `[,;:.]` only handles common English punctuation. Other languages or contexts may use different marks. -- Workaround: Make punctuation marks configurable, or document the list and allow users to add custom nodes for other punctuation. - -**Case-insensitive matching doesn't handle Unicode case folding:** -- Python's `.lower()` method handles most Unicode, but some edge cases in Turkish, Greek, and other languages may not be handled optimally. -- Workaround: Document that case-insensitive matching is "best effort" for non-ASCII text. - ---- - -*Concerns audit: 2026-03-03* diff --git a/.planning/codebase/CONVENTIONS.md b/.planning/codebase/CONVENTIONS.md deleted file mode 100644 index 5e03d69..0000000 --- a/.planning/codebase/CONVENTIONS.md +++ /dev/null @@ -1,186 +0,0 @@ -# Coding Conventions - -**Analysis Date:** 2026-03-03 - -## Naming Patterns - -**Files:** -- Node files: `string__node.py` (e.g., `string_strip_node.py`, `string_multi_replace_node.py`) -- Test file: `test_.py` (e.g., `test_string_nodes.py`) -- Class names reflect file names in PascalCase (e.g., `StringStripNode` from `string_strip_node.py`) - -**Classes:** -- Node classes: `StringNode` format (e.g., `StringStripNode`, `StringMultiReplaceNode`, `StringConditionalAppendNode`) -- All node classes follow ComfyUI convention with specific class methods and attributes - -**Functions/Methods:** -- snake_case for method names (e.g., `string_strip`, `cleanup_text`, `conditional_append`, `contains_any`) -- Core execution method: `FUNCTION = ""` points to the main processing method -- Helper methods: lower case with underscores (e.g., `cleanup_text`) - -**Variables:** -- snake_case for local variables (e.g., `input_string`, `strings_to_remove`, `replacement_pairs`, `strings_list`) -- Boolean prefixes: `match_case`, `match_whole_string`, `preserve_punctuation`, `was_appended`, `was_any_appended` - -**Constants:** -- UPPERCASE for class constants (e.g., `RETURN_TYPES`, `RETURN_NAMES`, `FUNCTION`, `CATEGORY`, `INPUT_TYPES`, `OUTPUT_NODE`) - -## Code Style - -**Formatting:** -- No detected formatter configuration (.prettierrc, black config, etc.) -- Standard Python conventions: 4-space indentation -- Line length varies, no strict limit enforced -- Blank lines used to separate logical sections within methods - -**Linting:** -- No detected linting configuration (.pylintrc, .flake8, etc.) -- Code follows general PEP 8 style conventions -- Minimal deviation from standard Python conventions - -**Class Structure Pattern:** -All node classes follow a consistent structure: -```python -class StringNodeName: - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "parameter_name": ("TYPE", {"configuration": "dict"}) - } - } - - RETURN_TYPES = ("STRING",) # or ("BOOLEAN", "STRING") etc. - RETURN_NAMES = ("return_name",) - FUNCTION = "method_name" - CATEGORY = "utils/StringEssentials" - - def method_name(self, parameters): - # Implementation - return (result,) # Always return tuple -``` - -## Import Organization - -**Order:** -1. Standard library imports (`import unittest`, `import re`) -2. Class imports from local modules (e.g., `from string_strip_node import StringStripNode`) - -**Path Aliases:** -- No path aliases detected or used - -**Module Organization:** -- `__init__.py` at `/home/mark/Code/ComfyUI_StringEssentials/__init__.py` imports all node classes -- NODE_CLASS_MAPPINGS and NODE_DISPLAY_NAME_MAPPINGS provide ComfyUI registry -- All modules use relative imports in `__init__.py` - -## Error Handling - -**Patterns:** -- Input validation through conditional checks (if not line: continue) -- Empty input handling: return default empty/false values (e.g., `return (False, "")`) -- No explicit try-catch blocks; relies on Python built-ins for error prevention -- String operations wrapped in safe calls (e.g., `.strip()`, `.split()`) -- All methods handle empty strings and whitespace gracefully - -**Example from `string_contains_any_node.py`:** -```python -if not substrings_list: - return (False, "") - -# Prepare strings for comparison -search_string = input_string if match_case else input_string.lower() -``` - -## Logging - -**Framework:** Not detected - no logging module used in codebase - -**Console Output:** -- No console logging throughout production code -- Tests use unittest assertions for verification -- No debug output or print statements in production code - -## Comments - -**When to Comment:** -- Comments reference issue numbers for fixes (e.g., "# Issue #6 fix", "# Test Issue #6", "# Issue #8") -- Comments explain regex patterns and matching behavior (e.g., "Remove spaces before punctuation", "Normalize multiple spaces") -- Docstrings minimal; only used in `StringContainsAnyNode` with class-level docstring - -**JSDoc/TSDoc:** -- Not applicable - Python codebase without type hints -- Class methods have minimal/no docstrings - -## Function Design - -**Size:** -- Small to medium functions (methods range 10-50 lines) -- Core logic methods typically 30-50 lines: `string_strip`, `string_replace`, `conditional_append` -- Helper methods compact: `cleanup_text` is 3 lines - -**Parameters:** -- Input parameters correspond directly to INPUT_TYPES definitions -- Boolean flags for feature toggling common (e.g., `match_case`, `preserve_punctuation`) -- String inputs often use multiline format for flexibility - -**Return Values:** -- Always return tuples, matching RETURN_TYPES specification -- Single return: `(result,)` -- Multiple returns: `(result, boolean_flag)` -- Empty returns use falsy values: `(False, "")` or `(input_string, False)` - -## Module Design - -**Exports:** -- `__init__.py` at `/home/mark/Code/ComfyUI_StringEssentials/__init__.py` exports all node classes -- NODE_CLASS_MAPPINGS dict maps string names to classes for ComfyUI registration -- NODE_DISPLAY_NAME_MAPPINGS provides UI-friendly names - -**Barrel Files:** -- Yes, `__init__.py` acts as barrel file with explicit imports -- Each node class imported individually -- WEB_DIRECTORY constant exported for ComfyUI - -**Shared Utilities:** -- `cleanup_text()` method duplicated in both `StringStripNode` and `StringMultiReplaceNode` (not DRY, but isolated to context) -- No separate utils module; all logic encapsulated in node classes - -## Common Patterns - -**Regex Pattern Compilation:** -Patterns compiled once in a loop for performance: -```python -# From string_strip_node.py and string_multi_replace_node.py -patterns = [] -for _, string_to_remove in removals: - # Build pattern - pattern = ... - patterns.append(re.compile(pattern, flags=flags)) - -# Apply all patterns -for pattern in patterns: - result = pattern.sub('', result) -``` - -**String Parsing (Multiline Input):** -Common pattern for parsing user input: -```python -strings_list = [] -for line in strings_to_remove.splitlines(): - line = line.strip() - if not line: - continue - strings_list.append(line) -``` - -**Case Sensitivity Handling:** -Consistent approach across nodes: -```python -flags = 0 if match_case else re.IGNORECASE -regex = re.compile(pattern, flags=flags) -``` - ---- - -*Convention analysis: 2026-03-03* diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md deleted file mode 100644 index 968347d..0000000 --- a/.planning/codebase/INTEGRATIONS.md +++ /dev/null @@ -1,81 +0,0 @@ -# External Integrations - -**Analysis Date:** 2026-03-03 - -## APIs & External Services - -**LLM Integration:** -- Compatible with outputs from Ollama, Claude.ai, OpenAI ChatGPT -- No direct SDK/client integration - processes text output from LLM services -- Purpose: Clean and transform LLM-generated prompts and descriptions - -## Data Storage - -**Databases:** -- Not applicable - Nodes process in-memory strings only, no persistent storage - -**File Storage:** -- Local filesystem only - Custom node installed in ComfyUI custom_nodes directory -- No external file storage integrations - -**Caching:** -- None - All operations are stateless transformations - -## Authentication & Identity - -**Auth Provider:** -- Not applicable - Standalone utility nodes with no authentication requirements -- Custom node registration managed by ComfyUI framework - -## Monitoring & Observability - -**Error Tracking:** -- None - Uses ComfyUI's native error handling and logging - -**Logs:** -- ComfyUI application logs -- No external log aggregation - -## CI/CD & Deployment - -**Hosting:** -- GitHub repository: https://github.com/bradsec/ComfyUI_StringEssentials -- ComfyUI Registry: Registered via ComfyUI package registry (PublisherId: bradsec) - -**CI Pipeline:** -- GitHub Actions workflow: `.github/workflows/publish.yml` -- Automated publishing to ComfyUI registry on release - -## Environment Configuration - -**Required env vars:** -- None - Zero environment variable dependencies - -**Secrets location:** -- Not applicable - No secrets or credentials used - -## Webhooks & Callbacks - -**Incoming:** -- None - -**Outgoing:** -- None - -## Frontend Integration - -**ComfyUI Web Interface:** -- JavaScript extensions in `js/string_essentials.js` -- Custom node widget initialization via ComfyUI's extension API -- Widget API: `ComfyWidgets` for STRING input display -- App API: `app.registerExtension()` for node lifecycle hooks - -**Node Widget Configuration:** -- Multiline text inputs for string configuration -- Boolean toggles for matching options (case-sensitive, whole word, etc.) -- Dropdown selections for position (beginning/end) -- Custom separators configurable via STRING inputs - ---- - -*Integration audit: 2026-03-03* diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md deleted file mode 100644 index fac78b6..0000000 --- a/.planning/codebase/STACK.md +++ /dev/null @@ -1,79 +0,0 @@ -# Technology Stack - -**Analysis Date:** 2026-03-03 - -## Languages - -**Primary:** -- Python 3.x - Core node implementation and string manipulation logic -- JavaScript - Frontend UI extensions and ComfyUI widget integration - -## Runtime - -**Environment:** -- ComfyUI - Custom node framework for AI image generation workflows - -**Package Manager:** -- pip - Python dependency management -- No Python dependencies or external modules required (pure Python implementation) - -## Frameworks - -**Core:** -- ComfyUI Custom Nodes Framework - Node registration and execution - - Uses `NODE_CLASS_MAPPINGS` and `NODE_DISPLAY_NAME_MAPPINGS` for node registration - - Located: `__init__.py` - -**Testing:** -- unittest - Python standard library testing framework -- Config: No external test configuration file (uses unittest defaults) -- Test file: `test_string_nodes.py` - -**Build/Dev:** -- No formal build system required -- Direct Python module installation into ComfyUI custom_nodes directory - -## Key Dependencies - -**Critical:** -- None - This is a zero-dependency ComfyUI custom node package -- All functionality implemented using Python standard library only (re module for regex) - -**Infrastructure:** -- None - Standalone custom node implementation - -## Configuration - -**Environment:** -- No environment variables required -- No configuration files needed -- Simple cloning into ComfyUI custom_nodes directory - -**Build:** -- `pyproject.toml` - Package metadata and ComfyUI registry information - - Version: 2.0.7 - - Publisher: bradsec (ComfyUI Registry identifier) - - License: Included in LICENSE file - -## Platform Requirements - -**Development:** -- Python 3.x -- ComfyUI installation (as parent application) -- Git for repository cloning - -**Production:** -- ComfyUI application -- Python 3.x runtime -- Custom node installed in `custom_nodes/ComfyUI_StringEssentials/` directory - -## Platform Support - -**Deployment Target:** -- ComfyUI custom nodes directory -- Cross-platform (Windows, macOS, Linux) -- Web-based ComfyUI interface with JavaScript frontend integration - ---- - -*Stack analysis: 2026-03-03* diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md deleted file mode 100644 index e94cb0c..0000000 --- a/.planning/codebase/STRUCTURE.md +++ /dev/null @@ -1,207 +0,0 @@ -# Codebase Structure - -**Analysis Date:** 2026-03-03 - -## Directory Layout - -``` -ComfyUI_StringEssentials/ -├── __init__.py # Node registry and exports -├── pyproject.toml # Project metadata and configuration -├── README.md # Documentation -├── LICENSE # License file -├── string_textbox_node.py # String Textbox node -├── string_strip_node.py # String Strip node -├── string_multi_replace_node.py # String Multi Replace node -├── string_preview_node.py # String Preview node -├── string_conditional_append_node.py # String Conditional Append node -├── string_contains_any_node.py # String Contains Any node -├── test_string_nodes.py # Unit tests -├── .planning/ # Planning and analysis docs (not committed) -│ └── codebase/ # Architecture documentation -├── .pytest_cache/ # Pytest cache (gitignored) -├── js/ # Client-side assets (currently empty) -└── images/ # Documentation images -``` - -## Directory Purposes - -**Root Directory:** -- Purpose: Contains all Python node implementations and project config -- Contains: Node classes, tests, project metadata -- Key files: All `*_node.py` files, `__init__.py`, `pyproject.toml`, `test_string_nodes.py` - -**js/ Directory:** -- Purpose: Placeholder for client-side JavaScript/web assets -- Contains: Currently empty, referenced in `__init__.py` WEB_DIRECTORY -- Committed: Yes (directory exists, may have assets) - -**images/ Directory:** -- Purpose: Documentation images for README -- Contains: PNG screenshots of node interfaces and example workflows -- Committed: Yes - -**.planning/codebase/ Directory:** -- Purpose: Architecture and analysis documentation generated by GSD tools -- Contains: ARCHITECTURE.md, STRUCTURE.md, CONVENTIONS.md, TESTING.md, etc. -- Committed: No (git ignored) - -**.pytest_cache/ Directory:** -- Purpose: Pytest runtime cache -- Contains: Test execution metadata -- Committed: No (git ignored) - -## Key File Locations - -**Entry Points:** -- `__init__.py`: Module initialization - imports nodes and exports NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS, WEB_DIRECTORY - -**Node Implementations:** -- `string_textbox_node.py`: StringTextboxNode - simple text input passthrough (5 lines of logic) -- `string_strip_node.py`: StringStripNode - removes specified strings with regex patterns -- `string_multi_replace_node.py`: StringMultiReplaceNode - replaces text using delimiter-separated pairs -- `string_preview_node.py`: StringPreviewNode - displays string output in ComfyUI UI -- `string_conditional_append_node.py`: StringConditionalAppendNode - appends text only if not present -- `string_contains_any_node.py`: StringContainsAnyNode - checks if any of multiple substrings exist - -**Configuration:** -- `pyproject.toml`: Project metadata including name, version (2.0.7), description, repository URL - -**Testing:** -- `test_string_nodes.py`: 62 unit tests covering all node functionalities - -**Documentation:** -- `README.md`: User-facing documentation with node descriptions and usage examples - -## Naming Conventions - -**Files:** -- Node files: `string__node.py` format - - Examples: `string_strip_node.py`, `string_multi_replace_node.py` - - Pattern: snake_case with `_node.py` suffix - -**Classes:** -- Node classes: PascalCase with "Node" suffix - - Examples: `StringTextboxNode`, `StringStripNode`, `StringMultiReplaceNode` - - Pattern: Convert filename from snake_case to PascalCase, append "Node" - -**Methods:** -- Execution methods: verb_noun_v1 format (snake_case) - - Examples: `string_strip()`, `string_replace()`, `conditional_append()`, `contains_any()`, `pass_string()`, `preview_string()` - - Pattern: Descriptive snake_case names indicating operation - -**Variables:** -- Instance variables: snake_case with descriptive names - - Examples: `input_string`, `strings_to_remove`, `match_case`, `preserve_punctuation` - - Pattern: Clear names indicating type and purpose - -**Constants:** -- Node metadata: UPPERCASE - - Examples: `RETURN_TYPES`, `RETURN_NAMES`, `FUNCTION`, `CATEGORY`, `INPUT_TYPES`, `OUTPUT_NODE` - - Pattern: ComfyUI convention for node interface - -## Where to Add New Code - -**New String Operation Node:** -1. Create file: `string__node.py` in root directory -2. Class structure (follow pattern from existing nodes): - - Define `INPUT_TYPES()` classmethod with parameter definitions - - Define `RETURN_TYPES` tuple with output types - - Define `RETURN_NAMES` tuple with output names - - Set `FUNCTION = ""` - - Set `CATEGORY = "utils/StringEssentials"` - - Implement execution method with logic -3. Add to `__init__.py`: - - Import the new class at top - - Add entry to `NODE_CLASS_MAPPINGS` dict (key = class name as string) - - Add entry to `NODE_DISPLAY_NAME_MAPPINGS` dict (key = class name, value = display name) -4. Add tests to `test_string_nodes.py`: - - Create test class or add methods to `TestStringNodes` - - Test basic functionality, edge cases, parameter variations - -**Example node implementation pattern from `string_strip_node.py`:** -```python -import re - -class StringStripNode: - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "input_string": ("STRING", {...}), - "strings_to_remove": ("STRING", {...}), - "match_case": ("BOOLEAN", {...}), - # ... more parameters - } - } - - RETURN_TYPES = ("STRING",) - RETURN_NAMES = ("modified_string",) - FUNCTION = "string_strip" - CATEGORY = "utils/StringEssentials" - - def cleanup_text(self, text): - # Helper method for text normalization - pass - - def string_strip(self, input_string, strings_to_remove, ...): - # Parse input (splitlines, strip, filter empty) - # Compile regex patterns - # Apply patterns - # Cleanup if needed - return (result,) -``` - -**Utilities/Helpers:** -- Shared helper methods: Add to individual node class if only used there -- Common patterns: Currently duplicated in `cleanup_text()` across nodes (consider extraction if adding more nodes) -- Location: Keep at root level - no separate utils directory used - -**Tests:** -- Add test methods to `TestStringNodes` class in `test_string_nodes.py` -- Follow naming: `test__` (e.g., `test_strip_basic_functionality`) -- Setup: Use `self.setUp()` to instantiate node classes -- Pattern: Call node method directly with test parameters, assert expected results - -## Special Directories - -**js/ Directory:** -- Purpose: ComfyUI web assets (referenced in WEB_DIRECTORY in `__init__.py`) -- Generated: No -- Committed: Yes (directory exists, may be empty or contain future web assets) -- Note: Currently unused but available for client-side node customization - -**images/ Directory:** -- Purpose: Screenshots and diagrams for documentation -- Generated: No (manually created/updated) -- Committed: Yes -- Files: PNG images referenced in README.md - -**.planning/codebase/ Directory:** -- Purpose: GSD (Get Shit Done) architecture analysis documents -- Generated: Yes (by GSD tools) -- Committed: No (git ignored) -- Contains: ARCHITECTURE.md, STRUCTURE.md, CONVENTIONS.md, TESTING.md, CONCERNS.md - -**.pytest_cache/ Directory:** -- Purpose: Pytest internal cache for test discovery and execution -- Generated: Yes (auto-created by pytest) -- Committed: No (git ignored) - -## File Organization Rationale - -**Flat root structure for nodes:** Each node is a separate file at root level -- Rationale: Simple discovery by ComfyUI, clear 1:1 mapping between file and node class -- Alternative avoided: Subdirectory organization (would complicate imports in `__init__.py`) - -**Single test file:** All tests in `test_string_nodes.py` -- Rationale: Small codebase, all nodes similar in nature, easy to run all tests together -- Scalability: If adding more nodes, consider splitting tests by node when >100 test methods - -**Shared patterns duplicated:** `cleanup_text()` method exists in both `string_strip_node.py` and `string_multi_replace_node.py` -- Current state: Intentionally duplicated to keep each node self-contained -- Future improvement: Extract to shared module if >3 nodes need it - ---- - -*Structure analysis: 2026-03-03* diff --git a/.planning/codebase/TESTING.md b/.planning/codebase/TESTING.md deleted file mode 100644 index 369c611..0000000 --- a/.planning/codebase/TESTING.md +++ /dev/null @@ -1,251 +0,0 @@ -# Testing Patterns - -**Analysis Date:** 2026-03-03 - -## Test Framework - -**Runner:** -- unittest (Python standard library) -- Config: None (uses default unittest discovery) -- No pytest.ini, setup.cfg, or tox.ini configuration detected - -**Assertion Library:** -- unittest.TestCase assertions (built-in) - -**Run Commands:** -```bash -python -m unittest test_string_nodes.py # Run all tests -python -m unittest test_string_nodes.TestStringNodes # Run specific test class -python -m unittest test_string_nodes.TestStringNodes.test_ # Run specific test -``` - -**Test File Location:** -- `test_string_nodes.py` in project root alongside source files (`/home/mark/Code/ComfyUI_StringEssentials/test_string_nodes.py`) -- Co-located with source code (not in separate tests directory) - -## Test File Organization - -**Location:** -- Co-located pattern: test file in same directory as source modules - -**Naming:** -- Test file: `test_string_nodes.py` -- Test class: `TestStringNodes` (PascalCase with Test prefix) -- Test methods: `test_` format - -**Structure:** -``` -test_string_nodes.py -├── TestStringNodes (class) -│ ├── setUp() - Initialize node instances -│ ├── test_strip_* - Tests for StringStripNode -│ ├── test_replace_* - Tests for StringMultiReplaceNode -│ ├── test_append_* - Tests for StringConditionalAppendNode -│ └── test_contains_any_* - Tests for StringContainsAnyNode -└── if __name__ == '__main__': unittest.main() -``` - -## Test Structure - -**Suite Organization:** -```python -class TestStringNodes(unittest.TestCase): - def setUp(self): - self.strip_node = StringStripNode() - self.replace_node = StringMultiReplaceNode() - self.append_node = StringConditionalAppendNode() - self.contains_any_node = StringContainsAnyNode() -``` - -**Patterns:** -- **Setup pattern:** `setUp()` method instantiates all node instances as instance variables for reuse across test methods -- **No teardown:** No `tearDown()` method (no cleanup needed) -- **Assertion pattern:** Direct method calls on node instances with parameter unpacking: - ```python - result = self.strip_node.string_strip( - input_string=input_string, - strings_to_remove=strings_to_remove, - match_case=False, - match_whole_string=True, - preserve_punctuation=True, - remove_extra_spaces=True - )[0] - self.assertEqual(result, expected_output) - ``` - -**Test Method Characteristics:** -- Each test is independent and focused on a single behavior -- Tests use explicit parameter names (keyword arguments) for clarity -- Return value tuple unpacking: `[0]` for single return, tuple unpacking for multiple returns -- Clear arrange-act-assert flow (input setup → method call → assertion) - -## Test Coverage by Node - -**StringStripNode Tests:** -- `test_strip_basic_functionality`: Single string removal -- `test_strip_multiple_strings`: Multiple removal patterns (multiline input) -- `test_strip_case_sensitivity`: Case-insensitive vs case-sensitive modes -- `test_strip_punctuation_preserved`: Punctuation preservation (Issue #6) -- `test_strip_punctuation_removed`: Legacy punctuation removal behavior -- Extra spaces handling covered in `test_extra_spaces_handling` - -**StringMultiReplaceNode Tests:** -- `test_replace_basic_functionality`: Single replacement pair -- `test_replace_multiple_pairs`: Multiple replacement pairs from multiline input -- `test_replace_case_sensitivity`: Case-insensitive vs case-sensitive modes -- `test_replace_custom_delimiter`: Custom delimiter support (not just `::` -- `test_replace_punctuation_preserved`: Punctuation preservation (Issue #6) -- `test_replace_prompt_syntax_preserved`: Bracket syntax preservation (e.g., `[word1:word2:.5]`) -- `test_replace_with_space`: Trailing space preservation in replacements (Issue #8) -- `test_replace_with_leading_space`: Leading space in replacement strings (Issue #8) -- `test_replace_with_whitespace_only`: Multiple spaces in replacements (Issue #8) -- `test_replace_with_tab`: Tab character in replacements (Issue #8) - -**StringConditionalAppendNode Tests:** -- `test_append_string_not_found`: Appending when string not present -- `test_append_string_found`: No append when string already present -- `test_append_beginning`: Position flag "beginning" vs "end" -- `test_append_case_insensitive`: Case-insensitive search -- `test_append_case_sensitive`: Case-sensitive search -- `test_append_custom_separator`: Custom separator handling -- `test_append_no_separator`: Empty string separator -- `test_append_multiple_strings`: Multiple check strings with mixed found/not found -- `test_append_multiple_all_found`: All strings already present (no append) - -**StringContainsAnyNode Tests:** -- `test_contains_any_found`: Basic found case -- `test_contains_any_not_found`: Basic not found case -- `test_contains_any_multiple_first_match`: Returns first match from multiple options -- `test_contains_any_case_insensitive`: Default case-insensitive behavior -- `test_contains_any_case_sensitive`: Case-sensitive search -- `test_contains_any_case_sensitive_found`: Case-sensitive with matching case -- `test_contains_any_empty_input`: Empty input string handling -- `test_contains_any_empty_substrings`: Empty substrings input -- `test_contains_any_whitespace_substrings`: Whitespace-only lines are ignored -- `test_contains_any_partial_match`: Substring matching (anime matches animation) - -## Mocking - -**Framework:** None - unittest provides basic mocking but not used in this codebase - -**Patterns:** -- No mock objects used -- No external dependencies mocked -- Tests use real node instances with direct method calls -- All test data is embedded in test methods (no external fixtures) - -**What to Mock:** -- No mocking required; all node classes are stateless and dependency-free - -**What NOT to Mock:** -- Don't mock the node classes - test them directly with real instances - -## Fixtures and Factories - -**Test Data:** -- All test data embedded directly in test methods -- No separate fixture files or factory classes -- Input strings created inline: - ```python - input_string = "This is a test string with test word" - strings_to_remove = "test" - ``` - -**Location:** -- Test data is co-located with test methods (no separate fixtures directory) -- Issue-specific test data clearly labeled with issue references: - ```python - def test_strip_punctuation_preserved(self): - # Test Issue #6 fix: punctuation should be preserved - input_string = "Let's meet, Grandma!" - ``` - -## Coverage - -**Requirements:** None enforced (no coverage configuration detected) - -**View Coverage:** -```bash -# Using unittest's built-in capabilities (limited): -python -m unittest discover -v - -# Better coverage with coverage.py (not currently installed): -pip install coverage -coverage run -m unittest test_string_nodes.py -coverage report -``` - -**Observed Coverage:** -- **StringStripNode:** 100% - All major code paths tested (basic, multiple, case sensitivity, punctuation handling, spaces) -- **StringMultiReplaceNode:** 100% - All code paths tested (basic, multiple, case sensitivity, custom delimiter, punctuation, whitespace preservation) -- **StringConditionalAppendNode:** 100% - All code paths tested (found/not found, position, case sensitivity, separator options, multiple strings) -- **StringContainsAnyNode:** 100% - All code paths tested (found/not found, case sensitivity, empty inputs, whitespace handling, partial matching) -- **StringPreviewNode:** 0% - No tests (trivial pass-through logic) -- **StringTextboxNode:** 0% - No tests (trivial pass-through logic) - -## Test Types - -**Unit Tests:** -- Scope: Individual node class methods -- Approach: Direct method invocation with arranged inputs, assert on single output -- Example: `test_strip_basic_functionality` tests `string_strip()` method with specific parameters -- No test doubles or stubs - real objects used - -**Integration Tests:** -- Not present in codebase (no multi-component interaction testing) - -**E2E Tests:** -- Not present (ComfyUI-specific E2E would require full ComfyUI runtime) - -**Issue-Driven Tests:** -- Tests explicitly tied to GitHub issues in comments -- Issue #6: Punctuation preservation tests -- Issue #8: Whitespace preservation in replacements tests -- Issue #9: StringContainsAnyNode feature tests -- Pattern: When fixing a bug, issue number added as comment and test created to verify fix - -## Common Patterns - -**Async Testing:** -- Not applicable - Python standard library code without async/await - -**Error Testing:** -- No explicit error/exception testing -- Edge cases tested: empty strings, whitespace-only input, multiple spaces -- Validation through return values rather than exception handling - -**Testing Multiline Input:** -```python -strings_to_remove = """test -More Text""" -result = self.strip_node.string_strip( - input_string=input_string, - strings_to_remove=strings_to_remove, - match_case=False, - match_whole_string=True, - preserve_punctuation=True, - remove_extra_spaces=True -)[0] -``` - -**Testing Multiple Parameters:** -```python -result, was_appended = self.append_node.conditional_append( - input_string=input_string, - strings_to_check=strings_to_check, - position="end", - match_case=False, - separator=", " -) -self.assertEqual(result, expected_string) -self.assertTrue(was_appended) -``` - -**Testing Boolean Returns:** -- StringConditionalAppendNode returns `(string, boolean)` tuple -- StringContainsAnyNode returns `(boolean, string)` tuple -- Tests unpack both return values and assert on each - ---- - -*Testing analysis: 2026-03-03*