Skip to content

Commit

Permalink
Add Directory Go Into node (#2702)
Browse files Browse the repository at this point in the history
  • Loading branch information
RunDevelopment authored Mar 21, 2024
1 parent 1614bdc commit f96aa3b
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from __future__ import annotations

import re
from pathlib import Path

from nodes.groups import optional_list_group
from nodes.properties.inputs import DirectoryInput, TextInput
from nodes.properties.outputs import DirectoryOutput

from .. import directory_group

INVALID_CHARS = re.compile(r"[<>:\"|?*\x00-\x1F]")


def is_abs(path: str) -> bool:
return path.startswith(("/", "\\")) or Path(path).is_absolute()


def go_into(dir: Path, folder: str) -> Path:
if is_abs(folder):
raise ValueError("Absolute paths are not allowed as folders.")

invalid = INVALID_CHARS.search(folder)
if invalid is not None:
raise ValueError(f"Invalid character '{invalid.group()}' in folder name.")

return (dir / folder).resolve()


@directory_group.register(
schema_id="chainner:utility:into_directory",
name="Directory Go Into",
description="Goes forward into a directory.",
icon="BsFolder",
inputs=[
DirectoryInput(must_exist=False, label_style="hidden"),
TextInput("Folder"),
optional_list_group(
*[TextInput(f"Folder {i}").make_optional() for i in range(2, 11)],
),
],
outputs=[
DirectoryOutput(
output_type="""
def into(dir: Directory | Error, folder: string | null): Directory | Error {
match dir {
Error as e => e,
Directory => {
match folder {
null => dir,
string => {
let result = goIntoDirectory(dir.path, folder);
match result {
string => Directory { path: result },
Error => result,
}
},
}
},
}
}
let d1 = into(Input0, Input1);
let d2 = into(d1, Input2);
let d3 = into(d2, Input3);
let d4 = into(d3, Input4);
let d5 = into(d4, Input5);
let d6 = into(d5, Input6);
let d7 = into(d6, Input7);
let d8 = into(d7, Input8);
let d9 = into(d8, Input9);
let d10 = into(d9, Input10);
d10
""",
),
],
)
def directory_go_into_node(directory: Path, *folders: str | None) -> Path:
for folder in folders:
if folder is not None:
directory = go_into(directory, folder)
return directory
45 changes: 45 additions & 0 deletions src/common/types/chainner-builtin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
union,
wrapBinary,
wrapQuaternary,
wrapScopedBinary,
wrapScopedUnary,
wrapTernary,
} from '@chainner/navi';
Expand Down Expand Up @@ -412,3 +413,47 @@ export const getParentDirectory = wrapBinary<StringPrimitive, Int, StringPrimiti
return StringType.instance;
}
);

// eslint-disable-next-line no-control-regex
const INVALID_PATH_CHARS = /[<>:"|?*\x00-\x1F]/;
const goIntoDirectoryImpl = (basePath: string, relPath: string): string | Error => {
const isAbsolute = /^[/\\]/.test(relPath) || path.isAbsolute(relPath);
if (isAbsolute) {
return new Error('Absolute paths are not allowed as folders.');
}

const invalid = INVALID_PATH_CHARS.exec(relPath);
if (invalid) {
return new Error(`Invalid character '${invalid[0]}' in folder name.`);
}

const joined = path.join(basePath, relPath);
return path.resolve(joined);
};
export const goIntoDirectory = wrapScopedBinary(
(
scope,
basePath: StringPrimitive,
relPath: StringPrimitive
): Arg<StringPrimitive | StructInstanceType> => {
const errorDesc = getStructDescriptor(scope, 'Error');

if (basePath.type === 'literal' && relPath.type === 'literal') {
try {
const result = goIntoDirectoryImpl(basePath.value, relPath.value);
if (typeof result === 'string') {
return literal(result);
}
return createInstance(errorDesc, {
message: literal(result.message),
});
} catch (e) {
return createInstance(errorDesc, {
message: literal(String(e)),
});
}
}

return union(StringType.instance, errorDesc.default);
}
);
3 changes: 3 additions & 0 deletions src/common/types/chainner-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { lazy } from '../util';
import {
formatTextPattern,
getParentDirectory,
goIntoDirectory,
padCenter,
padEnd,
padStart,
Expand Down Expand Up @@ -128,6 +129,7 @@ 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;
intrinsic def goIntoDirectory(basePath: string, path: string): string | Error;
`;

export const getChainnerScope = lazy((): Scope => {
Expand All @@ -142,6 +144,7 @@ export const getChainnerScope = lazy((): Scope => {
splitFilePath,
parseColorJson,
getParentDirectory: makeScoped(getParentDirectory),
goIntoDirectory,
};

const definitions = parseDefinitions(new SourceDocument(code, 'chainner-internal'));
Expand Down

0 comments on commit f96aa3b

Please sign in to comment.