43 lines
2.3 KiB
Python
43 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
import argparse, re
|
|
from pathlib import Path
|
|
|
|
def valid_identifier(value: str) -> str:
|
|
if not re.fullmatch(r'[A-Za-z][A-Za-z0-9]*', value):
|
|
raise argparse.ArgumentTypeError('Use PascalCase alphanumeric identifiers only.')
|
|
return value
|
|
|
|
def render_tree(source: Path, target: Path, tokens: dict[str, str], dry_run: bool) -> list[Path]:
|
|
generated: list[Path] = []
|
|
for item in source.rglob('*'):
|
|
if item.is_dir(): continue
|
|
relative = Path(str(item.relative_to(source)).replace('__MODULE__', tokens['MODULE']).replace('__FEATURE__', tokens['FEATURE']))
|
|
output = target / relative
|
|
content = item.read_text(encoding='utf-8')
|
|
for key, value in tokens.items(): content = content.replace(f'__{key}__', value)
|
|
if '__' in content: raise RuntimeError(f'Unresolved template token in {item}')
|
|
generated.append(output)
|
|
if not dry_run:
|
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
if output.exists(): raise FileExistsError(f'Refusing to overwrite {output}')
|
|
output.write_text(content, encoding='utf-8')
|
|
return generated
|
|
|
|
def main() -> int:
|
|
parser=argparse.ArgumentParser(description='Generate a K-ArtSell Vertical Slice backend/frontend packet.')
|
|
parser.add_argument('--module', required=True, type=valid_identifier)
|
|
parser.add_argument('--feature', required=True, type=valid_identifier)
|
|
parser.add_argument('--slice-id', required=True, help='e.g. VS-14')
|
|
parser.add_argument('--root', type=Path, default=Path.cwd())
|
|
parser.add_argument('--dry-run', action='store_true')
|
|
args=parser.parse_args()
|
|
template_root=Path(__file__).resolve().parents[1] / 'templates' / 'vertical-slice'
|
|
tokens={'MODULE':args.module,'FEATURE':args.feature,'SLICE_ID':args.slice_id}
|
|
targets=[(template_root/'backend',args.root/'src'/f'KArtSell.Modules.{args.module}'/'Features'/args.feature),(template_root/'frontend',args.root/'frontend'/'src'/'features'/re.sub(r'(?<!^)(?=[A-Z])','-',args.feature).lower())]
|
|
generated=[]
|
|
for source,target in targets: generated.extend(render_tree(source,target,tokens,args.dry_run))
|
|
for path in generated: print(path)
|
|
return 0
|
|
if __name__=='__main__': raise SystemExit(main())
|