Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions src/features/editor/TextEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,28 @@ const TextEditor = () => {
});
}, []);

const handleValidate = useCallback(
(errors: any[]) => {
// Let Monaco handle syntax highlighting errors, but don't interfere with our validation
// Monaco errors are mainly for syntax highlighting and basic JSON structure
const monacoError = errors[0]?.message;
if (monacoError && !useFile.getState().error) {
// Only set Monaco errors if we don't have custom validation errors
setError(monacoError);
}
},
[setError]
);

const handleChange = useCallback(
(newContents: string | undefined) => {
if (newContents !== undefined) {
setContents({ contents: newContents, skipUpdate: true });
}
},
[setContents]
);

return (
<StyledEditorWrapper>
<StyledWrapper>
Expand All @@ -82,8 +104,8 @@ const TextEditor = () => {
value={contents}
options={editorOptions}
onMount={handleMount}
onValidate={errors => setError(errors[0]?.message)}
onChange={contents => setContents({ contents, skipUpdate: true })}
onValidate={handleValidate}
onChange={handleChange}
loading={<LoadingOverlay visible />}
/>
</StyledWrapper>
Expand Down
13 changes: 12 additions & 1 deletion src/lib/utils/jsonAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,18 @@ export const contentToJson = (value: string, format = FileFormat.JSON): Promise<
const { parse } = await import("jsonc-parser");
const errors: ParseError[] = [];
const result = parse(value, errors);
if (errors.length > 0) JSON.parse(value);

// If there are parsing errors from jsonc-parser, fall back to strict JSON.parse
if (errors.length > 0) {
try {
const strictResult = JSON.parse(value);
return resolve(strictResult);
} catch (jsonError) {
// If both parsers fail, reject with the JSON error which is more standard
return reject(jsonError);
}
}

return resolve(result);
}

Expand Down
34 changes: 26 additions & 8 deletions src/store/useFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,17 @@ const isURL = (value: string) => {
);
};

const debouncedUpdateJson = debounce((value: unknown) => {
useGraph.getState().setLoading(true);
useJson.getState().setJson(JSON.stringify(value, null, 2));
const debouncedUpdateJson = debounce((value: unknown, hasError: boolean) => {
if (!hasError) {
useGraph.getState().setLoading(true);
useJson.getState().setJson(JSON.stringify(value, null, 2));
}
}, 800);

const useFile = create<FileStates & JsonActions>()((set, get) => ({
...initialStates,
clear: () => {
set({ contents: "" });
set({ contents: "", error: null, hasChanges: false });
useJson.getState().clear();
},
setJsonSchema: jsonSchema => set({ jsonSchema }),
Expand Down Expand Up @@ -136,12 +138,14 @@ const useFile = create<FileStates & JsonActions>()((set, get) => ({
try {
set({
...(contents && { contents }),
error: null,
error: null, // Clear any previous errors when new content is set
hasChanges,
format: format ?? get().format,
});

const isFetchURL = window.location.href.includes("?");

// Try to parse the JSON to validate it
const json = await contentToJson(get().contents, get().format);

if (!useConfig.getState().liveTransformEnabled && skipUpdate) return;
Expand All @@ -152,10 +156,24 @@ const useFile = create<FileStates & JsonActions>()((set, get) => ({
set({ hasChanges: true });
}

debouncedUpdateJson(json);
// Only update JSON if there's no error
debouncedUpdateJson(json, false);
} catch (error: any) {
if (error?.mark?.snippet) return set({ error: error.mark.snippet });
if (error?.message) set({ error: error.message });
// Handle validation errors properly
let errorMessage = "Invalid format";

if (error?.mark?.snippet) {
errorMessage = error.mark.snippet;
} else if (error?.message) {
errorMessage = error.message;
} else if (typeof error === "string") {
errorMessage = error;
}

set({ error: errorMessage });

// Don't update JSON when there's an error, and stop loading states
debouncedUpdateJson({}, true);
useJson.setState({ loading: false });
useGraph.setState({ loading: false });
}
Expand Down