defbuild_json_data(class_name:str,prefix:str,fields:list[FieldDescription])->dict:"""Build JSON data structure for a config class."""return{"class_name":class_name,"env_prefix":prefix,"fields":[asdict(f)forfinfields],}
defescape_markdown(text:str)->str:"""Escape markdown special characters."""forcharin["\\","`","*","_","{","}","[","]","(",")","#","+","-",".","!","|"]:text=text.replace(char,"\\"+char)returntext
defrender_json(class_name:str,prefix:str,fields:list[FieldDescription],line_ending:str,)->str:"""Render fields as JSON."""data=build_json_data(class_name,prefix,fields)result=json.dumps(data,indent=2)ifline_ending!="\n":result=result.replace("\n",line_ending)returnresult
defrender_dotenv(class_name:str,prefix:str,fields:list[FieldDescription],line_ending:str,include_descriptions:bool=True,include_examples:bool=True,)->str:"""Render fields as a .env.example file."""lines:list[str]=[]lines.append(f"# Configuration for {class_name}")ifprefix:lines.append(f"# All variables prefixed with: {prefix}")lines.append("")forfieldinfields:ifinclude_descriptionsandfield.descriptionandfield.description!="-":lines.append(f"# {field.description}")type_info=f"# Type: {field.type_name}"iffield.constraintsandfield.constraints!="-":type_info+=f" | Constraints: {field.constraints}"lines.append(type_info)# Type-based Example lines cover only the cases where the value line# below shows nothing useful: required fields (default "-") and empty# defaults (""). Any other default is already shown on the value# line, so an Example line would be a byte-identical duplicate.# Unknowable defaults (a raising factory renders# SET_PER_ENVIRONMENT), secrets, and None defaults get no Example# line either.ifinclude_examplesandfield.defaultin("","-"):iffield.type_name.startswith("list["):sep=field.separatorlines.append(f"# Example: {field.env_var}=value1{sep}value2{sep}value3")eliffield.type_name=="int":lines.append(f"# Example: {field.env_var}=8000")eliffield.type_name=="bool":lines.append(f"# Example: {field.env_var}=true")eliffield.type_name=="str":lines.append(f"# Example: {field.env_var}=your_value_here")iffield.required:lines.append(f"{field.env_var}=")else:iffield.default=="<secret>":lines.append(f"# {field.env_var}=your_secret_here")eliffield.defaultandfield.defaultnotin("-","None"):lines.append(f"# {field.env_var}={field.default}")else:# A "None" default lands here on purpose: "KEY=None" fails# coercion for non-str fields when uncommented, and env# files cannot express None — the empty value (which# Optional fields map back to None) is the honest render.lines.append(f"# {field.env_var}=")lines.append("")returnline_ending.join(lines)