diff --git a/.cspell b/.cspell index 1576a9ec4..3d9ace5d3 100644 --- a/.cspell +++ b/.cspell @@ -76,6 +76,7 @@ kstem kuromoji Kuromoji languageset +latlon Léon localstats Lovins @@ -160,6 +161,8 @@ securityconfig slowlog Slowlog slurpfile +smartcn +Smartcn snapshotted softmax Sorani @@ -179,9 +182,11 @@ termvectors tfidf Tfidf Tika +tlbr tokenfilters translog Translog +trbl tubone Undeploys unigrams diff --git a/spec/schemas/_common.analysis.yaml b/spec/schemas/_common.analysis.yaml index 22f6ad014..9cae913b6 100644 --- a/spec/schemas/_common.analysis.yaml +++ b/spec/schemas/_common.analysis.yaml @@ -1373,7 +1373,7 @@ components: type: string enum: - canonical - - 'no' + - no IcuCollationStrength: type: string enum: diff --git a/spec/schemas/_common.mapping.yaml b/spec/schemas/_common.mapping.yaml index 4aaace28f..c08585de3 100644 --- a/spec/schemas/_common.mapping.yaml +++ b/spec/schemas/_common.mapping.yaml @@ -881,17 +881,17 @@ components: - title: left type: string enum: - - left - LEFT - clockwise - cw + - left - title: right type: string enum: - - right - RIGHT - - counterclockwise - ccw + - counterclockwise + - right GeoStrategy: type: string enum: @@ -1201,8 +1201,8 @@ components: model_id: type: string required: - - type - dimension + - type MatchType: type: string enum: diff --git a/spec/schemas/indices._common.yaml b/spec/schemas/indices._common.yaml index 3a01d2e99..141beba9b 100644 --- a/spec/schemas/indices._common.yaml +++ b/spec/schemas/indices._common.yaml @@ -418,10 +418,10 @@ components: TranslogDurability: type: string enum: - - async - ASYNC - - request - REQUEST + - async + - request TranslogRetention: type: object properties: diff --git a/tools/src/_utils/index.ts b/tools/src/_utils/index.ts index 5177fd86e..02d9a18aa 100644 --- a/tools/src/_utils/index.ts +++ b/tools/src/_utils/index.ts @@ -15,6 +15,9 @@ import { to_json } from "../helpers"; export const HTTP_METHODS: OpenAPIV3.HttpMethods[] = Object.values(OpenAPIV3.HttpMethods) export type SchemaObjectType = OpenAPIV3.ArraySchemaObjectType | OpenAPIV3.NonArraySchemaObjectType export const SCHEMA_OBJECT_TYPES: SchemaObjectType[] = ['array', 'boolean', 'object', 'number', 'string', 'integer'] +export const SCHEMA_NUMERIC_TYPES: SchemaObjectType[] = ['number', 'integer'] +export const SCHEMA_NUMBER_FORMATS: string[] = ['float', 'double'] +export const SCHEMA_INTEGER_FORMATS: string[] = ['int32', 'int64'] export function is_ref (o: MaybeRef): o is OpenAPIV3.ReferenceObject { return o != null && typeof o === 'object' && '$ref' in o diff --git a/tools/src/linter/InlineObjectSchemaValidator.ts b/tools/src/linter/InlineObjectSchemaValidator.ts deleted file mode 100644 index 1f3e06134..000000000 --- a/tools/src/linter/InlineObjectSchemaValidator.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* -* Copyright OpenSearch Contributors -* SPDX-License-Identifier: Apache-2.0 -* -* The OpenSearch Contributors require contributions made to -* this file be licensed under the Apache-2.0 license or a -* compatible open source license. -*/ - -import type NamespacesFolder from './components/NamespacesFolder' -import type SchemasFolder from './components/SchemasFolder' -import { type ValidationError } from 'types' -import { SchemaVisitor } from '../_utils/SpecificationVisitor' -import { is_ref, type MaybeRef, SpecificationContext } from '../_utils' -import { type OpenAPIV3 } from 'openapi-types' - -export default class InlineObjectSchemaValidator { - private readonly _namespaces_folder: NamespacesFolder - private readonly _schemas_folder: SchemasFolder - - constructor (namespaces_folder: NamespacesFolder, schemas_folder: SchemasFolder) { - this._namespaces_folder = namespaces_folder - this._schemas_folder = schemas_folder - } - - validate (): ValidationError[] { - const errors: ValidationError[] = [] - - const visitor = new SchemaVisitor((ctx, schema) => { - this.#validate_schema(ctx, schema, errors) - }); - - [ - ...this._namespaces_folder.files, - ...this._schemas_folder.files - ].forEach(f => { visitor.visit_specification(new SpecificationContext(f.file), f.spec()) }) - - return errors - } - - #validate_schema (ctx: SpecificationContext, schema: MaybeRef, errors: ValidationError[]): void { - if (is_ref(schema) || schema.type !== 'object' || schema.properties === undefined) { - return - } - - const ancestry = ctx.keys.reverse() - - if (ancestry[1] === 'properties' || - ancestry[0] === 'additionalProperties' || - ancestry[0] === 'items' || - (ancestry[0] === 'schema' && ancestry[2] === 'parameters' && ancestry[3] !== 'components')) { - errors.push(ctx.error('object schemas should be defined out-of-line via a $ref')) - } - } -} diff --git a/tools/src/linter/SchemaVisitingValidator.ts b/tools/src/linter/SchemaVisitingValidator.ts new file mode 100644 index 000000000..bf3beff82 --- /dev/null +++ b/tools/src/linter/SchemaVisitingValidator.ts @@ -0,0 +1,99 @@ +/* +* Copyright OpenSearch Contributors +* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +import type NamespacesFolder from './components/NamespacesFolder' +import type SchemasFolder from './components/SchemasFolder' +import { type ValidationError } from 'types' +import { SchemaVisitor } from '../_utils/SpecificationVisitor' +import { + is_ref, + type MaybeRef, + SCHEMA_INTEGER_FORMATS, + SCHEMA_NUMBER_FORMATS, + SCHEMA_NUMERIC_TYPES, + SpecificationContext +} from '../_utils' +import { type OpenAPIV3 } from 'openapi-types' + +export default class SchemaVisitingValidator { + private readonly _namespaces_folder: NamespacesFolder + private readonly _schemas_folder: SchemasFolder + + constructor (namespaces_folder: NamespacesFolder, schemas_folder: SchemasFolder) { + this._namespaces_folder = namespaces_folder + this._schemas_folder = schemas_folder + } + + validate (): ValidationError[] { + const errors: ValidationError[] = [] + + const validating_functions = [ + this.#validate_inline_object_schema.bind(this), + this.#validate_numeric_schema.bind(this) + ] + + const visitor = new SchemaVisitor((ctx, schema) => { + for (const f of validating_functions) { + f(ctx, schema, errors) + } + }); + + [ + ...this._namespaces_folder.files, + ...this._schemas_folder.files + ].forEach(f => { visitor.visit_specification(new SpecificationContext(f.file), f.spec()) }) + + return errors + } + + #validate_inline_object_schema (ctx: SpecificationContext, schema: MaybeRef, errors: ValidationError[]): void { + if (is_ref(schema) || schema.type !== 'object' || schema.properties === undefined) { + return + } + + const ancestry = ctx.keys.reverse() + + if (ancestry[1] === 'properties' || + ancestry[0] === 'additionalProperties' || + ancestry[0] === 'items' || + (ancestry[0] === 'schema' && ancestry[2] === 'parameters' && ancestry[3] !== 'components')) { + errors.push(ctx.error('object schemas should be defined out-of-line via a $ref')) + } + } + + #validate_numeric_schema (ctx: SpecificationContext, schema: MaybeRef, errors: ValidationError[]): void { + if (is_ref(schema) || schema.type === undefined || !SCHEMA_NUMERIC_TYPES.includes(schema.type)) { + return + } + + if (schema.type === 'number') { + if (schema.format === undefined || SCHEMA_NUMBER_FORMATS.includes(schema.format)) { + return + } + + if (SCHEMA_INTEGER_FORMATS.includes(schema.format)) { + errors.push(ctx.error(`schema of type 'number' with format '${schema.format}' should instead be of type 'integer'`)) + } else { + errors.push(ctx.error(`schema of type 'number' with format '${schema.format}' is invalid, expected one of: ${SCHEMA_NUMBER_FORMATS.join(', ')}`)) + } + } + + if (schema.type === 'integer') { + if (schema.format === undefined || SCHEMA_INTEGER_FORMATS.includes(schema.format)) { + return + } + + if (SCHEMA_NUMBER_FORMATS.includes(schema.format)) { + errors.push(ctx.error(`schema of type 'integer' with format '${schema.format}' should instead be of type 'number'`)) + } else { + errors.push(ctx.error(`schema of type 'integer' with format '${schema.format}' is invalid, expected one of: ${SCHEMA_INTEGER_FORMATS.join(', ')}`)) + } + } + } +} diff --git a/tools/src/linter/SpecValidator.ts b/tools/src/linter/SpecValidator.ts index b954d3acc..462fbe93b 100644 --- a/tools/src/linter/SpecValidator.ts +++ b/tools/src/linter/SpecValidator.ts @@ -13,7 +13,7 @@ import { type ValidationError } from 'types' import SchemaRefsValidator from './SchemaRefsValidator' import SupersededOperationsFile from './components/SupersededOperationsFile' import InfoFile from './components/InfoFile' -import InlineObjectSchemaValidator from './InlineObjectSchemaValidator' +import SchemaVisitingValidator from './SchemaVisitingValidator' import SchemasValidator from './SchemasValidator' import { type Logger } from '../Logger' @@ -25,7 +25,7 @@ export default class SpecValidator { schemas_folder: SchemasFolder schemas_validator: SchemasValidator schema_refs_validator: SchemaRefsValidator - inline_object_schema_validator: InlineObjectSchemaValidator + inline_object_schema_validator: SchemaVisitingValidator constructor (root_folder: string, logger: Logger) { this.logger = logger @@ -35,7 +35,7 @@ export default class SpecValidator { this.schemas_folder = new SchemasFolder(`${root_folder}/schemas`) this.schemas_validator = new SchemasValidator(root_folder, logger) this.schema_refs_validator = new SchemaRefsValidator(this.namespaces_folder, this.schemas_folder) - this.inline_object_schema_validator = new InlineObjectSchemaValidator(this.namespaces_folder, this.schemas_folder) + this.inline_object_schema_validator = new SchemaVisitingValidator(this.namespaces_folder, this.schemas_folder) } validate (): ValidationError[] { diff --git a/tools/tests/linter/InlineObjectSchemaValidator.test.ts b/tools/tests/linter/InlineObjectSchemaValidator.test.ts index 8efeea258..7e3b2514c 100644 --- a/tools/tests/linter/InlineObjectSchemaValidator.test.ts +++ b/tools/tests/linter/InlineObjectSchemaValidator.test.ts @@ -9,13 +9,13 @@ import SchemasFolder from 'linter/components/SchemasFolder' import NamespacesFolder from 'linter/components/NamespacesFolder' -import InlineObjectSchemaValidator from 'linter/InlineObjectSchemaValidator' +import SchemaVisitingValidator from 'linter/SchemaVisitingValidator' test('validate()', () => { const root_folder = './tools/tests/linter/fixtures/inline_object_schema_validator' const namespaces_folder = new NamespacesFolder(`${root_folder}/namespaces`) const schemas_folder = new SchemasFolder(`${root_folder}/schemas`) - const validator = new InlineObjectSchemaValidator(namespaces_folder, schemas_folder) + const validator = new SchemaVisitingValidator(namespaces_folder, schemas_folder) expect(validator.validate()).toEqual([ { file: 'namespaces/ops.yaml',