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
352 changes: 146 additions & 206 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/utils/DiagnosticError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { GraphQLError, Location, Source } from "graphql";
import * as ts from "typescript";
import { Result } from "./Result";

type FixableDiagnostic = ts.Diagnostic & {
export type FixableDiagnostic = ts.Diagnostic & {
fix?: ts.CodeFixAction;
};
export type FixableDiagnosticWithLocation = ts.DiagnosticWithLocation & {
Expand Down
17 changes: 8 additions & 9 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@
},
"dependencies": {
"@algolia/client-search": "^4.17.0",
"@codemirror/commands": "^6.2.2",
"@codemirror/lang-javascript": "^6.1.4",
"@codemirror/language": "^6.6.0",
"@codemirror/lint": "^6.2.0",
"@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.9.3",
"@docusaurus/core": "3.4.0",
"@docusaurus/preset-classic": "3.4.0",
"@docusaurus/theme-classic": "3.4.0",
Expand All @@ -36,12 +30,11 @@
"@types/react": "^18",
"@typescript/vfs": "1.6.0",
"clsx": "^1.2.1",
"cm6-graphql": "^0.0.3",
"glob": "^9.3.4",
"graphql": "^16.6.0",
"graphql-language-service": "^5.1.2",
"grats": "workspace:*",
"lz-string": "^1.5.0",
"monaco-editor": "^0.51.0",
"netlify-cli": "^17.0.1",
"path-browserify": "^1.0.1",
"prettier": "^2.8.7",
Expand All @@ -50,6 +43,7 @@
"raw-loader": "^4.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-monaco-editor": "^0.55.0",
"react-redux": "^8.0.5",
"redux": "^4.2.1",
"reselect": "^4.1.7",
Expand All @@ -59,9 +53,14 @@
"@docusaurus/module-type-aliases": "3.4.0",
"@docusaurus/tsconfig": "3.4.0",
"@types/react": "^18.2.29",
"css-loader": "^7.1.2",
"file-loader": "^6.2.0",
"graphql-relay": "^0.10.0",
"monaco-editor-webpack-plugin": "^7.1.0",
"style-loader": "^4.0.0",
"ts-node": "^10.9.2",
"typescript": "5.5.4"
"typescript": "5.5.4",
"worker-loader": "^3.0.8"
},
"browserslist": {
"production": [
Expand Down
30 changes: 30 additions & 0 deletions website/plugins/monaco-editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");

module.exports = function (_context, _options) {
return {
name: "monaco-editor",
configureWebpack(_config, _isServer) {
return {
module: {
rules: [
/*
{
test: /\.ttf$/,
use: ["file-loader"],
},
*/
{
test: /\.ttf$/,
type: "asset/resource",
},
],
},
plugins: [
new MonacoWebpackPlugin({
languages: ["typescript", "graphql"],
}),
],
};
},
};
};
21 changes: 21 additions & 0 deletions website/plugins/webpack.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");

module.exports = function (_context, _options) {
return {
name: "custom-docusaurus-plugin",
Expand All @@ -11,6 +13,25 @@ module.exports = function (_context, _options) {
node: {
__dirname: "mock",
},
module: {
rules: [
/*
{
test: /monaco.*\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.ttf$/,
type: "asset/resource",
},
*/
],
},
plugins: [
new MonacoWebpackPlugin({
languages: ["typescript", "graphql"],
}),
],
};
},
};
Expand Down
11 changes: 11 additions & 0 deletions website/src/components/MonacoPlayground/BothEditors.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import InputEditor from "./InputEditor";
import OutputEditor from "./OutputEditor";

export default function BothEditors() {
return (
<>
<InputEditor />
<OutputEditor />
</>
);
}
92 changes: 92 additions & 0 deletions website/src/components/MonacoPlayground/InputEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React, { useEffect, useState } from "react";
import store, { getDoc, useAppSelector } from "../PlaygroundFeatures/store";
import { monaco as Monaco } from "react-monaco-editor";
import { getDiagnostics } from "../PlaygroundFeatures/gratsStoreBindings";
import {
codeActionsForDiagnostics,
resolveDiagnosticLocation,
} from "./diagnostics";
import MonacoEditor from "./MonacoEditor";

export default function InputEditor() {
const diagnostics = useAppSelector(getDiagnostics);
const [editor, setEditor] =
useState<Monaco.editor.IStandaloneCodeEditor | null>(null);
const [monaco, setMonaco] = useState<typeof Monaco | null>(null);
const doc = useAppSelector(getDoc);

useEffect(() => {
if (editor == null || monaco == null) {
return;
}
if (diagnostics == null) {
return;
}
const model = editor.getModel();
if (model == null) {
return;
}
const text = editor.getValue();
const markers = diagnostics.map((diagnostic) => {
const { startLineNumber, startColumn, endLineNumber, endColumn } =
resolveDiagnosticLocation(text, diagnostic.start, diagnostic.length);

return {
severity: monaco.MarkerSeverity.Error,
message: diagnostic.messageText,
startLineNumber,
startColumn,
endLineNumber,
endColumn,
};
});
monaco.editor.setModelMarkers(model, "owner", markers);
const disposable = monaco.languages.registerCodeActionProvider(
"typescript",
{
provideCodeActions: (model, _range, _context, _token) => {
const actions = codeActionsForDiagnostics(text, model, diagnostics);
return {
actions: actions,
dispose: () => {
// noop
},
};
},
},
);

return () => {
disposable.dispose();
};
}, [editor, monaco, diagnostics]);

const newDoc = debounce((value) => {
store.dispatch({ type: "NEW_DOCUMENT_TEXT", value });
});

return (
<MonacoEditor
language="typescript"
value={doc}
onChange={(value: string) => {
newDoc(value);
}}
editorDidMount={(editor, monaco) => {
setEditor(editor);
setMonaco(monaco);
editor.focus();
}}
/>
);
}

function debounce(func, wait = 500) {
let timeout;
return function (...args) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const context = this;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait);
};
}
81 changes: 81 additions & 0 deletions website/src/components/MonacoPlayground/MonacoEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useRef, useState, useEffect } from "react";
import MonacoEditorImpl, { MonacoEditorProps } from "react-monaco-editor";
import { useColorMode } from "@docusaurus/theme-common";

export default function MonacoEditor(props: MonacoEditorProps) {
const { colorMode } = useColorMode();

function onEditorWillMount(monaco) {
const vsDarkTheme = {
base: "vs-dark",
inherit: true,
rules: [{ background: "121212" }],
colors: {
"editor.background": "#121212",
},
};

monaco.editor.defineTheme("vs-dark", vsDarkTheme);

if (props.editorWillMount) {
props.editorWillMount(monaco);
}
}

return (
<div style={{ height: "100%", width: "100%", overflow: "hidden" }}>
<ResizableComponent>
{({ width, height }) => (
<MonacoEditorImpl
{...props}
width={width}
height={height}
options={{
...(props.options ?? {}),
minimap: { enabled: false },
}}
// @ts-ignore
onEditorWillMount={onEditorWillMount}
editorDidMount={(editor, monaco) => {
if (props.editorDidMount) {
props.editorDidMount(editor, monaco);
}
}}
theme={colorMode === "dark" ? "vs-dark" : "vs-light"}
/>
)}
</ResizableComponent>
</div>
);
}

const ResizableComponent = ({ children }) => {
const ref = useRef(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });

useEffect(() => {
const updateDimensions = () => {
if (ref.current) {
setDimensions({
// @ts-ignore
width: ref.current.offsetWidth,
// @ts-ignore
height: ref.current.offsetHeight,
});
}
};

updateDimensions(); // Initial measurement
window.addEventListener("resize", updateDimensions); // Update on window resize

return () => {
window.removeEventListener("resize", updateDimensions); // Cleanup
};
}, []);

return (
<div ref={ref} style={{ width: "100%", height: "100%" }}>
{children({ ...dimensions })}
</div>
);
};
62 changes: 62 additions & 0 deletions website/src/components/MonacoPlayground/OutputEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from "react";
import { getOutputOption, useAppSelector } from "../PlaygroundFeatures/store";
import {
getErrorText,
getSchemaText,
getTsSchema,
} from "../PlaygroundFeatures/gratsStoreBindings";
import MonacoEditor from "../MonacoPlayground/MonacoEditor";

/**
* If there are errors, show the error message as plain text.
*
* If the output option is "sdl", show the SDL.
* If the output option is "typescript", show the generated graphql-js implementation.
*/
export default function OutputEditor() {
const errorText = useAppSelector(getErrorText);
const outputOptions = useAppSelector(getOutputOption);
if (errorText) {
return <ErrorsEditor errorText={errorText} />;
}
switch (outputOptions) {
case "sdl":
return <SchemaEditor />;
case "typescript":
return <TsSchemaEditor />;
default:
return null;
}
}

function ErrorsEditor({ errorText }) {
return (
<MonacoEditor
value={errorText}
options={{ readOnly: true, wordWrap: "on" }}
language="plaintext"
/>
);
}

function TsSchemaEditor() {
const tsSchema = useAppSelector(getTsSchema);
return (
<MonacoEditor
value={tsSchema ?? ""}
options={{ readOnly: true }}
language="typescript"
/>
);
}

function SchemaEditor() {
const schemaText = useAppSelector(getSchemaText);
return (
<MonacoEditor
value={schemaText ?? ""}
options={{ readOnly: true }}
language="graphql"
/>
);
}
Loading