Skip to content

Feat(#27): add input validation#28

Merged
mvhenten merged 1 commit intomainfrom
feat-add-validation
Dec 17, 2025
Merged

Feat(#27): add input validation#28
mvhenten merged 1 commit intomainfrom
feat-add-validation

Conversation

@mvhenten
Copy link
Owner

@mvhenten mvhenten commented Dec 17, 2025

Lack of input validation can creep up on us - as typescript types won't easily allow string length or number type validation.

Copilot AI review requested due to automatic review settings December 17, 2025 11:39
@mvhenten mvhenten merged commit 6e82dba into main Dec 17, 2025
7 checks passed
@mvhenten mvhenten deleted the feat-add-validation branch December 17, 2025 11:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive input validation to ElectroDB entity attributes based on TypeSpec constraints. The emitter now generates validation functions at build time that enforce constraints like string length, integer types, datetime formats, and enum values.

Key changes:

  • Introduces validation function generation based on TypeSpec decorators (@minlength, @maxlength, @minValue, @MaxValue, @pattern, etc.)
  • Adds type-specific validators for integers, floats, datetime types, and enums
  • Updates test suite to verify validation functions are generated correctly and enforce constraints as expected

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/emitter.ts Implements validation constraint extraction and function generation with helper functions for type detection (integer, float, datetime), constraint gathering from property and scalar hierarchies, and validation function building via eval
test/entities.test.js Updates existing entity tests to check for validation function presence and adds comprehensive validation test suites covering string length, integers, datetime, and enum validations with both positive and negative test cases

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +228 to +232
if (constraints.pattern) {
const escapedPattern = constraints.pattern.replace(/\\/g, "\\\\");
checks.push(
`if (typeof value === "string" && !new RegExp("${escapedPattern}").test(value)) throw new Error("Value must match pattern ${escapedPattern}")`,
);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern escaping is insufficient and could lead to code injection. Only backslashes are escaped, but quotes and other special characters that could break out of the string literal are not handled. Consider using JSON.stringify to properly escape the pattern for use in a string literal, or use template literal escaping. For example, if a pattern contains a double quote, it would break the generated code.

Copilot uses AI. Check for mistakes.
Comment on lines +262 to +266
if (constraints.enumValues && constraints.enumValues.length > 0) {
const allowedValues = JSON.stringify(constraints.enumValues);
checks.push(
`if (!${allowedValues}.includes(value)) throw new Error("Value must be one of: ${constraints.enumValues.join(", ")}")`,
);
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enum values in the error message are not escaped and could contain special characters that break the generated code or produce confusing error messages. While JSON.stringify is used for the array check, the error message uses join which doesn't escape special characters. Consider escaping the enum values in the error message or using JSON.stringify for the error message portion as well.

Copilot uses AI. Check for mistakes.
Comment on lines +139 to +165
/**
* Gets the base scalar name for a type (for datetime type identification).
*/
function getBaseScalarName(type: Scalar): string {
const dateTimeTypes = [
"utcDateTime",
"offsetDateTime",
"plainDate",
"plainTime",
];

// Check the type itself first
if (dateTimeTypes.includes(type.name)) {
return type.name;
}

// Walk up the base scalar chain to find a datetime type
let baseType = type.baseScalar;
while (baseType) {
if (dateTimeTypes.includes(baseType.name)) {
return baseType.name;
}
baseType = baseType.baseScalar;
}

return type.name;
}
Copy link

Copilot AI Dec 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getBaseScalarName function duplicates the dateTimeTypes array definition from isDateTimeType. Consider extracting this array to a module-level constant to avoid duplication and ensure consistency if the list needs to be updated in the future.

Copilot uses AI. Check for mistakes.
mvhenten added a commit that referenced this pull request Dec 17, 2025
@MaxValue
Copy link

Maaan didn't know I am a typespec generator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants