Skip to content
Merged
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
11 changes: 11 additions & 0 deletions .changeset/honest-clouds-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'monaco-graphql': patch
---

remove unused types

- `BaseSchemaConfig`
- `IDisposable`
- `JSONDiagnosticOptions`
- `IEvent`
- `FilePointer`
6 changes: 6 additions & 0 deletions .changeset/kind-timers-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@graphiql/react': minor
'graphiql': major
---

support `externalFragments` prop and remove `validationRules` prop
1 change: 1 addition & 0 deletions docs/migration/graphiql-5.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
- Removed props
- `keyMap`. To use Vim or Emacs keybindings in Monaco, you can use community plugins. Monaco Vim: https://github.com/brijeshb42/monaco-vim. Monaco Emacs: https://github.com/aioutecism/monaco-emacs
- `readOnly`
- `validationRules`. Use custom GraphQL worker, see https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql#custom-webworker-for-passing-non-static-config-to-worker.'
74 changes: 30 additions & 44 deletions packages/graphiql-react/src/components/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ export const GraphiQLProvider: FC<GraphiQLProviderProps> = ({
'The `GraphiQLProvider` component requires a `fetcher` function to be passed as prop.',
);
}
// @ts-expect-error -- runtime check
if (props.validationRules) {
throw new Error(
"`validationRules` isn't yet implemented, submit an issue in GitHub",
'`validationRules` prop is removed. Use custom GraphQL worker, see https://github.com/graphql/graphiql/tree/main/packages/monaco-graphql#custom-webworker-for-passing-non-static-config-to-worker.',
);
}
return (
Expand All @@ -91,7 +92,6 @@ const InnerGraphiQLProvider: FC<InnerGraphiQLProviderProps> = ({
onEditOperationName,
onTabChange,
shouldPersistHeaders = false,
validationRules = [],
onCopyQuery,
onPrettifyQuery = DEFAULT_PRETTIFY_QUERY,

Expand Down Expand Up @@ -143,14 +143,42 @@ const InnerGraphiQLProvider: FC<InnerGraphiQLProviderProps> = ({
? storage.get(PERSIST_HEADERS_STORAGE_KEY) === 'true'
: shouldPersistHeaders;

const $externalFragments = (() => {
const map = new Map<string, FragmentDefinitionNode>();
if (Array.isArray(externalFragments)) {
for (const fragment of externalFragments) {
map.set(fragment.name.value, fragment);
}
} else if (typeof externalFragments === 'string') {
visit(parse(externalFragments, {}), {
FragmentDefinition(fragment) {
map.set(fragment.name.value, fragment);
},
});
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime check
} else if (externalFragments) {
throw new TypeError(
'The `externalFragments` prop must either be a string that contains the fragment definitions in SDL or a list of FragmentDefinitionNode objects.',
);
}
return map;
})();

const store = create<AllSlices>((...args) => ({
...createEditorSlice({
activeTabIndex,
defaultHeaders,
defaultQuery,
externalFragments: $externalFragments,
initialHeaders: headers ?? defaultHeaders ?? '',
initialQuery:
query ?? (activeTabIndex === 0 ? tabs[0]!.query : null) ?? '',
initialResponse: response,
initialVariables: variables ?? '',
onCopyQuery,
onEditOperationName,
onPrettifyQuery,
onTabChange,
shouldPersistHeaders: $shouldPersistHeaders,
tabs,
})(...args),
Expand All @@ -174,48 +202,6 @@ const InnerGraphiQLProvider: FC<InnerGraphiQLProviderProps> = ({
// }
// }, [shouldPersistHeaders]);

const $externalFragments = (() => {
const map = new Map<string, FragmentDefinitionNode>();
if (Array.isArray(externalFragments)) {
for (const fragment of externalFragments) {
map.set(fragment.name.value, fragment);
}
} else if (typeof externalFragments === 'string') {
visit(parse(externalFragments, {}), {
FragmentDefinition(fragment) {
map.set(fragment.name.value, fragment);
},
});
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime check
} else if (externalFragments) {
throw new Error(
'The `externalFragments` prop must either be a string that contains the fragment definitions in SDL or a list of FragmentDefinitionNode objects.',
);
}
return map;
})();
// Editor sync
useEffect(() => {
storeRef.current.setState({
defaultHeaders,
defaultQuery,
externalFragments: $externalFragments,
onCopyQuery,
onEditOperationName,
onPrettifyQuery,
onTabChange,
validationRules,
});
}, [
$externalFragments,
onTabChange,
onEditOperationName,
defaultQuery,
defaultHeaders,
validationRules,
onCopyQuery,
onPrettifyQuery,
]);
// Execution sync
useEffect(() => {
storeRef.current.setState({
Expand Down
64 changes: 29 additions & 35 deletions packages/graphiql-react/src/components/query-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const QueryEditor: FC<QueryEditorProps> = ({
copyQuery,
prettifyEditors,
mergeQuery,
externalFragments,
} = useGraphiQL(
pick(
'initialQuery',
Expand All @@ -78,6 +79,7 @@ export const QueryEditor: FC<QueryEditorProps> = ({
'copyQuery',
'prettifyEditors',
'mergeQuery',
'externalFragments',
),
);
const storage = useStorage();
Expand Down Expand Up @@ -258,24 +260,27 @@ export const QueryEditor: FC<QueryEditorProps> = ({
if (!schema) {
return;
}
// eslint-disable-next-line no-console
console.log('setting setSchemaConfig');
MONACO_GRAPHQL_API.setSchemaConfig([{ uri: 'schema.graphql', schema }]);
MONACO_GRAPHQL_API.setExternalFragmentDefinitions([
...externalFragments.values(),
]);
if (!referencePlugin) {
return;
}

let currentSchemaReference: SchemaReference | null = null;

const disposables = [
languages.registerDefinitionProvider('graphql', {
provideDefinition(model, p, _token) {
const graphQLPosition = toGraphQLPosition(p);
provideDefinition(model, position, _token) {
const graphQLPosition = toGraphQLPosition(position);
const context = getContextAtPosition(
model.getValue(),
graphQLPosition,
schema,
);
if (!context) {
return null;
return;
}
const { typeInfo, token } = context;
const { kind, step } = token.state;
Expand All @@ -294,47 +299,36 @@ export const QueryEditor: FC<QueryEditorProps> = ({
typeInfo.type &&
'description' in typeInfo.type)
) {
return {
uri: model.uri,
range: new Range(p.lineNumber, p.column, p.lineNumber, p.column),
};
currentSchemaReference = { kind, typeInfo };
const { lineNumber, column } = position;
const range = new Range(lineNumber, column, lineNumber, column);
return [{ uri: model.uri, range }];
}

return null;
currentSchemaReference = null;
},
}),
languages.registerReferenceProvider('graphql', {
provideReferences(model, p, _context, _token) {
const graphQLPosition = toGraphQLPosition(p);
const context = getContextAtPosition(
model.getValue(),
graphQLPosition,
schema,
);
if (!context) {
return null;
provideReferences(model, { lineNumber, column }, _context, _token) {
if (!currentSchemaReference) {
return;
}
const { typeInfo, token } = context;
const { kind } = token.state;
if (!kind) {
return null;
}

setVisiblePlugin(referencePlugin);
setSchemaReference({ kind, typeInfo });
onClickReferenceRef.current?.({ kind, typeInfo });
setSchemaReference(currentSchemaReference);
onClickReferenceRef.current?.(currentSchemaReference);

return [
{
uri: model.uri,
range: new Range(p.lineNumber, p.column, p.lineNumber, p.column),
},
];
const range = new Range(lineNumber, column, lineNumber, column);
return [{ uri: model.uri, range }];
},
}),
];
return cleanupDisposables(disposables);
}, [schema, referencePlugin, setSchemaReference, setVisiblePlugin]);
}, [
schema,
referencePlugin,
setSchemaReference,
setVisiblePlugin,
externalFragments,
]);

return (
<div
Expand Down
36 changes: 11 additions & 25 deletions packages/graphiql-react/src/stores/editor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { StateCreator } from 'zustand';
import type {
FragmentDefinitionNode,
ValidationRule,
OperationDefinitionNode,
DocumentNode,
} from 'graphql';
Expand All @@ -21,7 +20,6 @@ import {
STORAGE_KEY as STORAGE_KEY_TABS,
} from '../utility/tabs';
import { AllSlices, MonacoEditor } from '../types';
import { DEFAULT_PRETTIFY_QUERY } from '../constants';
import { debounce, formatJSONC } from '../utility';
import { print } from 'graphql';

Expand Down Expand Up @@ -120,7 +118,7 @@ export interface EditorSlice extends TabsState {
initialVariables: string;

/**
* A map of fragment definitions using the fragment name as key which are
* A map of fragment definitions using the fragment name as a key which are
* made available to include in the query.
*/
externalFragments: Map<string, FragmentDefinitionNode>;
Expand All @@ -141,7 +139,7 @@ export interface EditorSlice extends TabsState {
* - The `query` prop
* - The value persisted in storage
* These default contents will only be used for the first tab. When opening
* more tabs the query editor will start out empty.
* more tabs, the query editor will start out empty.
*/
defaultQuery?: string;

Expand All @@ -165,13 +163,7 @@ export interface EditorSlice extends TabsState {
onTabChange?(tabState: TabsState): void;

/**
* A list of custom validation rules that are run in addition to the rules
* provided by the GraphQL spec.
*/
validationRules: ValidationRule[];

/**
* Headers to be set when opening a new tab
* Headers to be set when opening a new tab.
*/
defaultHeaders?: string;

Expand Down Expand Up @@ -291,12 +283,7 @@ export interface EditorProps
* @default false
*/
shouldPersistHeaders?: boolean;
/**
* This prop accepts custom validation rules for GraphQL documents that are
* run against the contents of the query editor (in addition to the rules
* that are specified in the GraphQL spec).
*/
validationRules?: ValidationRule[];

/**
* This prop can be used to set the contents of the variables editor. Every
* time this prop changes, the contents of the variables editor are replaced.
Expand All @@ -317,6 +304,13 @@ type CreateEditorSlice = (
| 'initialVariables'
| 'initialHeaders'
| 'initialResponse'
| 'onEditOperationName'
| 'externalFragments'
| 'onTabChange'
| 'defaultQuery'
| 'defaultHeaders'
| 'onPrettifyQuery'
| 'onCopyQuery'
>,
) => StateCreator<AllSlices, [], [], EditorSlice>;

Expand Down Expand Up @@ -364,7 +358,6 @@ export const createEditorSlice: CreateEditorSlice = initial => (set, get) => {

return {
...initial,

addTab() {
set(current => {
const { defaultQuery, defaultHeaders, onTabChange, storeTabs } = get();
Expand Down Expand Up @@ -476,13 +469,6 @@ export const createEditorSlice: CreateEditorSlice = initial => (set, get) => {
set({ shouldPersistHeaders: persist });
storage.set(PERSIST_HEADERS_STORAGE_KEY, persist.toString());
},
onEditOperationName: undefined,
externalFragments: null!,
onTabChange: undefined,
defaultQuery: undefined,
defaultHeaders: undefined,
validationRules: null!,
onPrettifyQuery: DEFAULT_PRETTIFY_QUERY,
storeTabs({ tabs, activeTabIndex }) {
const { storage } = storageStore.getState();
const { shouldPersistHeaders } = get();
Expand Down
3 changes: 2 additions & 1 deletion packages/graphiql-react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import {
PluginSlice,
SchemaSlice,
} from './stores';
import { RuleKind } from 'graphql-language-service';

export type EditorProps = ComponentPropsWithoutRef<'div'>;

export interface SchemaReference {
kind: string;
kind: RuleKind;
typeInfo: AllTypeInfo;
}

Expand Down
Loading
Loading