Add slugify string node
This commit is contained in:
@@ -31,6 +31,11 @@
|
|||||||
- Output: cleaned `STRING`
|
- Output: cleaned `STRING`
|
||||||
- Removes a trailing `_<digits>` iteration suffix before the file extension, for example `asset_003.png -> asset.png`.
|
- Removes a trailing `_<digits>` iteration suffix before the file extension, for example `asset_003.png -> asset.png`.
|
||||||
|
|
||||||
|
- `Dumas Slugify String`
|
||||||
|
- Input: `text`
|
||||||
|
- Output: slug `STRING`
|
||||||
|
- Converts text into a lowercase URL/file-safe slug, for example `Crème brûlée 2026 -> creme-brulee-2026`.
|
||||||
|
|
||||||
- `Dumas JSON Get Value`
|
- `Dumas JSON Get Value`
|
||||||
- Inputs: `json_object`, `path`
|
- Inputs: `json_object`, `path`
|
||||||
- Output: `JSON`
|
- Output: `JSON`
|
||||||
@@ -167,6 +172,8 @@ decr -> use index - 1
|
|||||||
|
|
||||||
`Dumas Strip Iteration Suffix` only strips a final numeric suffix. Names like `my_asset_final.png` are left untouched, while `my_asset_012.png` becomes `my_asset.png`.
|
`Dumas Strip Iteration Suffix` only strips a final numeric suffix. Names like `my_asset_final.png` are left untouched, while `my_asset_012.png` becomes `my_asset.png`.
|
||||||
|
|
||||||
|
`Dumas Slugify String` lowercases text, strips accents, replaces non-alphanumeric runs with `-`, and trims leading or trailing dashes.
|
||||||
|
|
||||||
## Roadmap
|
## 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.
|
This repo is intended to grow into a broader set of Dumas-branded generic utility nodes, including JSON helpers and adjacent data-manipulation tools.
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ from functools import lru_cache
|
|||||||
from itertools import islice
|
from itertools import islice
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
import unicodedata
|
||||||
|
|
||||||
|
|
||||||
def _clone_container(value):
|
def _clone_container(value):
|
||||||
@@ -259,6 +261,16 @@ def _strip_iteration_suffix(value):
|
|||||||
return f"{prefix}{extension}"
|
return f"{prefix}{extension}"
|
||||||
|
|
||||||
|
|
||||||
|
def _slugify_string(value):
|
||||||
|
if not isinstance(value, str):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
normalized = unicodedata.normalize("NFKD", value)
|
||||||
|
ascii_value = normalized.encode("ascii", "ignore").decode("ascii")
|
||||||
|
slug = re.sub(r"[^a-zA-Z0-9]+", "-", ascii_value.lower())
|
||||||
|
return slug.strip("-")
|
||||||
|
|
||||||
|
|
||||||
class DumasJSONStringToObjectNode:
|
class DumasJSONStringToObjectNode:
|
||||||
CATEGORY = "Dumas/JSON"
|
CATEGORY = "Dumas/JSON"
|
||||||
RETURN_TYPES = ("JSON",)
|
RETURN_TYPES = ("JSON",)
|
||||||
@@ -298,6 +310,23 @@ class DumasStripIterationSuffixNode:
|
|||||||
return (_strip_iteration_suffix(filename),)
|
return (_strip_iteration_suffix(filename),)
|
||||||
|
|
||||||
|
|
||||||
|
class DumasSlugifyStringNode:
|
||||||
|
CATEGORY = "Dumas/String"
|
||||||
|
RETURN_TYPES = ("STRING",)
|
||||||
|
FUNCTION = "slugify_string"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"text": ("STRING", {"default": "", "multiline": False}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def slugify_string(self, text):
|
||||||
|
return (_slugify_string(text),)
|
||||||
|
|
||||||
|
|
||||||
class DumasJSONObjectToStringNode:
|
class DumasJSONObjectToStringNode:
|
||||||
CATEGORY = "Dumas/JSON"
|
CATEGORY = "Dumas/JSON"
|
||||||
RETURN_TYPES = ("STRING",)
|
RETURN_TYPES = ("STRING",)
|
||||||
@@ -630,6 +659,7 @@ class DumasJSONUnflattenNode:
|
|||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"DumasJSONStringToObject": DumasJSONStringToObjectNode,
|
"DumasJSONStringToObject": DumasJSONStringToObjectNode,
|
||||||
"DumasStripIterationSuffix": DumasStripIterationSuffixNode,
|
"DumasStripIterationSuffix": DumasStripIterationSuffixNode,
|
||||||
|
"DumasSlugifyString": DumasSlugifyStringNode,
|
||||||
"DumasJSONObjectToString": DumasJSONObjectToStringNode,
|
"DumasJSONObjectToString": DumasJSONObjectToStringNode,
|
||||||
"DumasJSONGetValue": DumasJSONGetValueNode,
|
"DumasJSONGetValue": DumasJSONGetValueNode,
|
||||||
"DumasJSONSetValue": DumasJSONSetValueNode,
|
"DumasJSONSetValue": DumasJSONSetValueNode,
|
||||||
@@ -650,6 +680,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
"DumasJSONStringToObject": "Dumas JSON String to Object",
|
"DumasJSONStringToObject": "Dumas JSON String to Object",
|
||||||
"DumasStripIterationSuffix": "Dumas Strip Iteration Suffix",
|
"DumasStripIterationSuffix": "Dumas Strip Iteration Suffix",
|
||||||
|
"DumasSlugifyString": "Dumas Slugify String",
|
||||||
"DumasJSONObjectToString": "Dumas JSON Object to String",
|
"DumasJSONObjectToString": "Dumas JSON Object to String",
|
||||||
"DumasJSONGetValue": "Dumas JSON Get Value",
|
"DumasJSONGetValue": "Dumas JSON Get Value",
|
||||||
"DumasJSONSetValue": "Dumas JSON Set Value",
|
"DumasJSONSetValue": "Dumas JSON Set Value",
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from dumas_json_nodes import (
|
|||||||
DumasJSONObjectToStringNode,
|
DumasJSONObjectToStringNode,
|
||||||
DumasJSONStringToObjectNode,
|
DumasJSONStringToObjectNode,
|
||||||
DumasJSONSetValueNode,
|
DumasJSONSetValueNode,
|
||||||
|
DumasSlugifyStringNode,
|
||||||
DumasStripIterationSuffixNode,
|
DumasStripIterationSuffixNode,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -63,6 +64,20 @@ class DumasJSONNodeTests(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(result, ("my_asset_final.png",))
|
self.assertEqual(result, ("my_asset_final.png",))
|
||||||
|
|
||||||
|
def test_slugify_string_normalizes_text(self):
|
||||||
|
node = DumasSlugifyStringNode()
|
||||||
|
|
||||||
|
result = node.slugify_string("Hello, World! This is Dumas.")
|
||||||
|
|
||||||
|
self.assertEqual(result, ("hello-world-this-is-dumas",))
|
||||||
|
|
||||||
|
def test_slugify_string_strips_accents_and_repeated_symbols(self):
|
||||||
|
node = DumasSlugifyStringNode()
|
||||||
|
|
||||||
|
result = node.slugify_string("Crème brûlée___2026")
|
||||||
|
|
||||||
|
self.assertEqual(result, ("creme-brulee-2026",))
|
||||||
|
|
||||||
def test_get_value_reads_nested_paths(self):
|
def test_get_value_reads_nested_paths(self):
|
||||||
node = DumasJSONGetValueNode()
|
node = DumasJSONGetValueNode()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user