Added nested keys check after root keys check for environment editor. (#2685)

Co-authored-by: Opender Singh <opender.singh@konghq.com>
Co-authored-by: James Gatz <jamesgatzos@gmail.com>
Co-authored-by: Dimitri Mitropoulos <dimitrimitropoulos@gmail.com>
This commit is contained in:
John
2021-09-11 03:25:32 +08:00
committed by GitHub
parent 6b20648b5b
commit 7e7d235fec
2 changed files with 175 additions and 24 deletions

View File

@@ -1,26 +1,149 @@
import { NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME } from '../../../../templating';
import { ensureKeyIsValid } from '../environment-editor';
import { checkNestedKeys, ensureKeyIsValid } from '../environment-editor';
describe('ensureKeyIsValid', () => {
it.each(['$', '$a', '$ab'])('%s should be invalid when as key begins with $', key => {
expect(ensureKeyIsValid(key)).toBe(`"${key}" cannot begin with '$' or contain a '.'`);
describe('ensureKeyIsValid()', () => {
it.each([
'$',
'$a',
'$ab',
])('"%s" should be invalid when key begins with $', key => {
expect(ensureKeyIsValid(key, false)).toBe(`"${key}" cannot begin with '$' or contain a '.'`);
});
it.each(['.', 'a.', '.a', 'a.b'])('%s should be invalid when key contains .', key => {
expect(ensureKeyIsValid(key)).toBe(`"${key}" cannot begin with '$' or contain a '.'`);
it.each([
'.',
'a.',
'.a',
'a.b',
])('"%s" should be invalid when key contains .', key => {
expect(ensureKeyIsValid(key, false)).toBe(`"${key}" cannot begin with '$' or contain a '.'`);
});
it.each(['$a.b', '$.'])('%s should be invalid when key starts with $ and contains .', key => {
expect(ensureKeyIsValid(key)).toBe(`"${key}" cannot begin with '$' or contain a '.'`);
it.each([
'$a.b',
'$.',
])('"%s" should be invalid when key starts with $ and contains .', key => {
expect(ensureKeyIsValid(key, false)).toBe(`"${key}" cannot begin with '$' or contain a '.'`);
});
const name = NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME;
it(`${name} as a key should be invalid`, () => {
expect(ensureKeyIsValid(name)).toBe(`"${name}" is a reserved key`);
it.each([
'_',
])('"%s" should be invalid when key is _', key => {
expect(ensureKeyIsValid(key, true)).toBe(`"${key}" is a reserved key`);
});
it.each(['a', 'ab', 'a$', 'a$b', 'a-b', `a${name}b`, `${name}ab`])('%s should be valid', key => {
expect(ensureKeyIsValid(key)).toBe(null);
it.each([
'_',
'a',
'ab',
'a$',
'a$b',
'a-b',
`a${NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME}b`,
`${NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME}ab`,
])('"%s" should be valid as a nested key', key => {
expect(ensureKeyIsValid(key, false)).toBe(null);
});
it.each([
'a',
'ab',
'a$',
'a$b',
'a-b',
`a${NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME}b`,
`${NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME}ab`,
])('"%s" should be valid as a root value', key => {
expect(ensureKeyIsValid(key, true)).toBe(null);
});
});
describe('checkNestedKeys()', () => {
it('should check root property and error', () => {
const obj = {
'base-url': 'https://api.insomnia.rest',
'$nes.ted': {
'path-with-hyphens': '/path-with-hyphen',
},
'ar-ray': [
'/first',
{
'second': 'second',
},
{
'third': 'third',
},
],
};
const err = checkNestedKeys(obj);
expect(err).toBe('"$nes.ted" cannot begin with \'$\' or contain a \'.\'');
});
it('should check nested property and error', () => {
const obj = {
'base-url': 'https://api.insomnia.rest',
'nested': {
'$path-wi.th-hyphens': '/path-with-hyphen',
},
'ar-ray': [
'/first',
{
'second': 'second',
},
{
'third': 'third',
},
],
};
const err = checkNestedKeys(obj);
expect(err).toBe('"$path-wi.th-hyphens" cannot begin with \'$\' or contain a \'.\'');
});
it('should check for complex objects inside array', () => {
const obj = {
'base-url': 'https://api.insomnia.rest',
'nested': {
'path-with-hyphens': '/path-with-hyphen',
},
'ar-ray': [
'/first',
{
'second': 'second',
},
{
'thi.rd': 'third',
},
],
};
const err = checkNestedKeys(obj);
expect(err).toBe('"thi.rd" cannot begin with \'$\' or contain a \'.\'');
});
it('should check nested properties and pass', () => {
const obj = {
'base-url': 'https://api.insomnia.rest',
'nested': {
'path-with-hyphens': '/path-with-hyphen',
},
'ar-ray': [
'/first',
{
'second': 'second',
},
{
'third': 'third',
},
],
};
const err = checkNestedKeys(obj);
expect(err).toBe(null);
});
});

View File

@@ -5,21 +5,52 @@ import React, { PureComponent } from 'react';
import { AUTOBIND_CFG, JSON_ORDER_PREFIX, JSON_ORDER_SEPARATOR } from '../../../common/constants';
import { NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME } from '../../../templating';
import CodeEditor from '../codemirror/code-editor';
// NeDB field names cannot begin with '$' or contain a period '.'
// Docs: https://github.com/DeNA/nedb#inserting-documents
const INVALID_NEDB_KEY_REGEX = /^\$|\./;
export const ensureKeyIsValid = (key: string): string | null => {
export const ensureKeyIsValid = (key: string, isRoot: boolean): string | null => {
if (key.match(INVALID_NEDB_KEY_REGEX)) {
return `"${key}" cannot begin with '$' or contain a '.'`;
}
if (key === NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME) {
return `"${NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME}" is a reserved key`; // verbiage WIP
if (key === NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME && isRoot) {
return `"${NUNJUCKS_TEMPLATE_GLOBAL_PROPERTY_NAME}" is a reserved key`;
}
return null;
};
/**
* Recursively check nested keys in and immediately return when an invalid key found
*/
export function checkNestedKeys(obj: Record<string, any>, isRoot = true): string | null {
for (const key in obj) {
let result: string | null = null;
// Check current key
result = ensureKeyIsValid(key, isRoot);
// Exit if necessary
if (result) {
return result;
}
// Check nested keys
if (typeof obj[key] === 'object') {
result = checkNestedKeys(obj[key], false);
}
// Exit if necessary
if (result) {
return result;
}
}
return null;
}
export interface EnvironmentInfo {
object: Record<string, any>;
propertyOrder: Record<string, any> | null;
@@ -64,14 +95,11 @@ class EnvironmentEditor extends PureComponent<Props, State> {
}
// Check for invalid key names
// TODO: these only check root properties, not nested properties
if (value && value.object) {
for (const key of Object.keys(value.object)) {
error = ensureKeyIsValid(key);
if (error) {
break;
}
// Check root and nested properties
const err = checkNestedKeys(value.object);
if (err) {
error = err;
}
}