Skip to content

Commit

Permalink
Fix up docs
Browse files Browse the repository at this point in the history
  • Loading branch information
imalsogreg committed Nov 22, 2024
1 parent 31b78f9 commit f4ee739
Showing 1 changed file with 34 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,15 @@ pub(super) fn validate(ctx: &mut Context<'_>) {
}

/// Enforce that keywords in the user's requested target languages
/// do not appear as field names in BAML classes.
pub(super) fn assert_no_reserved_names_in_fields(
/// do not appear as field names in BAML classes, and that field
/// names are not equal to type names when using Pydantic.
pub(super) fn assert_no_field_name_collisions(
ctx: &mut Context<'_>,
generator_output_types: &HashSet<GeneratorOutputType>,
) {

// The list of reserved words for all user-requested codegen targets.
let reserved = reserved_names(generator_output_types);

for cls in ctx.db.walk_classes() {
for c in cls.static_fields() {
let field: &Field<FieldType> = c.ast_field();
Expand All @@ -66,15 +68,26 @@ pub(super) fn assert_no_reserved_names_in_fields(
if let Some(langs) = reserved.get(field.name()) {
let msg = match langs.as_slice() {
[lang] => format!("Field name is a reserved word in generated {lang} clients."),
_ => format!("Field name is a reserved word in language clients: {}.", join(langs, ", ")),
_ => format!(
"Field name is a reserved word in language clients: {}.",
join(langs, ", ")
),
};
ctx.push_error(DatamodelError::new_field_validation_error(
msg , "class", c.name(), field.name(), field.span.clone()))
msg,
"class",
c.name(),
field.name(),
field.span.clone(),
))
}

// Check for collision between field name and type name when using Pydantic.
if generator_output_types.contains(&GeneratorOutputType::PythonPydantic) {
let type_name = field.expr.as_ref().map_or("".to_string(), |r#type| r#type.name());
let type_name = field
.expr
.as_ref()
.map_or("".to_string(), |r#type| r#type.name());
if field.name() == type_name {
ctx.push_error(DatamodelError::new_field_validation_error(
"When using the python/pydantic generator, a field name must not be exactly equal to the type name. Consider changing the field name and using an alias.".to_string(),
Expand All @@ -89,13 +102,15 @@ pub(super) fn assert_no_reserved_names_in_fields(
}
}

/// For a given set of target language, construct a map from keyword to the list
/// of target languages in which that identifier is a keyword.
/// For a given set of target languages, construct a map from keyword to the
/// list of target languages in which that identifier is a keyword.
///
/// This will be used later to make error messages like, "Could not use name
/// `ETA` becase that is a keyword in Python", "Could not use the name `return`
/// because that is a keyword in Python and Typescript".
fn reserved_names(generator_output_types: &HashSet<GeneratorOutputType>) -> HashMap<&'static str, Vec<GeneratorOutputType>> {
/// `continue` becase that is a keyword in Python", "Could not use the name
/// `return` because that is a keyword in Python and Typescript".
fn reserved_names(
generator_output_types: &HashSet<GeneratorOutputType>,
) -> HashMap<&'static str, Vec<GeneratorOutputType>> {
let mut keywords: HashMap<&str, Vec<GeneratorOutputType>> = HashMap::new();

let language_keywords: Vec<(&str, GeneratorOutputType)> = [
Expand Down Expand Up @@ -133,13 +148,15 @@ fn reserved_names(generator_output_types: &HashSet<GeneratorOutputType>) -> Hash
keywords
}

// This list of keywords was copied from
// https://www.w3schools.com/python/python_ref_keywords.asp
// .
const RESERVED_NAMES_PYTHON: &[&str] = &[
"False", "None", "True", "and", "as", "assert", "async",
"await", "break", "class", "continue", "def", "del", "elif",
"else", "except", "finally", "for", "from", "global", "if",
"import", "in", "is", "lambda", "nonlocal", "not", "or",
"pass", "raise", "return", "try", "while", "with", "yield"
];
"False", "None", "True", "and", "as", "assert", "async", "await", "break", "class", "continue",
"def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import",
"in", "is", "lambda", "nonlocal", "not", "or", "pass", "raise", "return", "try", "while",
"with", "yield",
];

// Typescript is much more flexible in the key names it allows.
const RESERVED_NAMES_TYPESCRIPT: &[&str] = &[];

0 comments on commit f4ee739

Please sign in to comment.