Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions nirman/parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import re
from typing import List, Tuple

# A set for fast, case-insensitive lookup of Windows reserved names.
# We also include '.' and '..' which are special on all platforms.
RESERVED_NAMES = {
"con", "prn", "aux", "nul",
"com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
"lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
".", ".."
}

# Regex for invalid characters, EXCLUDING slashes which are handled separately.
INVALID_CHARS_REGEX = r'[<>:"|?*]'

def parse_markdown_tree(lines: List[str]) -> List[Tuple[int, str, bool]]:
"""
Parse a markdown tree structure into a list of tuples representing the file/folder hierarchy.
Expand Down Expand Up @@ -38,10 +50,29 @@ def parse_markdown_tree(lines: List[str]) -> List[Tuple[int, str, bool]]:
depth = 0
else:
depth = (len(prefix) // 4) + 1

# 1. First, determine if it's a directory from the raw name.
is_directory = name.endswith(('/', '\\'))

# 2. Then, create the clean_name by stripping the slashes.
clean_name = name.strip('\\/')

# 3. Now, sanitize the clean_name for invalid characters.
clean_name = re.sub(INVALID_CHARS_REGEX, '_', clean_name)

# 4. Finally, sanitize for reserved system names.
base_name = clean_name.split('.')[0]
if base_name.lower() in RESERVED_NAMES:
clean_name = "_" + clean_name

is_directory = name.endswith(('/', '\\'))
clean_name = name.strip('\\/')

# Get the base name before any extension for the check.
base_name = clean_name.split('.')[0]
if base_name.lower() in RESERVED_NAMES:
clean_name = "_" + clean_name

if clean_name == '.' and depth == 0:
is_directory = True

Expand Down