From 4afc1b2cac3f7898e4a73bab3f7b5c974dbb78e2 Mon Sep 17 00:00:00 2001 From: Quentin Pradet Date: Fri, 14 Nov 2025 10:23:28 +0400 Subject: [PATCH] Allow @ sign in @server_default annotation (#5664) * Allow @ sign in @server_default annotation * Fix lint * Run make contrib (cherry picked from commit 469fd6b822a8ad039ffde61fd2ce755205d14292) # Conflicts: # output/schema/schema.json --- compiler/src/model/utils.ts | 5 +++++ docs/modeling-guide.md | 12 ++++++++++++ output/openapi/elasticsearch-openapi.json | 5 +++-- output/openapi/elasticsearch-serverless-openapi.json | 5 +++-- output/schema/schema.json | 7 ++++--- specification/eql/search/EqlSearchRequest.ts | 3 ++- specification/ingest/_types/Processors.ts | 2 +- 7 files changed, 30 insertions(+), 9 deletions(-) diff --git a/compiler/src/model/utils.ts b/compiler/src/model/utils.ts index 1df0269ff1..9dd98e4251 100644 --- a/compiler/src/model/utils.ts +++ b/compiler/src/model/utils.ts @@ -877,6 +877,11 @@ function hoistPropertyAnnotations (property: model.Property, jsDocs: JSDoc[]): v assert(jsDocs, Array.isArray(value), 'The default value should be an array') property.serverDefault = value } else { + // JSDoc prevents literal @ in values, but the at sign can be escaped + if (value.startsWith('\\@')) { + value = value.replace('\\@', '@') + } + switch (property.type.type.name) { case 'boolean': assert(jsDocs, value === 'true' || value === 'false', `The default value for ${property.name} should be a boolean`) diff --git a/docs/modeling-guide.md b/docs/modeling-guide.md index 974bb4589e..6a59d2c86a 100644 --- a/docs/modeling-guide.md +++ b/docs/modeling-guide.md @@ -601,6 +601,18 @@ class Foo { } ``` +If you need an `@` sign, you can escape it: + +```ts +class Foo { + /** + * Field containing event timestamp. + * @server_default \@timestamp + */ + timestamp_field?: Field +} +``` + #### `@doc_id` An identifier that can be used for generating the doc url in clients. diff --git a/output/openapi/elasticsearch-openapi.json b/output/openapi/elasticsearch-openapi.json index 0e66ad168d..43fd03e291 100644 --- a/output/openapi/elasticsearch-openapi.json +++ b/output/openapi/elasticsearch-openapi.json @@ -102051,7 +102051,7 @@ }, "target_field": { "description": "The field that will hold the parsed date.", - "default": "`@timestamp`", + "default": "@timestamp", "allOf": [ { "$ref": "#/components/schemas/_types.Field" @@ -144207,7 +144207,8 @@ ] }, "timestamp_field": { - "description": "Field containing event timestamp. Default \"@timestamp\"", + "description": "Field containing event timestamp.", + "default": "@timestamp", "allOf": [ { "$ref": "#/components/schemas/_types.Field" diff --git a/output/openapi/elasticsearch-serverless-openapi.json b/output/openapi/elasticsearch-serverless-openapi.json index 5e71e85e6a..4fb6e20d34 100644 --- a/output/openapi/elasticsearch-serverless-openapi.json +++ b/output/openapi/elasticsearch-serverless-openapi.json @@ -66069,7 +66069,7 @@ }, "target_field": { "description": "The field that will hold the parsed date.", - "default": "`@timestamp`", + "default": "@timestamp", "allOf": [ { "$ref": "#/components/schemas/_types.Field" @@ -86746,7 +86746,8 @@ ] }, "timestamp_field": { - "description": "Field containing event timestamp. Default \"@timestamp\"", + "description": "Field containing event timestamp.", + "default": "@timestamp", "allOf": [ { "$ref": "#/components/schemas/_types.Field" diff --git a/output/schema/schema.json b/output/schema/schema.json index 2755031169..ad2b5987a8 100644 --- a/output/schema/schema.json +++ b/output/schema/schema.json @@ -137312,9 +137312,10 @@ } }, { - "description": "Field containing event timestamp. Default \"@timestamp\"", + "description": "Field containing event timestamp.", "name": "timestamp_field", "required": false, + "serverDefault": "@timestamp", "type": { "kind": "instance_of", "type": { @@ -137716,7 +137717,7 @@ } } ], - "specLocation": "eql/search/EqlSearchRequest.ts#L28-L166" + "specLocation": "eql/search/EqlSearchRequest.ts#L28-L167" }, { "kind": "response", @@ -177731,7 +177732,7 @@ "description": "The field that will hold the parsed date.", "name": "target_field", "required": false, - "serverDefault": "`@timestamp`", + "serverDefault": "@timestamp", "type": { "kind": "instance_of", "type": { diff --git a/specification/eql/search/EqlSearchRequest.ts b/specification/eql/search/EqlSearchRequest.ts index 049966f9a0..91ccd44944 100644 --- a/specification/eql/search/EqlSearchRequest.ts +++ b/specification/eql/search/EqlSearchRequest.ts @@ -108,7 +108,8 @@ export interface Request extends RequestBase { */ tiebreaker_field?: Field /** - * Field containing event timestamp. Default "@timestamp" + * Field containing event timestamp. + * @server_default \@timestamp */ timestamp_field?: Field /** diff --git a/specification/ingest/_types/Processors.ts b/specification/ingest/_types/Processors.ts index 2040dca164..1ec077575a 100644 --- a/specification/ingest/_types/Processors.ts +++ b/specification/ingest/_types/Processors.ts @@ -784,7 +784,7 @@ export class DateProcessor extends ProcessorBase { locale?: string /** * The field that will hold the parsed date. - * @server_default `@timestamp` + * @server_default \@timestamp */ target_field?: Field /**