From a7b61aa0364f7ab0e1ddb03ee73163d28eb5e180 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Tue, 11 Aug 2020 20:47:20 +0300 Subject: [PATCH] Deprecate schema-less specs in Vega (#73805) * Deprecate schema-less specs in Vega Closes #30951 * update an error Message * update tests * update error message * Update vega_parser.ts Co-authored-by: Elastic Machine --- .../public/data_model/vega_parser.test.js | 27 +++++++----- .../public/data_model/vega_parser.ts | 44 +++++++++++-------- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/plugins/vis_type_vega/public/data_model/vega_parser.test.js b/src/plugins/vis_type_vega/public/data_model/vega_parser.test.js index 62563dce2a18d..ac92f31b890ed 100644 --- a/src/plugins/vis_type_vega/public/data_model/vega_parser.test.js +++ b/src/plugins/vis_type_vega/public/data_model/vega_parser.test.js @@ -28,6 +28,18 @@ jest.mock('../lib/vega', () => ({ vegaLite: jest.requireActual('vega-lite'), })); +describe(`VegaParser.parseAsync`, () => { + test(`should throw an error in case of $spec is not defined`, async () => { + const vp = new VegaParser('{}'); + + await vp.parseAsync(); + + expect( + vp.error.startsWith('Your specification requires a "$schema" field with a valid URL') + ).toBeTruthy(); + }); +}); + describe(`VegaParser._setDefaultValue`, () => { function check(spec, expected, ...params) { return () => { @@ -149,23 +161,14 @@ describe('VegaParser._resolveEsQueries', () => { ); }); -describe('VegaParser._parseSchema', () => { - function check(schema, isVegaLite, warningCount) { +describe('VegaParser.parseSchema', () => { + function check(schema, isVegaLite) { return () => { const vp = new VegaParser({ $schema: schema }); - expect(vp._parseSchema()).toBe(isVegaLite); - expect(vp.spec).toEqual({ $schema: schema }); - expect(vp.warnings).toHaveLength(warningCount); + expect(vp.parseSchema(vp.spec).isVegaLite).toBe(isVegaLite); }; } - test('should warn on no vega version specified', () => { - const vp = new VegaParser({}); - expect(vp._parseSchema()).toBe(false); - expect(vp.spec).toEqual({ $schema: 'https://vega.github.io/schema/vega/v5.json' }); - expect(vp.warnings).toHaveLength(1); - }); - test( 'should not warn on current vega version', check('https://vega.github.io/schema/vega/v5.json', false, 0) diff --git a/src/plugins/vis_type_vega/public/data_model/vega_parser.ts b/src/plugins/vis_type_vega/public/data_model/vega_parser.ts index 94d79071b8ef2..aceeefd953655 100644 --- a/src/plugins/vis_type_vega/public/data_model/vega_parser.ts +++ b/src/plugins/vis_type_vega/public/data_model/vega_parser.ts @@ -55,7 +55,6 @@ const locToDirMap: Record = { top: 'column-reverse', bottom: 'column', }; -const DEFAULT_SCHEMA: string = 'https://vega.github.io/schema/vega/v5.json'; // If there is no "%type%" parameter, use this parser const DEFAULT_PARSER: string = 'elasticsearch'; @@ -117,8 +116,27 @@ export class VegaParser { if (this.isVegaLite !== undefined) throw new Error(); if (typeof this.spec === 'string') { - this.spec = hjson.parse(this.spec, { legacyRoot: false }); + const spec = hjson.parse(this.spec, { legacyRoot: false }); + + if (!spec.$schema) { + throw new Error( + i18n.translate('visTypeVega.vegaParser.inputSpecDoesNotSpecifySchemaErrorMessage', { + defaultMessage: `Your specification requires a {schemaParam} field with a valid URL for +Vega (see {vegaSchemaUrl}) or +Vega-Lite (see {vegaLiteSchemaUrl}). +The URL is an identifier only. Kibana and your browser will never access this URL.`, + values: { + schemaParam: '"$schema"', + vegaLiteSchemaUrl: 'https://vega.github.io/vega-lite/docs/spec.html#top-level', + vegaSchemaUrl: + 'https://vega.github.io/vega/docs/specification/#top-level-specification-properties', + }, + }) + ); + } + this.spec = spec; } + if (!_.isPlainObject(this.spec)) { throw new Error( i18n.translate('visTypeVega.vegaParser.invalidVegaSpecErrorMessage', { @@ -126,7 +144,7 @@ export class VegaParser { }) ); } - this.isVegaLite = this._parseSchema(); + this.isVegaLite = this.parseSchema(this.spec).isVegaLite; this.useHover = !this.isVegaLite; this._config = this._parseConfig(); @@ -497,23 +515,11 @@ export class VegaParser { /** * Parse Vega schema element - * @returns {boolean} is this a VegaLite schema? + * @returns {object} isVegaLite, libVersion * @private */ - _parseSchema() { - if (!this.spec) return false; - if (!this.spec.$schema) { - this._onWarning( - i18n.translate('visTypeVega.vegaParser.inputSpecDoesNotSpecifySchemaWarningMessage', { - defaultMessage: - 'The input spec does not specify a {schemaParam}, defaulting to {defaultSchema}', - values: { defaultSchema: `"${DEFAULT_SCHEMA}"`, schemaParam: '"$schema"' }, - }) - ); - this.spec.$schema = DEFAULT_SCHEMA; - } - - const schema = schemaParser(this.spec.$schema); + private parseSchema(spec: VegaSpec) { + const schema = schemaParser(spec.$schema); const isVegaLite = schema.library === 'vega-lite'; const libVersion = isVegaLite ? vegaLite.version : vega.version; @@ -531,7 +537,7 @@ export class VegaParser { ); } - return isVegaLite; + return { isVegaLite, libVersion }; } /** diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 20484f80e8f52..10d6e8a16fe93 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4288,7 +4288,6 @@ "visTypeVega.vegaParser.dataExceedsSomeParamsUseTimesLimitErrorMessage": "データには {urlParam}、{valuesParam}、 {sourceParam} の内複数を含めることができません", "visTypeVega.vegaParser.hostConfigIsDeprecatedWarningMessage": "{deprecatedConfigName} は廃止されました。代わりに {newConfigName} を使用してください。", "visTypeVega.vegaParser.hostConfigValueTypeErrorMessage": "{configName} が含まれている場合、オブジェクトでなければなりません", - "visTypeVega.vegaParser.inputSpecDoesNotSpecifySchemaWarningMessage": "インプット仕様で {schemaParam} が指定されていないため、デフォルトで {defaultSchema} になります", "visTypeVega.vegaParser.invalidVegaSpecErrorMessage": "無効な Vega 仕様", "visTypeVega.vegaParser.kibanaConfigValueTypeErrorMessage": "{configName} が含まれている場合、オブジェクトでなければなりません", "visTypeVega.vegaParser.mapStyleValueTypeWarningMessage": "{mapStyleConfigName} は {mapStyleConfigFirstAllowedValue} か {mapStyleConfigSecondAllowedValue} のどちらかです", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 568637574aeac..378dd3817008d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4289,7 +4289,6 @@ "visTypeVega.vegaParser.dataExceedsSomeParamsUseTimesLimitErrorMessage": "数据不得包含 {urlParam}、{valuesParam} 和 {sourceParam} 中的多个值", "visTypeVega.vegaParser.hostConfigIsDeprecatedWarningMessage": "{deprecatedConfigName} 已弃用。请改用 {newConfigName}。", "visTypeVega.vegaParser.hostConfigValueTypeErrorMessage": "如果存在,{configName} 必须为对象", - "visTypeVega.vegaParser.inputSpecDoesNotSpecifySchemaWarningMessage": "输入规范未指定 {schemaParam},其默认值为 {defaultSchema}", "visTypeVega.vegaParser.invalidVegaSpecErrorMessage": "Vega 规范无效", "visTypeVega.vegaParser.kibanaConfigValueTypeErrorMessage": "如果存在,{configName} 必须为对象", "visTypeVega.vegaParser.mapStyleValueTypeWarningMessage": "{mapStyleConfigName} 可能为 {mapStyleConfigFirstAllowedValue} 或 {mapStyleConfigSecondAllowedValue}",