📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-06-23 16:03:00 +00:00
parent c4c6a41c21
commit 59e15f8999
557 changed files with 10501 additions and 3168 deletions
@@ -13,6 +13,7 @@ Usage:
import argparse
import os
import re
import sys
from pathlib import Path
from datetime import datetime
@@ -138,9 +139,44 @@ export type {{ {name}Props }} from './{name}';
''',
}
_COMPONENT_NAME_RE = re.compile(r"^[A-Za-z][A-Za-z0-9_-]*$")
def _safe_component_name(name: str) -> str:
name = name.strip()
if not _COMPONENT_NAME_RE.fullmatch(name):
raise ValueError("Component name must start with a letter and contain only letters, numbers, hyphens, or underscores")
return name
def _safe_component_dir(output_dir: Path, pascal_name: str, flat: bool) -> Path:
output_root = output_dir.resolve()
component_dir = output_root if flat else (output_root / pascal_name).resolve()
component_dir.relative_to(output_root)
return component_dir
def _safe_output_dir(raw_dir: str) -> Path:
raw = str(raw_dir).strip()
if "\x00" in raw:
raise ValueError("Output directory contains an invalid null byte")
parts = Path(raw).parts
if any(part == ".." for part in parts):
raise ValueError("Output directory must not contain '..' segments")
return Path(raw).expanduser().resolve()
def _safe_component_file(component_dir: Path, filename: str) -> Path:
if "/" in filename or "\\" in filename or "\x00" in filename or ".." in filename:
raise ValueError(f"Unsafe generated filename: {filename}")
target = (component_dir / filename).resolve()
target.relative_to(component_dir.resolve())
return target
def to_pascal_case(name: str) -> str:
"""Convert string to PascalCase."""
name = _safe_component_name(name)
# Handle kebab-case and snake_case
words = name.replace('-', '_').split('_')
return ''.join(word.capitalize() for word in words)
@@ -170,10 +206,7 @@ def generate_component(
kebab_name = to_kebab_case(pascal_name)
# Determine output path
if flat:
component_dir = output_dir
else:
component_dir = output_dir / pascal_name
component_dir = _safe_component_dir(output_dir, pascal_name, flat)
files_created = []
@@ -182,10 +215,10 @@ def generate_component(
# Generate main component file
if component_type == "hook":
main_file = component_dir / f"use{pascal_name}.ts"
main_file = _safe_component_file(component_dir, f"use{pascal_name}.ts")
template = TEMPLATES["hook"]
else:
main_file = component_dir / f"{pascal_name}.tsx"
main_file = _safe_component_file(component_dir, f"{pascal_name}.tsx")
template = TEMPLATES[component_type]
content = template.format(name=pascal_name)
@@ -194,21 +227,21 @@ def generate_component(
# Generate test file
if with_test and component_type != "hook":
test_file = component_dir / f"{pascal_name}.test.tsx"
test_file = _safe_component_file(component_dir, f"{pascal_name}.test.tsx")
test_content = TEMPLATES["test"].format(name=pascal_name)
test_file.write_text(test_content)
files_created.append(str(test_file))
# Generate story file
if with_story and component_type != "hook":
story_file = component_dir / f"{pascal_name}.stories.tsx"
story_file = _safe_component_file(component_dir, f"{pascal_name}.stories.tsx")
story_content = TEMPLATES["story"].format(name=pascal_name)
story_file.write_text(story_content)
files_created.append(str(story_file))
# Generate index file
if with_index and not flat:
index_file = component_dir / "index.ts"
index_file = _safe_component_file(component_dir, "index.ts")
index_content = TEMPLATES["index"].format(name=pascal_name)
index_file.write_text(index_content)
files_created.append(str(index_file))
@@ -244,14 +277,31 @@ def print_result(result: dict, verbose: bool = False) -> None:
print(f"\n const {{ isLoading, error }} = use{result['name']}();")
def self_test() -> None:
assert to_pascal_case("product-card") == "ProductCard"
for bad_name in ("../Card", "Bad.Name", "", "1Card"):
try:
to_pascal_case(bad_name)
except ValueError:
pass
else:
raise AssertionError(f"accepted unsafe component name: {bad_name!r}")
def main():
parser = argparse.ArgumentParser(
description="Generate React/Next.js components with TypeScript and Tailwind CSS"
)
parser.add_argument(
"name",
nargs="?",
help="Component name (PascalCase or kebab-case)"
)
parser.add_argument(
"--self-test",
action="store_true",
help="Run safety self-checks"
)
parser.add_argument(
"--dir", "-d",
default="src/components",
@@ -296,7 +346,14 @@ def main():
args = parser.parse_args()
output_dir = Path(args.dir)
if args.self_test:
self_test()
return
if not args.name:
parser.error("name is required unless --self-test is used")
output_dir = _safe_output_dir(args.dir)
pascal_name = to_pascal_case(args.name)
if args.dry_run: