1pub const PYTHON_KEYWORDS: &[&str] = &[
19 "False", "None", "True", "and", "as", "assert", "async", "await", "break", "class", "continue", "def", "del",
20 "elif", "else", "except", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "nonlocal",
21 "not", "or", "pass", "raise", "return", "try", "type", "while", "with", "yield",
22];
23
24pub const PYTHON_STR_METHODS: &[&str] = &[
31 "capitalize",
32 "casefold",
33 "center",
34 "count",
35 "encode",
36 "endswith",
37 "expandtabs",
38 "find",
39 "format",
40 "format_map",
41 "index",
42 "isalnum",
43 "isalpha",
44 "isascii",
45 "isdecimal",
46 "isdigit",
47 "isidentifier",
48 "islower",
49 "isnumeric",
50 "isprintable",
51 "isspace",
52 "istitle",
53 "isupper",
54 "join",
55 "ljust",
56 "lower",
57 "lstrip",
58 "maketrans",
59 "partition",
60 "removeprefix",
61 "removesuffix",
62 "replace",
63 "rfind",
64 "rindex",
65 "rjust",
66 "rpartition",
67 "rsplit",
68 "rstrip",
69 "split",
70 "splitlines",
71 "startswith",
72 "strip",
73 "swapcase",
74 "title",
75 "translate",
76 "upper",
77 "zfill",
78];
79
80pub const JAVA_KEYWORDS: &[&str] = &[
82 "abstract",
83 "assert",
84 "boolean",
85 "break",
86 "byte",
87 "case",
88 "catch",
89 "char",
90 "class",
91 "const",
92 "continue",
93 "default",
94 "do",
95 "double",
96 "else",
97 "enum",
98 "extends",
99 "final",
100 "finally",
101 "float",
102 "for",
103 "goto",
104 "if",
105 "implements",
106 "import",
107 "instanceof",
108 "int",
109 "interface",
110 "long",
111 "native",
112 "new",
113 "package",
114 "private",
115 "protected",
116 "public",
117 "return",
118 "short",
119 "static",
120 "strictfp",
121 "super",
122 "switch",
123 "synchronized",
124 "this",
125 "throw",
126 "throws",
127 "transient",
128 "try",
129 "void",
130 "volatile",
131 "while",
132];
133
134pub const CSHARP_KEYWORDS: &[&str] = &[
136 "abstract",
137 "as",
138 "base",
139 "bool",
140 "break",
141 "byte",
142 "case",
143 "catch",
144 "char",
145 "checked",
146 "class",
147 "const",
148 "continue",
149 "decimal",
150 "default",
151 "delegate",
152 "do",
153 "double",
154 "else",
155 "enum",
156 "event",
157 "explicit",
158 "extern",
159 "false",
160 "finally",
161 "fixed",
162 "float",
163 "for",
164 "foreach",
165 "goto",
166 "if",
167 "implicit",
168 "in",
169 "int",
170 "interface",
171 "internal",
172 "is",
173 "lock",
174 "long",
175 "namespace",
176 "new",
177 "null",
178 "object",
179 "operator",
180 "out",
181 "override",
182 "params",
183 "private",
184 "protected",
185 "public",
186 "readonly",
187 "ref",
188 "return",
189 "sbyte",
190 "sealed",
191 "short",
192 "sizeof",
193 "stackalloc",
194 "static",
195 "string",
196 "struct",
197 "switch",
198 "this",
199 "throw",
200 "true",
201 "try",
202 "typeof",
203 "uint",
204 "ulong",
205 "unchecked",
206 "unsafe",
207 "ushort",
208 "using",
209 "virtual",
210 "void",
211 "volatile",
212 "while",
213];
214
215pub const PHP_KEYWORDS: &[&str] = &[
217 "abstract",
218 "and",
219 "as",
220 "break",
221 "callable",
222 "case",
223 "catch",
224 "class",
225 "clone",
226 "const",
227 "continue",
228 "declare",
229 "default",
230 "die",
231 "do",
232 "echo",
233 "else",
234 "elseif",
235 "empty",
236 "enddeclare",
237 "endfor",
238 "endforeach",
239 "endif",
240 "endswitch",
241 "endwhile",
242 "eval",
243 "exit",
244 "extends",
245 "final",
246 "finally",
247 "fn",
248 "for",
249 "foreach",
250 "function",
251 "global",
252 "goto",
253 "if",
254 "implements",
255 "include",
256 "instanceof",
257 "insteadof",
258 "interface",
259 "isset",
260 "list",
261 "match",
262 "namespace",
263 "new",
264 "or",
265 "print",
266 "private",
267 "protected",
268 "public",
269 "readonly",
270 "require",
271 "return",
272 "static",
273 "switch",
274 "throw",
275 "trait",
276 "try",
277 "unset",
278 "use",
279 "var",
280 "while",
281 "xor",
282 "yield",
283];
284
285pub const RUBY_KEYWORDS: &[&str] = &[
287 "__ENCODING__",
288 "__FILE__",
289 "__LINE__",
290 "BEGIN",
291 "END",
292 "alias",
293 "and",
294 "begin",
295 "break",
296 "case",
297 "class",
298 "def",
299 "defined?",
300 "do",
301 "else",
302 "elsif",
303 "end",
304 "ensure",
305 "false",
306 "for",
307 "if",
308 "in",
309 "module",
310 "next",
311 "nil",
312 "not",
313 "or",
314 "redo",
315 "rescue",
316 "retry",
317 "return",
318 "self",
319 "super",
320 "then",
321 "true",
322 "undef",
323 "unless",
324 "until",
325 "when",
326 "while",
327 "yield",
328];
329
330pub const ELIXIR_KEYWORDS: &[&str] = &[
332 "after", "and", "catch", "do", "else", "end", "false", "fn", "in", "nil", "not", "or", "rescue", "true", "when",
333];
334
335pub const GO_KEYWORDS: &[&str] = &[
337 "break",
338 "case",
339 "chan",
340 "const",
341 "continue",
342 "default",
343 "defer",
344 "else",
345 "fallthrough",
346 "for",
347 "func",
348 "go",
349 "goto",
350 "if",
351 "import",
352 "interface",
353 "map",
354 "package",
355 "range",
356 "return",
357 "select",
358 "struct",
359 "switch",
360 "type",
361 "var",
362];
363
364pub const JS_KEYWORDS: &[&str] = &[
366 "abstract",
367 "arguments",
368 "await",
369 "boolean",
370 "break",
371 "byte",
372 "case",
373 "catch",
374 "char",
375 "class",
376 "const",
377 "continue",
378 "debugger",
379 "default",
380 "delete",
381 "do",
382 "double",
383 "else",
384 "enum",
385 "eval",
386 "export",
387 "extends",
388 "false",
389 "final",
390 "finally",
391 "float",
392 "for",
393 "function",
394 "goto",
395 "if",
396 "implements",
397 "import",
398 "in",
399 "instanceof",
400 "int",
401 "interface",
402 "let",
403 "long",
404 "native",
405 "new",
406 "null",
407 "package",
408 "private",
409 "protected",
410 "public",
411 "return",
412 "short",
413 "static",
414 "super",
415 "switch",
416 "synchronized",
417 "this",
418 "throw",
419 "throws",
420 "transient",
421 "true",
422 "try",
423 "typeof",
424 "var",
425 "void",
426 "volatile",
427 "while",
428 "with",
429 "yield",
430];
431
432pub const R_KEYWORDS: &[&str] = &[
434 "FALSE", "Inf", "NA", "NaN", "NULL", "TRUE", "break", "else", "for", "function", "if", "in", "next", "repeat",
435 "return", "while",
436];
437
438pub const KOTLIN_KEYWORDS: &[&str] = &[
440 "as",
441 "break",
442 "class",
443 "continue",
444 "do",
445 "else",
446 "false",
447 "for",
448 "fun",
449 "if",
450 "in",
451 "interface",
452 "is",
453 "null",
454 "object",
455 "package",
456 "return",
457 "super",
458 "this",
459 "throw",
460 "true",
461 "try",
462 "typealias",
463 "typeof",
464 "val",
465 "var",
466 "when",
467 "while",
468 "by",
470 "init",
471 "constructor",
472 "field",
473 "value",
474 "where",
475];
476
477pub const SWIFT_KEYWORDS: &[&str] = &[
479 "associatedtype",
480 "class",
481 "deinit",
482 "enum",
483 "extension",
484 "fileprivate",
485 "func",
486 "import",
487 "init",
488 "inout",
489 "internal",
490 "let",
491 "open",
492 "operator",
493 "private",
494 "protocol",
495 "public",
496 "rethrows",
497 "static",
498 "struct",
499 "subscript",
500 "typealias",
501 "var",
502 "break",
503 "case",
504 "continue",
505 "default",
506 "defer",
507 "do",
508 "else",
509 "fallthrough",
510 "for",
511 "guard",
512 "if",
513 "in",
514 "repeat",
515 "return",
516 "switch",
517 "where",
518 "while",
519 "as",
520 "Any",
521 "catch",
522 "false",
523 "is",
524 "nil",
525 "super",
526 "self",
527 "Self",
528 "throw",
529 "throws",
530 "true",
531 "try",
532 "_",
533];
534
535pub const DART_KEYWORDS: &[&str] = &[
537 "abstract",
538 "as",
539 "assert",
540 "async",
541 "await",
542 "break",
543 "case",
544 "catch",
545 "class",
546 "const",
547 "continue",
548 "covariant",
549 "default",
550 "deferred",
551 "do",
552 "dynamic",
553 "else",
554 "enum",
555 "export",
556 "extends",
557 "extension",
558 "external",
559 "factory",
560 "false",
561 "final",
562 "finally",
563 "for",
564 "Function",
565 "get",
566 "hide",
567 "if",
568 "implements",
569 "import",
570 "in",
571 "interface",
572 "is",
573 "late",
574 "library",
575 "mixin",
576 "new",
577 "null",
578 "of",
579 "on",
580 "operator",
581 "part",
582 "required",
583 "rethrow",
584 "return",
585 "set",
586 "show",
587 "static",
588 "super",
589 "switch",
590 "sync",
591 "this",
592 "throw",
593 "true",
594 "try",
595 "typedef",
596 "var",
597 "void",
598 "when",
599 "while",
600 "with",
601 "yield",
602];
603
604pub const GLEAM_KEYWORDS: &[&str] = &[
606 "as",
607 "assert",
608 "auto",
609 "case",
610 "const",
611 "delegate",
612 "derive",
613 "echo",
614 "else",
615 "fn",
616 "if",
617 "implement",
618 "import",
619 "let",
620 "macro",
621 "opaque",
622 "panic",
623 "pub",
624 "test",
625 "todo",
626 "type",
627 "use",
628];
629
630pub const ZIG_KEYWORDS: &[&str] = &[
632 "addrspace",
633 "align",
634 "allowzero",
635 "and",
636 "anyframe",
637 "anytype",
638 "asm",
639 "async",
640 "await",
641 "break",
642 "callconv",
643 "catch",
644 "comptime",
645 "const",
646 "continue",
647 "defer",
648 "else",
649 "enum",
650 "errdefer",
651 "error",
652 "export",
653 "extern",
654 "fn",
655 "for",
656 "if",
657 "inline",
658 "linksection",
659 "noalias",
660 "noinline",
661 "nosuspend",
662 "or",
663 "orelse",
664 "packed",
665 "pub",
666 "resume",
667 "return",
668 "struct",
669 "suspend",
670 "switch",
671 "test",
672 "threadlocal",
673 "try",
674 "union",
675 "unreachable",
676 "usingnamespace",
677 "var",
678 "volatile",
679 "while",
680];
681
682pub fn python_safe_name(name: &str) -> Option<String> {
690 if PYTHON_KEYWORDS.contains(&name) {
691 Some(format!("{name}_"))
692 } else {
693 None
694 }
695}
696
697pub fn python_ident(name: &str) -> String {
700 python_safe_name(name).unwrap_or_else(|| name.to_string())
701}
702
703pub fn python_str_enum_safe_name(name: &str) -> Option<String> {
709 if PYTHON_KEYWORDS.contains(&name) || PYTHON_STR_METHODS.contains(&name) {
710 Some(format!("{name}_"))
711 } else {
712 None
713 }
714}
715
716pub fn python_str_enum_ident(name: &str) -> String {
719 python_str_enum_safe_name(name).unwrap_or_else(|| name.to_string())
720}
721
722pub fn kotlin_safe_name(name: &str) -> Option<String> {
724 if KOTLIN_KEYWORDS.contains(&name) {
725 Some(format!("{name}_"))
726 } else {
727 None
728 }
729}
730
731pub fn kotlin_ident(name: &str) -> String {
733 kotlin_safe_name(name).unwrap_or_else(|| name.to_string())
734}
735
736pub fn swift_safe_name(name: &str) -> Option<String> {
738 if SWIFT_KEYWORDS.contains(&name) {
739 Some(format!("{name}_"))
740 } else {
741 None
742 }
743}
744
745pub fn swift_ident(name: &str) -> String {
747 swift_safe_name(name).unwrap_or_else(|| name.to_string())
748}
749
750pub fn swift_case_safe_name(name: &str) -> Option<String> {
759 if SWIFT_KEYWORDS.contains(&name) {
760 Some(format!("`{name}`"))
761 } else {
762 None
763 }
764}
765
766pub fn swift_case_ident(name: &str) -> String {
773 swift_case_safe_name(name).unwrap_or_else(|| name.to_string())
774}
775
776pub fn dart_safe_name(name: &str) -> Option<String> {
778 if DART_KEYWORDS.contains(&name) {
779 Some(format!("{name}_"))
780 } else {
781 None
782 }
783}
784
785pub fn dart_ident(name: &str) -> String {
787 dart_safe_name(name).unwrap_or_else(|| name.to_string())
788}
789
790pub fn gleam_safe_name(name: &str) -> Option<String> {
792 if GLEAM_KEYWORDS.contains(&name) {
793 Some(format!("{name}_"))
794 } else {
795 None
796 }
797}
798
799pub fn gleam_ident(name: &str) -> String {
801 gleam_safe_name(name).unwrap_or_else(|| name.to_string())
802}
803
804pub fn zig_safe_name(name: &str) -> Option<String> {
806 if ZIG_KEYWORDS.contains(&name) {
807 Some(format!("{name}_"))
808 } else {
809 None
810 }
811}
812
813pub fn zig_ident(name: &str) -> String {
822 let mut sanitized = String::with_capacity(name.len() + 1);
823 for ch in name.chars() {
824 if ch.is_ascii_alphanumeric() || ch == '_' {
825 sanitized.push(ch);
826 } else {
827 sanitized.push('_');
828 }
829 }
830 if sanitized.chars().next().is_some_and(|ch| ch.is_ascii_digit()) {
831 sanitized.insert(0, '_');
832 }
833 zig_safe_name(&sanitized).unwrap_or(sanitized)
834}
835
836#[cfg(test)]
837mod tests {
838 use super::*;
839
840 #[test]
841 fn python_class_is_reserved() {
842 assert_eq!(python_safe_name("class"), Some("class_".to_string()));
843 }
844
845 #[test]
846 fn python_ordinary_name_is_none() {
847 assert_eq!(python_safe_name("layout_class"), None);
848 }
849
850 #[test]
851 fn python_ident_reserved() {
852 assert_eq!(python_ident("class"), "class_");
853 }
854
855 #[test]
856 fn python_ident_ordinary() {
857 assert_eq!(python_ident("layout_class"), "layout_class");
858 }
859
860 #[test]
861 fn kotlin_class_is_reserved() {
862 assert_eq!(kotlin_safe_name("class"), Some("class_".to_string()));
863 assert_eq!(kotlin_safe_name("fun"), Some("fun_".to_string()));
864 assert_eq!(kotlin_safe_name("ordinary"), None);
865 assert_eq!(kotlin_ident("typealias"), "typealias_");
866 }
867
868 #[test]
869 fn swift_init_is_reserved() {
870 assert_eq!(swift_safe_name("init"), Some("init_".to_string()));
871 assert_eq!(swift_safe_name("Self"), Some("Self_".to_string()));
872 assert_eq!(swift_safe_name("normal"), None);
873 assert_eq!(swift_ident("protocol"), "protocol_");
874 }
875
876 #[test]
877 fn swift_case_ident_backtick_escapes_reserved_keywords() {
878 assert_eq!(swift_case_ident("default"), "`default`");
884 assert_eq!(swift_case_ident("protocol"), "`protocol`");
885 assert_eq!(swift_case_ident("init"), "`init`");
886 assert_eq!(swift_case_ident("Self"), "`Self`");
887 assert_eq!(swift_case_ident("Any"), "`Any`");
888 assert_eq!(swift_case_ident("class"), "`class`");
889 assert_eq!(swift_case_ident("inout"), "`inout`");
890 assert_eq!(swift_case_ident("rethrows"), "`rethrows`");
891 assert_eq!(swift_case_ident("gitHub"), "gitHub");
893 assert_eq!(swift_case_ident("normal"), "normal");
894 assert_eq!(swift_case_ident("dracula"), "dracula");
895 }
896
897 #[test]
898 fn swift_case_safe_name_returns_some_for_reserved() {
899 assert_eq!(swift_case_safe_name("default"), Some("`default`".to_string()));
900 assert_eq!(swift_case_safe_name("normal"), None);
901 }
902
903 #[test]
904 fn dart_async_is_reserved() {
905 assert_eq!(dart_safe_name("async"), Some("async_".to_string()));
906 assert_eq!(dart_safe_name("late"), Some("late_".to_string()));
907 assert_eq!(dart_safe_name("normal"), None);
908 assert_eq!(dart_ident("required"), "required_");
909 }
910
911 #[test]
912 fn gleam_pub_is_reserved() {
913 assert_eq!(gleam_safe_name("pub"), Some("pub_".to_string()));
914 assert_eq!(gleam_safe_name("opaque"), Some("opaque_".to_string()));
915 assert_eq!(gleam_safe_name("normal"), None);
916 assert_eq!(gleam_ident("type"), "type_");
917 }
918
919 #[test]
920 fn zig_comptime_is_reserved() {
921 assert_eq!(zig_safe_name("comptime"), Some("comptime_".to_string()));
922 assert_eq!(zig_safe_name("errdefer"), Some("errdefer_".to_string()));
923 assert_eq!(zig_safe_name("normal"), None);
924 assert_eq!(zig_ident("usingnamespace"), "usingnamespace_");
925 }
926
927 #[test]
928 fn python_keywords_covers_common_cases() {
929 for kw in &[
930 "def", "return", "yield", "pass", "import", "from", "type", "None", "True", "False",
931 ] {
932 assert!(
933 python_safe_name(kw).is_some(),
934 "expected {kw:?} to be a Python reserved keyword"
935 );
936 }
937 }
938
939 #[test]
940 fn python_str_enum_ident_escapes_str_methods() {
941 assert_eq!(python_str_enum_ident("title"), "title_");
943 assert_eq!(python_str_enum_ident("lower"), "lower_");
944 assert_eq!(python_str_enum_ident("upper"), "upper_");
945 assert_eq!(python_str_enum_ident("count"), "count_");
946 assert_eq!(python_str_enum_ident("capitalize"), "capitalize_");
947 assert_eq!(python_str_enum_ident("split"), "split_");
948 }
949
950 #[test]
951 fn python_str_enum_ident_escapes_python_keywords() {
952 assert_eq!(python_str_enum_ident("del"), "del_");
954 assert_eq!(python_str_enum_ident("class"), "class_");
955 assert_eq!(python_str_enum_ident("return"), "return_");
956 }
957
958 #[test]
959 fn python_str_enum_ident_passes_through_ordinary_names() {
960 assert_eq!(python_str_enum_ident("body"), "body");
962 assert_eq!(python_str_enum_ident("div"), "div");
963 assert_eq!(python_str_enum_ident("paragraph"), "paragraph");
964 }
965
966 #[test]
967 fn python_str_enum_safe_name_returns_some_for_reserved() {
968 assert_eq!(python_str_enum_safe_name("title"), Some("title_".to_string()));
969 assert_eq!(python_str_enum_safe_name("del"), Some("del_".to_string()));
970 }
971
972 #[test]
973 fn python_str_enum_safe_name_returns_none_for_ordinary() {
974 assert_eq!(python_str_enum_safe_name("body"), None);
975 assert_eq!(python_str_enum_safe_name("content"), None);
976 }
977}