@@ -121,10 +121,29 @@ def build_clash_config(mode: str, rules: List[Dict[str, str]]) -> Dict[str, Any]
121121 return config
122122
123123
124+ def _yaml_quote (s : str ) -> str :
125+ """Quote a string value if it contains YAML-special characters."""
126+ if not s :
127+ return "''"
128+ needs_quote = (
129+ s .startswith (("{" , "[" , "'" , '"' , "*" , "&" , "!" , "|" , ">" , "%" , "@" , "`" ))
130+ or "#" in s
131+ or ": " in s
132+ or s .endswith (":" )
133+ or s .startswith ("- " )
134+ or s .strip () != s
135+ or s .lower () in ("true" , "false" , "null" , "yes" , "no" , "on" , "off" )
136+ )
137+ if not needs_quote :
138+ return s
139+ escaped = s .replace ("'" , "''" )
140+ return f"'{ escaped } '"
141+
142+
124143def config_to_yaml (config : Dict [str , Any ]) -> str :
125144 """Convert config dict to YAML string."""
126145 lines = []
127-
146+
128147 def add_line (key : str , value , indent : int = 0 ):
129148 prefix = " " * indent
130149 if isinstance (value , dict ):
@@ -139,15 +158,15 @@ def add_line(key: str, value, indent: int = 0):
139158 for k , v in item .items ():
140159 add_line (k , v , indent + 2 )
141160 else :
142- lines .append (f"{ prefix } - { item } " )
161+ lines .append (f"{ prefix } - { _yaml_quote ( str ( item )) } " )
143162 elif isinstance (value , bool ):
144163 lines .append (f"{ prefix } { key } : { str (value ).lower ()} " )
145164 elif isinstance (value , int ):
146165 lines .append (f"{ prefix } { key } : { value } " )
147166 else :
148- lines .append (f"{ prefix } { key } : { value } " )
149-
167+ lines .append (f"{ prefix } { key } : { _yaml_quote ( str ( value )) } " )
168+
150169 for key , value in config .items ():
151170 add_line (key , value )
152-
171+
153172 return "\n " .join (lines )
0 commit comments