diff --git a/src/plugins/console/public/application/components/variables/utils.test.ts b/src/plugins/console/public/application/components/variables/utils.test.ts new file mode 100644 index 0000000000000..0b990ca998114 --- /dev/null +++ b/src/plugins/console/public/application/components/variables/utils.test.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { isValidVariableName } from './utils'; + +describe('utils', () => { + describe('isValidVariableName', () => { + it('returns `false` to `null`', () => { + // @ts-ignore passing a wrong type intentionally + expect(isValidVariableName(null)).toBe(false); + }); + + it('returns `false` to empty string', () => { + expect(isValidVariableName('')).toBe(false); + }); + + it('returns `false` to space string', () => { + expect(isValidVariableName(' ')).toBe(false); + }); + + it('returns `false` to integer zero', () => { + // @ts-ignore passing a wrong type intentionally + expect(isValidVariableName(0)).toBe(false); + }); + + it('returns `false` to float zero', () => { + // @ts-ignore passing a wrong type intentionally + expect(isValidVariableName(0.0)).toBe(false); + }); + + it('returns `true` to string zero', () => { + expect(isValidVariableName('0')).toBe(true); + }); + + it('returns `true` to allowed styles', () => { + for (const name of ['camelCase', 'snake_case', 'PascalCase', 'MACRO_CASE']) { + expect(isValidVariableName(name)).toBe(true); + } + }); + + it('returns `false` to disallowed styles', () => { + for (const name of ['kebab-case', 'COBOL-CASE', 'dot.notation', 'bracket[notation]']) { + expect(isValidVariableName(name)).toBe(false); + } + }); + + it('returns `true` to underscores prefix & suffix', () => { + expect(isValidVariableName('__name__')).toBe(true); + }); + + it('returns `true` to numbers prefix & suffix', () => { + expect(isValidVariableName('00name00')).toBe(true); + }); + }); +}); diff --git a/src/plugins/console/public/application/components/variables/utils.ts b/src/plugins/console/public/application/components/variables/utils.ts index 852498b92da98..3e0ac32f266c4 100644 --- a/src/plugins/console/public/application/components/variables/utils.ts +++ b/src/plugins/console/public/application/components/variables/utils.ts @@ -37,3 +37,12 @@ export const generateEmptyVariableField = (): DevToolsVariable => ({ name: '', value: '', }); + +export const isValidVariableName = (name: string) => { + /* + * MUST avoid characters that get URL-encoded, because they'll result in unusable variable names. + * Common variable names consist of letters, digits, and underscores and do not begin with a digit. + * However, the ones beginning with a digit are still allowed here for backward compatibility. + */ + return typeof name === 'string' && name.match(/^[a-zA-Z0-9_]+$/g) !== null; +}; diff --git a/src/plugins/console/public/application/components/variables/variables_flyout.tsx b/src/plugins/console/public/application/components/variables/variables_flyout.tsx index 46b67bdf9075f..5ca172b2e045b 100644 --- a/src/plugins/console/public/application/components/variables/variables_flyout.tsx +++ b/src/plugins/console/public/application/components/variables/variables_flyout.tsx @@ -85,15 +85,14 @@ export const DevToolsVariablesFlyout = (props: DevToolsVariablesFlyoutProps) => defaultMessage: 'Variable name', }), render: (name, { id }) => { - // Avoid characters that get URL-encoded, because they'll result in unusable variable names. - const isInvalid = name && !name.match(/^[a-zA-Z0-9]+$/g); + const isInvalid = !utils.isValidVariableName(name); return ( , ]} fullWidth={true}