diff --git a/output/openapi/elasticsearch-openapi.json b/output/openapi/elasticsearch-openapi.json index 7bab9ebbd2..c4be817bd5 100644 --- a/output/openapi/elasticsearch-openapi.json +++ b/output/openapi/elasticsearch-openapi.json @@ -79964,14 +79964,7 @@ ] }, "_types.TaskId": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] + "type": "string" }, "tasks._types.TaskListResponseBase": { "type": "object", diff --git a/output/openapi/elasticsearch-serverless-openapi.json b/output/openapi/elasticsearch-serverless-openapi.json index 2eb99359b7..d5e06b0b57 100644 --- a/output/openapi/elasticsearch-serverless-openapi.json +++ b/output/openapi/elasticsearch-serverless-openapi.json @@ -51891,14 +51891,7 @@ ] }, "_types.TaskId": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] + "type": "string" }, "enrich.execute_policy.ExecuteEnrichPolicyStatus": { "type": "object", diff --git a/output/schema/schema.json b/output/schema/schema.json index 627356f7d7..864854716c 100644 --- a/output/schema/schema.json +++ b/output/schema/schema.json @@ -54799,23 +54799,11 @@ }, "specLocation": "_types/common.ts#L129-L129", "type": { - "kind": "union_of", - "items": [ - { - "kind": "instance_of", - "type": { - "name": "string", - "namespace": "_builtins" - } - }, - { - "kind": "instance_of", - "type": { - "name": "integer", - "namespace": "_types" - } - } - ] + "kind": "instance_of", + "type": { + "name": "string", + "namespace": "_builtins" + } } }, { diff --git a/output/typescript/types.ts b/output/typescript/types.ts index c765ea8f16..60d988085c 100644 --- a/output/typescript/types.ts +++ b/output/typescript/types.ts @@ -2962,7 +2962,7 @@ export interface TaskFailure { reason: ErrorCause } -export type TaskId = string | integer +export type TaskId = string export interface TextEmbedding { model_id: string diff --git a/specification/_types/common.ts b/specification/_types/common.ts index 73847e459e..00343529a8 100644 --- a/specification/_types/common.ts +++ b/specification/_types/common.ts @@ -126,7 +126,7 @@ export type SequenceNumber = long export type PropertyName = string export type RelationName = string -export type TaskId = string | integer +export type TaskId = string /** @doc_id fuzziness */ export type Fuzziness = string | integer /** @doc_id query-dsl-multi-term-rewrite */ diff --git a/specification/eslint.config.js b/specification/eslint.config.js index 2244cadc45..398377dbad 100644 --- a/specification/eslint.config.js +++ b/specification/eslint.config.js @@ -32,6 +32,7 @@ export default defineConfig({ plugins: { 'es-spec-validator': validator }, rules: { 'es-spec-validator/single-key-dictionary-key-is-string': 'error', + 'es-spec-validator/dictionary-key-is-string': 'error', 'es-spec-validator/invalid-node-types': 'warn' } }) diff --git a/validator/README.md b/validator/README.md index c43b60e18b..d64b769259 100644 --- a/validator/README.md +++ b/validator/README.md @@ -8,6 +8,7 @@ It is configured [in the specification directory](../specification/eslint.config | Name | Description | | - | - | | `single-key-dictionary-key-is-string` | `SingleKeyDictionary` keys must be strings. | +| `dictionary-key-is-string` | `Dictionary` keys must be strings. | | `invalid-node-types` | The spec uses a subset of TypeScript, so some types, clauses and expressions are not allowed. | ## Usage diff --git a/validator/eslint-plugin-es-spec.js b/validator/eslint-plugin-es-spec.js index 95537a4d34..e74b363579 100644 --- a/validator/eslint-plugin-es-spec.js +++ b/validator/eslint-plugin-es-spec.js @@ -17,11 +17,13 @@ * under the License. */ import singleKeyDict from './rules/single-key-dictionary-key-is-string.js' +import dict from './rules/dictionary-key-is-string.js' import invalidNodeTypes from './rules/invalid-node-types.js' export default { rules: { 'single-key-dictionary-key-is-string': singleKeyDict, + 'dictionary-key-is-string': dict, 'invalid-node-types': invalidNodeTypes, } } diff --git a/validator/rules/dictionary-key-is-string.js b/validator/rules/dictionary-key-is-string.js new file mode 100644 index 0000000000..d5c8eb1897 --- /dev/null +++ b/validator/rules/dictionary-key-is-string.js @@ -0,0 +1,64 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { ESLintUtils } from '@typescript-eslint/utils'; +import ts from 'typescript' + +const createRule = ESLintUtils.RuleCreator(name => `https://example.com/rule/${name}`) + +export default createRule({ + name: 'dictionary-key-is-string', + create(context) { + return { + TSTypeReference(node) { + if (node.typeName.name === 'Dictionary') { + const key = node.typeArguments.params[0] + switch (key.type) { + case 'TSTypeReference': + // trace the reference to its original type definition + const services = ESLintUtils.getParserServices(context) + const type = services.getTypeAtLocation(key) + + // check that the type is a string or an enum (enum members evaluate to strings) + if (type.intrinsicName !== 'string' && !(type.symbol?.flags & ts.SymbolFlags.RegularEnum)) { + context.report({ node, messageId: 'stringKey' }) + } + break + case 'TSStringKeyword': + // type is string, skip + break + default: + // unknown type! + context.report({ node, messageId: 'stringKey' }) + break + } + } + }, + } + }, + meta: { + docs: { + description: 'Dictionary keys must be strings', + }, + messages: { + stringKey: "Dictionary's key must be a string" + }, + type: 'suggestion', + }, + defaultOptions: [] +}) diff --git a/validator/test/dictionary-key-is-string.test.js b/validator/test/dictionary-key-is-string.test.js new file mode 100644 index 0000000000..bf8d81b9a6 --- /dev/null +++ b/validator/test/dictionary-key-is-string.test.js @@ -0,0 +1,61 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { RuleTester } from '@typescript-eslint/rule-tester' +import rule from '../rules/dictionary-key-is-string.js' + +const ruleTester = new RuleTester({ + languageOptions: { + parserOptions: { + projectService: { + allowDefaultProject: ['*.ts*'], + }, + tsconfigRootDir: import.meta.dirname, + }, + }, +}) + +ruleTester.run('dictionary-key-is-string', rule, { + valid: [ + `type MyDict = Dictionary`, + `type MyDict = Dictionary`, + `type MyDict = Dictionary`, + `enum MyEnum { foo, bar, baz } + type MyDict = Dictionary`, + ], + invalid: [ + { + code: + `type MyKey = string | boolean + type MyDict = Dictionary`, + errors: [{ messageId: 'stringKey' }] + }, + { + code: `type MyDict = Dictionary`, + errors: [{ messageId: 'stringKey' }] + }, + { + code: `type MyDict = Dictionary`, + errors: [{ messageId: 'stringKey' }] + }, + { + code: `type MyDict = Dictionary`, + errors: [{ messageId: 'stringKey' }] + } + ], +})