diff --git a/apps/studio/components/grid/components/editor/JsonEditor.tsx b/apps/studio/components/grid/components/editor/JsonEditor.tsx index 1d6de055297..4423413f064 100644 --- a/apps/studio/components/grid/components/editor/JsonEditor.tsx +++ b/apps/studio/components/grid/components/editor/JsonEditor.tsx @@ -5,7 +5,7 @@ import { IconMaximize, Popover } from 'ui' import { BlockKeys, MonacoEditor, NullValue } from 'components/grid/components/common' import { useTrackedState } from 'components/grid/store' -import { prettifyJSON, tryParseJson } from 'lib/helpers' +import { prettifyJSON, tryParseJson, removeJSONTrailingComma } from 'lib/helpers' import { isNil } from 'lodash' interface JsonEditorProps @@ -36,7 +36,8 @@ export const JsonEditor = ({ }, []) const saveChanges = useCallback((newValue: string | null) => { - if (newValue !== value) commitChange(newValue) + const updatedValue = newValue !== null ? removeJSONTrailingComma(newValue) : newValue + if (updatedValue !== value) commitChange(newValue) }, []) const onChange = (_value: string | undefined) => { diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/JsonEditor.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/JsonEditor.tsx index 9b7340ddc5e..28cf419760d 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/JsonEditor.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/JsonEditor/JsonEditor.tsx @@ -3,7 +3,7 @@ import { useEffect, useState } from 'react' import { Button, IconAlignLeft, SidePanel } from 'ui' import TwoOptionToggle from 'components/ui/TwoOptionToggle' -import { minifyJSON, prettifyJSON, tryParseJson } from 'lib/helpers' +import { minifyJSON, prettifyJSON, tryParseJson, removeJSONTrailingComma } from 'lib/helpers' import toast from 'react-hot-toast' import ActionBar from '../../ActionBar' import DrilldownViewer from './DrilldownViewer' @@ -42,7 +42,8 @@ const JsonEdit = ({ const validateJSON = async (resolve: () => void) => { try { - const minifiedJSON = minifyJSON(jsonStr) + const newJsonStr = removeJSONTrailingComma(jsonStr) + const minifiedJSON = minifyJSON(newJsonStr) if (onSaveJSON) onSaveJSON(minifiedJSON, resolve) } catch (error: any) { resolve() diff --git a/apps/studio/lib/helpers.ts b/apps/studio/lib/helpers.ts index 82354e42e9b..a82ced07660 100644 --- a/apps/studio/lib/helpers.ts +++ b/apps/studio/lib/helpers.ts @@ -42,6 +42,14 @@ export const prettifyJSON = (minifiedJSON: string) => { } } +export const removeJSONTrailingComma = (jsonString: string) => { + /** + * Remove trailing commas: Delete any comma immediately preceding the closing brace '}' or + * bracket ']' using a regular expression. + */ + return jsonString.replace(/,\s*(?=[\}\]])/g, '') +} + export const uuidv4 = () => { return _uuidV4() } diff --git a/apps/studio/tests/components/Editor/RemoveJSONTrailingComma.utils.test.js b/apps/studio/tests/components/Editor/RemoveJSONTrailingComma.utils.test.js new file mode 100644 index 00000000000..61a84165c3b --- /dev/null +++ b/apps/studio/tests/components/Editor/RemoveJSONTrailingComma.utils.test.js @@ -0,0 +1,36 @@ +import { removeJSONTrailingComma } from '/apps/studio/lib/helpers.ts' + +describe('removeJSONTrailingComma', () => { + it('should handle an empty object', () => { + const jsonString = '{}' + expect(removeJSONTrailingComma(jsonString)).toEqual(jsonString) + }) + + it('should handle an empty array', () => { + const jsonString = '[]' + expect(removeJSONTrailingComma(jsonString)).toEqual(jsonString) + }) + + it('should handle a JSON string without a trailing comma', () => { + const jsonString = '{"name": "John", "age": 25}' + expect(removeJSONTrailingComma(jsonString)).toEqual(jsonString) + }) + + it('should remove a trailing comma for JSON object', () => { + const jsonString = '{"name": "John", "age": 25,}' + const expectedOutput = '{"name": "John", "age": 25}' + expect(removeJSONTrailingComma(jsonString)).toEqual(expectedOutput) + }) + + it('should remove a trailing commas in an array of objects', () => { + const jsonString = '[{"fruit1": "apple","fruit2": "banana",}]' + const expectedOutput = '[{"fruit1": "apple","fruit2": "banana"}]' + expect(removeJSONTrailingComma(jsonString)).toEqual(expectedOutput) + }) + + it('should remove all trailing commas in an array of objects', () => { + const jsonString = '[{"fruit1": "apple","fruit2": "banana",},]' + const expectedOutput = '[{"fruit1": "apple","fruit2": "banana"}]' + expect(removeJSONTrailingComma(jsonString)).toEqual(expectedOutput) + }) +})