From b0d4249ccd40f761a67f6a7fee05d4ca31c24c33 Mon Sep 17 00:00:00 2001 From: Michael Schmidt Date: Thu, 21 Mar 2024 14:51:28 +0100 Subject: [PATCH] Basic directory nodes (#2695) --- .../chaiNNer_standard/utility/__init__.py | 1 + .../utility/directory/directory_go_up.py | 37 +++++++++++++ .../utility/directory/directory_to_text.py | 27 ++++++++++ src/common/types/chainner-builtin.ts | 52 +++++++++++++++++++ src/common/types/chainner-scope.ts | 3 ++ 5 files changed, 120 insertions(+) create mode 100644 backend/src/packages/chaiNNer_standard/utility/directory/directory_go_up.py create mode 100644 backend/src/packages/chaiNNer_standard/utility/directory/directory_to_text.py diff --git a/backend/src/packages/chaiNNer_standard/utility/__init__.py b/backend/src/packages/chaiNNer_standard/utility/__init__.py index 6c1a850c17..3194c4c68e 100644 --- a/backend/src/packages/chaiNNer_standard/utility/__init__.py +++ b/backend/src/packages/chaiNNer_standard/utility/__init__.py @@ -6,3 +6,4 @@ text_group = utility_category.add_node_group("Text") color_group = utility_category.add_node_group("Color") random_group = utility_category.add_node_group("Random") +directory_group = utility_category.add_node_group("Directory") diff --git a/backend/src/packages/chaiNNer_standard/utility/directory/directory_go_up.py b/backend/src/packages/chaiNNer_standard/utility/directory/directory_go_up.py new file mode 100644 index 0000000000..561491d496 --- /dev/null +++ b/backend/src/packages/chaiNNer_standard/utility/directory/directory_go_up.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +from pathlib import Path + +from nodes.properties.inputs import DirectoryInput, NumberInput +from nodes.properties.outputs import DirectoryOutput + +from .. import directory_group + + +@directory_group.register( + schema_id="chainner:utility:back_directory", + name="Directory Go Up", + description="Traverse up from a directory the specified number of times.", + icon="BsFolder", + inputs=[ + DirectoryInput(must_exist=False, label_style="hidden"), + NumberInput("Times", minimum=0, default=1, label_style="inline").with_docs( + "How many times to go up.", + "- 0 will return the given directory as is.", + "- 1 will return the parent directory.", + "- 2 will return the grandparent directory.", + "- etc.", + hint=True, + ), + ], + outputs=[ + DirectoryOutput( + output_type="Directory { path: getParentDirectory(Input0.path, Input1) }", + ), + ], +) +def directory_go_up_node(directory: Path, amt: int) -> Path: + result = directory + for _ in range(amt): + result = result.parent + return result diff --git a/backend/src/packages/chaiNNer_standard/utility/directory/directory_to_text.py b/backend/src/packages/chaiNNer_standard/utility/directory/directory_to_text.py new file mode 100644 index 0000000000..2c5b074a8d --- /dev/null +++ b/backend/src/packages/chaiNNer_standard/utility/directory/directory_to_text.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +from pathlib import Path + +from nodes.properties.inputs import DirectoryInput +from nodes.properties.outputs import TextOutput + +from .. import directory_group + + +@directory_group.register( + schema_id="chainner:utility:directory_to_text", + name="Directory to Text", + description="Converts a directory path into text.", + icon="BsFolder", + inputs=[ + DirectoryInput(must_exist=False, label_style="hidden"), + ], + outputs=[ + TextOutput( + "Dir Text", + output_type="Input0.path", + ), + ], +) +def directory_to_text_node(directory: Path) -> str: + return str(directory) diff --git a/src/common/types/chainner-builtin.ts b/src/common/types/chainner-builtin.ts index def8387998..32c3ef67a6 100644 --- a/src/common/types/chainner-builtin.ts +++ b/src/common/types/chainner-builtin.ts @@ -14,6 +14,8 @@ import { handleNumberLiterals, intersect, literal, + union, + wrapBinary, wrapQuaternary, wrapScopedUnary, wrapTernary, @@ -360,3 +362,53 @@ export const parseColorJson = wrapScopedUnary( return createInstance(colorDesc); } ); + +const getParentDirectoryStr = (pathStr: string): string => { + return path.dirname(pathStr); +}; +export const getParentDirectory = wrapBinary( + (pathStr, times) => { + if (times.type === 'literal' && times.value === 0) { + return pathStr; + } + if (pathStr.type === 'literal') { + let min; + let max; + if (times.type === 'literal') { + min = times.value; + max = times.value; + } else { + min = times.min; + max = times.max; + } + + // the basic idea here is that repeatedly getting the parent directory of a path + // will eventually converge to the root directory, so we can stop when that happens + let p = pathStr.value; + for (let i = 0; i < min; i += 1) { + const next = getParentDirectoryStr(p); + if (next === p) { + return literal(p); + } + p = next; + } + + if (min === max) { + return literal(p); + } + + const values = new Set(); + values.add(p); + for (let i = min; i < max; i += 1) { + p = getParentDirectoryStr(p); + if (values.has(p)) { + break; + } + values.add(p); + } + + return union(...[...values].map(literal)); + } + return StringType.instance; + } +); diff --git a/src/common/types/chainner-scope.ts b/src/common/types/chainner-scope.ts index c274bfdd8c..33fe2da7e4 100644 --- a/src/common/types/chainner-scope.ts +++ b/src/common/types/chainner-scope.ts @@ -12,6 +12,7 @@ import { import { lazy } from '../util'; import { formatTextPattern, + getParentDirectory, padCenter, padEnd, padStart, @@ -126,6 +127,7 @@ intrinsic def padEnd(text: string, width: uint, padding: string): string; intrinsic def padCenter(text: string, width: uint, padding: string): string; intrinsic def splitFilePath(path: string): SplitFilePath; intrinsic def parseColorJson(json: string): Color; +intrinsic def getParentDirectory(path: string, times: uint): string; `; export const getChainnerScope = lazy((): Scope => { @@ -139,6 +141,7 @@ export const getChainnerScope = lazy((): Scope => { padCenter: makeScoped(padCenter), splitFilePath, parseColorJson, + getParentDirectory: makeScoped(getParentDirectory), }; const definitions = parseDefinitions(new SourceDocument(code, 'chainner-internal'));