Skip to content

Commit ac85df1

Browse files
stephentoubCopilot
andauthored
Emit regex data annotations from C# codegen (#1338)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 4dcbfc5 commit ac85df1

3 files changed

Lines changed: 47 additions & 5 deletions

File tree

dotnet/src/Polyfills/CodeAnalysisAttributes.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ internal sealed class StringSyntaxAttribute : Attribute
3030
{
3131
public const string Uri = nameof(Uri);
3232

33+
public const string Regex = nameof(Regex);
34+
3335
public StringSyntaxAttribute(string syntax)
3436
{
3537
Syntax = syntax;

nodejs/test/python-codegen.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,3 +455,41 @@ describe("enum value description codegen", () => {
455455
expect(code).toContain(' #[serde(rename = "beta")]\n Beta,');
456456
});
457457
});
458+
459+
describe("csharp session event codegen", () => {
460+
it("emits regular expression attributes for regex format properties with patterns", () => {
461+
const schema: JSONSchema7 = {
462+
definitions: {
463+
SessionEvent: {
464+
anyOf: [
465+
{
466+
type: "object",
467+
required: ["type", "data"],
468+
properties: {
469+
type: { const: "session.synthetic" },
470+
data: {
471+
type: "object",
472+
required: ["pattern"],
473+
properties: {
474+
pattern: {
475+
type: "string",
476+
format: "regex",
477+
pattern: "^foo\\d+$",
478+
},
479+
},
480+
},
481+
},
482+
},
483+
],
484+
},
485+
},
486+
};
487+
488+
const code = generateCSharpSessionEventsCode(schema);
489+
490+
expect(code).toContain(` [StringSyntax(StringSyntaxAttribute.Regex)]
491+
[RegularExpression("^foo\\\\d+$")]
492+
[JsonPropertyName("pattern")]`);
493+
expect(code.split(`[RegularExpression("^foo\\\\d+$")]`)).toHaveLength(2);
494+
});
495+
});

scripts/codegen/csharp.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -376,9 +376,12 @@ function emitDataAnnotations(schema: JSONSchema7, indent: string): string[] {
376376
attrs.push(`${indent}[StringSyntax(StringSyntaxAttribute.Uri)]`);
377377
}
378378

379-
// [StringSyntax(StringSyntaxAttribute.Regex)] for format: "regex"
379+
// [StringSyntax(StringSyntaxAttribute.Regex)] and [RegularExpression] for format: "regex"
380380
if (format === "regex") {
381381
attrs.push(`${indent}[StringSyntax(StringSyntaxAttribute.Regex)]`);
382+
if (typeof schema.pattern === "string") {
383+
attrs.push(`${indent}[RegularExpression("${escapeCSharpStringLiteral(schema.pattern)}")]`);
384+
}
382385
}
383386

384387
// [Base64String] for base64-encoded string properties
@@ -407,10 +410,9 @@ function emitDataAnnotations(schema: JSONSchema7, indent: string): string[] {
407410
}
408411
}
409412

410-
// [RegularExpression] for pattern
411-
if (typeof schema.pattern === "string") {
412-
const escaped = schema.pattern.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
413-
attrs.push(`${indent}[RegularExpression("${escaped}")]`);
413+
// [RegularExpression] for pattern constraints on non-regex-format properties
414+
if (format !== "regex" && typeof schema.pattern === "string") {
415+
attrs.push(`${indent}[RegularExpression("${escapeCSharpStringLiteral(schema.pattern)}")]`);
414416
}
415417

416418
// [MinLength] / [MaxLength] for string constraints

0 commit comments

Comments
 (0)