# Path: DnD/modules/lib/helpers.py
# def sanitize_filename(name: str) -> str:
#     """Translates problematic characters in a filename into happier ones."""
#     return name.translate(str.maketrans(" '/:", "_@&$"))


import json
import re
from pathlib import Path
from typing import List, Tuple, Optional
from bs4 import BeautifulSoup, Tag
from DnD.modules.lib.helpers import sanitize_filename
    return '\n'.join(effect), '\n'.join(variants)


def construct_attack(body: str, range: str) -> Optional[dict]:
    damage = re.search(r'(\d+d\d+(?:[+-]\d+)?) (\w+) damage', body)
    save = re.search(r'(\w+) saving throw', body, re.IGNORECASE)
    attack = 'spell attack' in body
    if not ((attack or save) and damage):
        return None
    # Try it as the most basic kind of attack
    return {
        "attacks": [
            {
                "range": range,
                "to_hit": {
                    "test": "ATTACKROLL" if attack else "SAVE",
                    "against": "AC" if attack else save.group(1).title(),
                },
                "on_hit": {
                    "damage": {
                        "base_roll": damage.group(1),
                        "damage_type": damage.group(2)
                    }
                }
            }
        ]
    }


def write_one(data: dict, outputdir: Path):

# Path: DnD/modules/lib/helpers.py
# def sanitize_filename(name: str) -> str:
#     """Translates problematic characters in a filename into happier ones."""
#     return name.translate(str.maketrans(" '/:", "_@&$"))


# Path: tools/scripts/read_spell_xml.py
import json
import re
from pathlib import Path
from typing import List, Tuple, Optional
from bs4 import BeautifulSoup, Tag
from DnD.modules.lib.helpers import sanitize_filename

    return '\n'.join(effect), '\n'.join(variants)


def construct_attack(body: str, range: str) -> Optional[dict]:
    damage = re.search(r'(\d+d\d+(?:[+-]\d+)?) (\w+) damage', body)
    save = re.search(r'(\w+) saving throw', body, re.IGNORECASE)
    attack = 'spell attack' in body
    if not ((attack or save) and damage):
        return None
    # Try it as the most basic kind of attack
    return {
        "attacks": [
            {
                "range": range,
                "to_hit": {
                    "test": "ATTACKROLL" if attack else "SAVE",
                    "against": "AC" if attack else save.group(1).title(),
                },
                "on_hit": {
                    "damage": {
                        "base_roll": damage.group(1),
                        "damage_type": damage.group(2)
                    }
                }
            }
        ]
    }


def write_one(data: dict, outputdir: Path):

    file = outputdir / sanitize_filename(data['name'] + '.spell')