graphql-language-service
Advanced tools
Comparing version 5.0.7-canary-0ac0349e.0 to 5.1.0
@@ -11,2 +11,4 @@ import { FragmentDefinitionNode, GraphQLDirective, GraphQLSchema } from 'graphql'; | ||
schema?: GraphQLSchema; | ||
uri?: string; | ||
mode?: GraphQLDocumentMode; | ||
}; | ||
@@ -21,3 +23,7 @@ export declare function getAutocompleteSuggestions(schema: GraphQLSchema, queryText: string, cursor: IPosition, contextToken?: ContextTokenForCodeMirror, fragmentDefs?: FragmentDefinitionNode[] | string, options?: AutocompleteSuggestionOptions): Array<CompletionItem>; | ||
export declare function getTypeInfo(schema: GraphQLSchema, tokenState: State): AllTypeInfo; | ||
export declare enum GraphQLDocumentMode { | ||
TYPE_SYSTEM = "TYPE_SYSTEM", | ||
EXECUTABLE = "EXECUTABLE" | ||
} | ||
export {}; | ||
//# sourceMappingURL=getAutocompleteSuggestions.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getTypeInfo = exports.canUseDirective = exports.runOnlineParser = exports.getTokenAtPosition = exports.getFragmentDefinitions = exports.getVariableCompletions = exports.getAutocompleteSuggestions = exports.SuggestionCommand = void 0; | ||
const vscode_languageserver_types_1 = require("vscode-languageserver-types"); | ||
exports.GraphQLDocumentMode = exports.getTypeInfo = exports.canUseDirective = exports.runOnlineParser = exports.getTokenAtPosition = exports.getFragmentDefinitions = exports.getVariableCompletions = exports.getAutocompleteSuggestions = exports.SuggestionCommand = void 0; | ||
const graphql_1 = require("graphql"); | ||
const types_1 = require("../types"); | ||
const graphql_2 = require("graphql"); | ||
@@ -29,7 +29,49 @@ const parser_1 = require("../parser"); | ||
}; | ||
const typeSystemKinds = [ | ||
graphql_1.Kind.SCHEMA_DEFINITION, | ||
graphql_1.Kind.OPERATION_TYPE_DEFINITION, | ||
graphql_1.Kind.SCALAR_TYPE_DEFINITION, | ||
graphql_1.Kind.OBJECT_TYPE_DEFINITION, | ||
graphql_1.Kind.INTERFACE_TYPE_DEFINITION, | ||
graphql_1.Kind.UNION_TYPE_DEFINITION, | ||
graphql_1.Kind.ENUM_TYPE_DEFINITION, | ||
graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION, | ||
graphql_1.Kind.DIRECTIVE_DEFINITION, | ||
graphql_1.Kind.SCHEMA_EXTENSION, | ||
graphql_1.Kind.SCALAR_TYPE_EXTENSION, | ||
graphql_1.Kind.OBJECT_TYPE_EXTENSION, | ||
graphql_1.Kind.INTERFACE_TYPE_EXTENSION, | ||
graphql_1.Kind.UNION_TYPE_EXTENSION, | ||
graphql_1.Kind.ENUM_TYPE_EXTENSION, | ||
graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION, | ||
]; | ||
const hasTypeSystemDefinitions = (sdl) => { | ||
let hasTypeSystemDef = false; | ||
if (sdl) { | ||
try { | ||
(0, graphql_2.visit)((0, graphql_2.parse)(sdl), { | ||
enter(node) { | ||
if (node.kind === 'Document') { | ||
return; | ||
} | ||
if (typeSystemKinds.includes(node.kind)) { | ||
hasTypeSystemDef = true; | ||
return graphql_2.BREAK; | ||
} | ||
return false; | ||
}, | ||
}); | ||
} | ||
catch (_a) { | ||
return hasTypeSystemDef; | ||
} | ||
} | ||
return hasTypeSystemDef; | ||
}; | ||
function getAutocompleteSuggestions(schema, queryText, cursor, contextToken, fragmentDefs, options) { | ||
var _a; | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j; | ||
const opts = Object.assign(Object.assign({}, options), { schema }); | ||
const token = contextToken || getTokenAtPosition(queryText, cursor); | ||
const state = token.state.kind === 'Invalid' ? token.state.prevState : token.state; | ||
const mode = (options === null || options === void 0 ? void 0 : options.mode) || getDocumentMode(queryText, options === null || options === void 0 ? void 0 : options.uri); | ||
if (!state) { | ||
@@ -42,13 +84,65 @@ return []; | ||
if (kind === parser_1.RuleKinds.DOCUMENT) { | ||
return (0, autocompleteUtils_1.hintList)(token, [ | ||
{ label: 'query', kind: vscode_languageserver_types_1.CompletionItemKind.Function }, | ||
{ label: 'mutation', kind: vscode_languageserver_types_1.CompletionItemKind.Function }, | ||
{ label: 'subscription', kind: vscode_languageserver_types_1.CompletionItemKind.Function }, | ||
{ label: 'fragment', kind: vscode_languageserver_types_1.CompletionItemKind.Function }, | ||
{ label: '{', kind: vscode_languageserver_types_1.CompletionItemKind.Constructor }, | ||
]); | ||
if (mode === GraphQLDocumentMode.TYPE_SYSTEM) { | ||
return getSuggestionsForTypeSystemDefinitions(token); | ||
} | ||
return getSuggestionsForExecutableDefinitions(token); | ||
} | ||
if (kind === parser_1.RuleKinds.EXTEND_DEF) { | ||
return getSuggestionsForExtensionDefinitions(token); | ||
} | ||
if (((_b = (_a = state.prevState) === null || _a === void 0 ? void 0 : _a.prevState) === null || _b === void 0 ? void 0 : _b.kind) === parser_1.RuleKinds.EXTENSION_DEFINITION && | ||
state.name) { | ||
return (0, autocompleteUtils_1.hintList)(token, []); | ||
} | ||
if (((_c = state.prevState) === null || _c === void 0 ? void 0 : _c.kind) === graphql_1.Kind.SCALAR_TYPE_EXTENSION) { | ||
return (0, autocompleteUtils_1.hintList)(token, Object.values(schema.getTypeMap()) | ||
.filter(graphql_1.isScalarType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: types_1.CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_d = state.prevState) === null || _d === void 0 ? void 0 : _d.kind) === graphql_1.Kind.OBJECT_TYPE_EXTENSION) { | ||
return (0, autocompleteUtils_1.hintList)(token, Object.values(schema.getTypeMap()) | ||
.filter(type => (0, graphql_1.isObjectType)(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: types_1.CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_e = state.prevState) === null || _e === void 0 ? void 0 : _e.kind) === graphql_1.Kind.INTERFACE_TYPE_EXTENSION) { | ||
return (0, autocompleteUtils_1.hintList)(token, Object.values(schema.getTypeMap()) | ||
.filter(graphql_1.isInterfaceType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: types_1.CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_f = state.prevState) === null || _f === void 0 ? void 0 : _f.kind) === graphql_1.Kind.UNION_TYPE_EXTENSION) { | ||
return (0, autocompleteUtils_1.hintList)(token, Object.values(schema.getTypeMap()) | ||
.filter(graphql_1.isUnionType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: types_1.CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_g = state.prevState) === null || _g === void 0 ? void 0 : _g.kind) === graphql_1.Kind.ENUM_TYPE_EXTENSION) { | ||
return (0, autocompleteUtils_1.hintList)(token, Object.values(schema.getTypeMap()) | ||
.filter(type => (0, graphql_1.isEnumType)(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: types_1.CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_h = state.prevState) === null || _h === void 0 ? void 0 : _h.kind) === graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION) { | ||
return (0, autocompleteUtils_1.hintList)(token, Object.values(schema.getTypeMap()) | ||
.filter(graphql_1.isInputObjectType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: types_1.CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (kind === parser_1.RuleKinds.IMPLEMENTS || | ||
(kind === parser_1.RuleKinds.NAMED_TYPE && | ||
((_a = state.prevState) === null || _a === void 0 ? void 0 : _a.kind) === parser_1.RuleKinds.IMPLEMENTS)) { | ||
((_j = state.prevState) === null || _j === void 0 ? void 0 : _j.kind) === parser_1.RuleKinds.IMPLEMENTS)) { | ||
return getSuggestionsForImplements(token, state, schema, queryText, typeInfo); | ||
@@ -73,3 +167,3 @@ } | ||
documentation: (_a = argDef.description) !== null && _a !== void 0 ? _a : undefined, | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Variable, | ||
kind: types_1.CompletionItemKind.Variable, | ||
type: argDef.type, | ||
@@ -85,4 +179,4 @@ }); | ||
const completionKind = kind === parser_1.RuleKinds.OBJECT_VALUE | ||
? vscode_languageserver_types_1.CompletionItemKind.Value | ||
: vscode_languageserver_types_1.CompletionItemKind.Field; | ||
? types_1.CompletionItemKind.Value | ||
: types_1.CompletionItemKind.Field; | ||
return (0, autocompleteUtils_1.hintList)(token, objectFields.map(field => { | ||
@@ -122,2 +216,24 @@ var _a; | ||
} | ||
const unwrappedState = unwrapType(state); | ||
if ((mode === GraphQLDocumentMode.TYPE_SYSTEM && | ||
!unwrappedState.needsAdvance && | ||
state.kind === parser_1.RuleKinds.NAMED_TYPE) || | ||
state.kind === parser_1.RuleKinds.LIST_TYPE) { | ||
if (unwrappedState.kind === parser_1.RuleKinds.FIELD_DEF) { | ||
return (0, autocompleteUtils_1.hintList)(token, Object.values(schema.getTypeMap()) | ||
.filter(type => (0, graphql_1.isOutputType)(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: types_1.CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (unwrappedState.kind === parser_1.RuleKinds.INPUT_VALUE_DEF) { | ||
return (0, autocompleteUtils_1.hintList)(token, Object.values(schema.getTypeMap()) | ||
.filter(type => (0, graphql_2.isInputType)(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: types_1.CompletionItemKind.Function, | ||
}))); | ||
} | ||
} | ||
if ((kind === parser_1.RuleKinds.VARIABLE_DEFINITION && step === 2) || | ||
@@ -157,2 +273,32 @@ (kind === parser_1.RuleKinds.LIST_TYPE && step === 1) || | ||
}; | ||
function getSuggestionsForTypeSystemDefinitions(token) { | ||
return (0, autocompleteUtils_1.hintList)(token, [ | ||
{ label: 'extend', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'type', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'interface', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'union', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'input', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'scalar', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'schema', kind: types_1.CompletionItemKind.Function }, | ||
]); | ||
} | ||
function getSuggestionsForExecutableDefinitions(token) { | ||
return (0, autocompleteUtils_1.hintList)(token, [ | ||
{ label: 'query', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'mutation', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'subscription', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'fragment', kind: types_1.CompletionItemKind.Function }, | ||
{ label: '{', kind: types_1.CompletionItemKind.Constructor }, | ||
]); | ||
} | ||
function getSuggestionsForExtensionDefinitions(token) { | ||
return (0, autocompleteUtils_1.hintList)(token, [ | ||
{ label: 'type', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'interface', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'union', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'input', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'scalar', kind: types_1.CompletionItemKind.Function }, | ||
{ label: 'schema', kind: types_1.CompletionItemKind.Function }, | ||
]); | ||
} | ||
function getSuggestionsForFieldNames(token, typeInfo, options) { | ||
@@ -182,3 +328,3 @@ var _a; | ||
deprecationReason: field.deprecationReason, | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Field, | ||
kind: types_1.CompletionItemKind.Field, | ||
type: field.type, | ||
@@ -189,3 +335,3 @@ }; | ||
suggestion.insertText = field.name + insertText; | ||
suggestion.insertTextFormat = vscode_languageserver_types_1.InsertTextFormat.Snippet; | ||
suggestion.insertTextFormat = types_1.InsertTextFormat.Snippet; | ||
suggestion.command = exports.SuggestionCommand; | ||
@@ -213,3 +359,3 @@ } | ||
deprecationReason: value.deprecationReason, | ||
kind: vscode_languageserver_types_1.CompletionItemKind.EnumMember, | ||
kind: types_1.CompletionItemKind.EnumMember, | ||
type: namedInputType, | ||
@@ -226,3 +372,3 @@ }); | ||
documentation: 'Not false.', | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Variable, | ||
kind: types_1.CompletionItemKind.Variable, | ||
type: graphql_2.GraphQLBoolean, | ||
@@ -234,3 +380,3 @@ }, | ||
documentation: 'Not true.', | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Variable, | ||
kind: types_1.CompletionItemKind.Variable, | ||
type: graphql_2.GraphQLBoolean, | ||
@@ -298,3 +444,3 @@ }, | ||
label: type.name, | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Interface, | ||
kind: types_1.CompletionItemKind.Interface, | ||
type, | ||
@@ -328,3 +474,3 @@ }; | ||
const typeMap = schema.getTypeMap(); | ||
possibleTypes = (0, autocompleteUtils_1.objectValues)(typeMap).filter(graphql_2.isCompositeType); | ||
possibleTypes = (0, autocompleteUtils_1.objectValues)(typeMap).filter(type => (0, graphql_2.isCompositeType)(type) && !type.name.startsWith('__')); | ||
} | ||
@@ -336,3 +482,3 @@ return (0, autocompleteUtils_1.hintList)(token, possibleTypes.map(type => { | ||
documentation: (namedType === null || namedType === void 0 ? void 0 : namedType.description) || '', | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Field, | ||
kind: types_1.CompletionItemKind.Field, | ||
}; | ||
@@ -362,3 +508,3 @@ })); | ||
documentation: `fragment ${frag.name.value} on ${frag.typeCondition.name.value}`, | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Field, | ||
kind: types_1.CompletionItemKind.Field, | ||
type: typeMap[frag.typeCondition.name.value], | ||
@@ -403,3 +549,3 @@ }))); | ||
type: variableType, | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Variable, | ||
kind: types_1.CompletionItemKind.Variable, | ||
}; | ||
@@ -449,3 +595,3 @@ variableName = null; | ||
documentation: type.description, | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Variable, | ||
kind: types_1.CompletionItemKind.Variable, | ||
}))); | ||
@@ -462,3 +608,3 @@ } | ||
documentation: directive.description || '', | ||
kind: vscode_languageserver_types_1.CompletionItemKind.Function, | ||
kind: types_1.CompletionItemKind.Function, | ||
}))); | ||
@@ -737,2 +883,28 @@ } | ||
exports.getTypeInfo = getTypeInfo; | ||
var GraphQLDocumentMode; | ||
(function (GraphQLDocumentMode) { | ||
GraphQLDocumentMode["TYPE_SYSTEM"] = "TYPE_SYSTEM"; | ||
GraphQLDocumentMode["EXECUTABLE"] = "EXECUTABLE"; | ||
})(GraphQLDocumentMode = exports.GraphQLDocumentMode || (exports.GraphQLDocumentMode = {})); | ||
function getDocumentMode(documentText, uri) { | ||
if (uri === null || uri === void 0 ? void 0 : uri.endsWith('.graphqls')) { | ||
return GraphQLDocumentMode.TYPE_SYSTEM; | ||
} | ||
return hasTypeSystemDefinitions(documentText) | ||
? GraphQLDocumentMode.TYPE_SYSTEM | ||
: GraphQLDocumentMode.EXECUTABLE; | ||
} | ||
function unwrapType(state) { | ||
if (state.prevState && | ||
state.kind && | ||
[ | ||
parser_1.RuleKinds.NAMED_TYPE, | ||
parser_1.RuleKinds.LIST_TYPE, | ||
parser_1.RuleKinds.TYPE, | ||
parser_1.RuleKinds.NON_NULL_TYPE, | ||
].includes(state.kind)) { | ||
return unwrapType(state.prevState); | ||
} | ||
return state; | ||
} | ||
//# sourceMappingURL=getAutocompleteSuggestions.js.map |
@@ -254,3 +254,28 @@ "use strict"; | ||
], | ||
ExtendDef: [word('extend'), 'ObjectTypeDef'], | ||
ExtendDef: [word('extend'), 'ExtensionDefinition'], | ||
ExtensionDefinition(token) { | ||
switch (token.value) { | ||
case 'schema': | ||
return graphql_1.Kind.SCHEMA_EXTENSION; | ||
case 'scalar': | ||
return graphql_1.Kind.SCALAR_TYPE_EXTENSION; | ||
case 'type': | ||
return graphql_1.Kind.OBJECT_TYPE_EXTENSION; | ||
case 'interface': | ||
return graphql_1.Kind.INTERFACE_TYPE_EXTENSION; | ||
case 'union': | ||
return graphql_1.Kind.UNION_TYPE_EXTENSION; | ||
case 'enum': | ||
return graphql_1.Kind.ENUM_TYPE_EXTENSION; | ||
case 'input': | ||
return graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION; | ||
} | ||
}, | ||
[graphql_1.Kind.SCHEMA_EXTENSION]: ['SchemaDef'], | ||
[graphql_1.Kind.SCALAR_TYPE_EXTENSION]: ['ScalarDef'], | ||
[graphql_1.Kind.OBJECT_TYPE_EXTENSION]: ['ObjectTypeDef'], | ||
[graphql_1.Kind.INTERFACE_TYPE_EXTENSION]: ['InterfaceDef'], | ||
[graphql_1.Kind.UNION_TYPE_EXTENSION]: ['UnionDef'], | ||
[graphql_1.Kind.ENUM_TYPE_EXTENSION]: ['EnumDef'], | ||
[graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION]: ['InputDef'], | ||
}; | ||
@@ -257,0 +282,0 @@ function word(value) { |
@@ -72,2 +72,3 @@ import { Kind } from 'graphql'; | ||
EXTEND_DEF: 'ExtendDef'; | ||
EXTENSION_DEFINITION: 'ExtensionDefinition'; | ||
DIRECTIVE_DEF: 'DirectiveDef'; | ||
@@ -102,2 +103,3 @@ IMPLEMENTS: 'Implements'; | ||
EXTEND_DEF: 'ExtendDef'; | ||
EXTENSION_DEFINITION: 'ExtensionDefinition'; | ||
DIRECTIVE_DEF: 'DirectiveDef'; | ||
@@ -104,0 +106,0 @@ IMPLEMENTS: 'Implements'; |
@@ -29,2 +29,3 @@ "use strict"; | ||
EXTEND_DEF: 'ExtendDef', | ||
EXTENSION_DEFINITION: 'ExtensionDefinition', | ||
DIRECTIVE_DEF: 'DirectiveDef', | ||
@@ -31,0 +32,0 @@ IMPLEMENTS: 'Implements', |
import type { Diagnostic as DiagnosticType, CompletionItem as CompletionItemType } from 'vscode-languageserver-types'; | ||
export { InsertTextFormat } from 'vscode-languageserver-types'; | ||
import type { ASTNode, GraphQLSchema } from 'graphql'; | ||
@@ -3,0 +4,0 @@ import type { DocumentNode, FragmentDefinitionNode, NamedTypeNode, TypeDefinitionNode, NameNode } from 'graphql/language'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.CompletionItemKind = exports.FileChangeTypeKind = void 0; | ||
exports.CompletionItemKind = exports.FileChangeTypeKind = exports.InsertTextFormat = void 0; | ||
var vscode_languageserver_types_1 = require("vscode-languageserver-types"); | ||
Object.defineProperty(exports, "InsertTextFormat", { enumerable: true, get: function () { return vscode_languageserver_types_1.InsertTextFormat; } }); | ||
exports.FileChangeTypeKind = { | ||
@@ -5,0 +7,0 @@ Created: 1, |
@@ -159,3 +159,3 @@ "use strict"; | ||
var _a; | ||
const { definition, required, definitions, } = getJSONSchemaFromGraphQLType(type, options); | ||
const { definition, required, definitions } = getJSONSchemaFromGraphQLType(type, options); | ||
jsonSchema.properties[variableName] = definition; | ||
@@ -162,0 +162,0 @@ if (required) { |
@@ -11,2 +11,4 @@ import { FragmentDefinitionNode, GraphQLDirective, GraphQLSchema } from 'graphql'; | ||
schema?: GraphQLSchema; | ||
uri?: string; | ||
mode?: GraphQLDocumentMode; | ||
}; | ||
@@ -21,3 +23,7 @@ export declare function getAutocompleteSuggestions(schema: GraphQLSchema, queryText: string, cursor: IPosition, contextToken?: ContextTokenForCodeMirror, fragmentDefs?: FragmentDefinitionNode[] | string, options?: AutocompleteSuggestionOptions): Array<CompletionItem>; | ||
export declare function getTypeInfo(schema: GraphQLSchema, tokenState: State): AllTypeInfo; | ||
export declare enum GraphQLDocumentMode { | ||
TYPE_SYSTEM = "TYPE_SYSTEM", | ||
EXECUTABLE = "EXECUTABLE" | ||
} | ||
export {}; | ||
//# sourceMappingURL=getAutocompleteSuggestions.d.ts.map |
@@ -1,4 +0,4 @@ | ||
import { CompletionItemKind, InsertTextFormat, } from 'vscode-languageserver-types'; | ||
import { isInterfaceType, GraphQLInterfaceType, GraphQLObjectType, Kind, DirectiveLocation, isListType, isNonNullType, } from 'graphql'; | ||
import { GraphQLBoolean, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, assertAbstractType, doTypesOverlap, getNamedType, getNullableType, isAbstractType, isCompositeType, isInputType, visit, parse, } from 'graphql'; | ||
import { isInterfaceType, GraphQLInterfaceType, GraphQLObjectType, Kind, DirectiveLocation, isListType, isNonNullType, isScalarType, isObjectType, isUnionType, isEnumType, isInputObjectType, isOutputType, } from 'graphql'; | ||
import { CompletionItemKind, InsertTextFormat, } from '../types'; | ||
import { GraphQLBoolean, GraphQLEnumType, GraphQLInputObjectType, GraphQLList, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, assertAbstractType, doTypesOverlap, getNamedType, getNullableType, isAbstractType, isCompositeType, isInputType, visit, BREAK, parse, } from 'graphql'; | ||
import { CharacterStream, onlineParser, RuleKinds, } from '../parser'; | ||
@@ -26,7 +26,49 @@ import { forEachState, getDefinitionState, getFieldDef, hintList, objectValues, } from './autocompleteUtils'; | ||
}; | ||
const typeSystemKinds = [ | ||
Kind.SCHEMA_DEFINITION, | ||
Kind.OPERATION_TYPE_DEFINITION, | ||
Kind.SCALAR_TYPE_DEFINITION, | ||
Kind.OBJECT_TYPE_DEFINITION, | ||
Kind.INTERFACE_TYPE_DEFINITION, | ||
Kind.UNION_TYPE_DEFINITION, | ||
Kind.ENUM_TYPE_DEFINITION, | ||
Kind.INPUT_OBJECT_TYPE_DEFINITION, | ||
Kind.DIRECTIVE_DEFINITION, | ||
Kind.SCHEMA_EXTENSION, | ||
Kind.SCALAR_TYPE_EXTENSION, | ||
Kind.OBJECT_TYPE_EXTENSION, | ||
Kind.INTERFACE_TYPE_EXTENSION, | ||
Kind.UNION_TYPE_EXTENSION, | ||
Kind.ENUM_TYPE_EXTENSION, | ||
Kind.INPUT_OBJECT_TYPE_EXTENSION, | ||
]; | ||
const hasTypeSystemDefinitions = (sdl) => { | ||
let hasTypeSystemDef = false; | ||
if (sdl) { | ||
try { | ||
visit(parse(sdl), { | ||
enter(node) { | ||
if (node.kind === 'Document') { | ||
return; | ||
} | ||
if (typeSystemKinds.includes(node.kind)) { | ||
hasTypeSystemDef = true; | ||
return BREAK; | ||
} | ||
return false; | ||
}, | ||
}); | ||
} | ||
catch (_a) { | ||
return hasTypeSystemDef; | ||
} | ||
} | ||
return hasTypeSystemDef; | ||
}; | ||
export function getAutocompleteSuggestions(schema, queryText, cursor, contextToken, fragmentDefs, options) { | ||
var _a; | ||
var _a, _b, _c, _d, _e, _f, _g, _h, _j; | ||
const opts = Object.assign(Object.assign({}, options), { schema }); | ||
const token = contextToken || getTokenAtPosition(queryText, cursor); | ||
const state = token.state.kind === 'Invalid' ? token.state.prevState : token.state; | ||
const mode = (options === null || options === void 0 ? void 0 : options.mode) || getDocumentMode(queryText, options === null || options === void 0 ? void 0 : options.uri); | ||
if (!state) { | ||
@@ -39,13 +81,65 @@ return []; | ||
if (kind === RuleKinds.DOCUMENT) { | ||
return hintList(token, [ | ||
{ label: 'query', kind: CompletionItemKind.Function }, | ||
{ label: 'mutation', kind: CompletionItemKind.Function }, | ||
{ label: 'subscription', kind: CompletionItemKind.Function }, | ||
{ label: 'fragment', kind: CompletionItemKind.Function }, | ||
{ label: '{', kind: CompletionItemKind.Constructor }, | ||
]); | ||
if (mode === GraphQLDocumentMode.TYPE_SYSTEM) { | ||
return getSuggestionsForTypeSystemDefinitions(token); | ||
} | ||
return getSuggestionsForExecutableDefinitions(token); | ||
} | ||
if (kind === RuleKinds.EXTEND_DEF) { | ||
return getSuggestionsForExtensionDefinitions(token); | ||
} | ||
if (((_b = (_a = state.prevState) === null || _a === void 0 ? void 0 : _a.prevState) === null || _b === void 0 ? void 0 : _b.kind) === RuleKinds.EXTENSION_DEFINITION && | ||
state.name) { | ||
return hintList(token, []); | ||
} | ||
if (((_c = state.prevState) === null || _c === void 0 ? void 0 : _c.kind) === Kind.SCALAR_TYPE_EXTENSION) { | ||
return hintList(token, Object.values(schema.getTypeMap()) | ||
.filter(isScalarType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_d = state.prevState) === null || _d === void 0 ? void 0 : _d.kind) === Kind.OBJECT_TYPE_EXTENSION) { | ||
return hintList(token, Object.values(schema.getTypeMap()) | ||
.filter(type => isObjectType(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_e = state.prevState) === null || _e === void 0 ? void 0 : _e.kind) === Kind.INTERFACE_TYPE_EXTENSION) { | ||
return hintList(token, Object.values(schema.getTypeMap()) | ||
.filter(isInterfaceType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_f = state.prevState) === null || _f === void 0 ? void 0 : _f.kind) === Kind.UNION_TYPE_EXTENSION) { | ||
return hintList(token, Object.values(schema.getTypeMap()) | ||
.filter(isUnionType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_g = state.prevState) === null || _g === void 0 ? void 0 : _g.kind) === Kind.ENUM_TYPE_EXTENSION) { | ||
return hintList(token, Object.values(schema.getTypeMap()) | ||
.filter(type => isEnumType(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (((_h = state.prevState) === null || _h === void 0 ? void 0 : _h.kind) === Kind.INPUT_OBJECT_TYPE_EXTENSION) { | ||
return hintList(token, Object.values(schema.getTypeMap()) | ||
.filter(isInputObjectType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (kind === RuleKinds.IMPLEMENTS || | ||
(kind === RuleKinds.NAMED_TYPE && | ||
((_a = state.prevState) === null || _a === void 0 ? void 0 : _a.kind) === RuleKinds.IMPLEMENTS)) { | ||
((_j = state.prevState) === null || _j === void 0 ? void 0 : _j.kind) === RuleKinds.IMPLEMENTS)) { | ||
return getSuggestionsForImplements(token, state, schema, queryText, typeInfo); | ||
@@ -117,2 +211,24 @@ } | ||
} | ||
const unwrappedState = unwrapType(state); | ||
if ((mode === GraphQLDocumentMode.TYPE_SYSTEM && | ||
!unwrappedState.needsAdvance && | ||
state.kind === RuleKinds.NAMED_TYPE) || | ||
state.kind === RuleKinds.LIST_TYPE) { | ||
if (unwrappedState.kind === RuleKinds.FIELD_DEF) { | ||
return hintList(token, Object.values(schema.getTypeMap()) | ||
.filter(type => isOutputType(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
}))); | ||
} | ||
if (unwrappedState.kind === RuleKinds.INPUT_VALUE_DEF) { | ||
return hintList(token, Object.values(schema.getTypeMap()) | ||
.filter(type => isInputType(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
}))); | ||
} | ||
} | ||
if ((kind === RuleKinds.VARIABLE_DEFINITION && step === 2) || | ||
@@ -151,2 +267,32 @@ (kind === RuleKinds.LIST_TYPE && step === 1) || | ||
}; | ||
function getSuggestionsForTypeSystemDefinitions(token) { | ||
return hintList(token, [ | ||
{ label: 'extend', kind: CompletionItemKind.Function }, | ||
{ label: 'type', kind: CompletionItemKind.Function }, | ||
{ label: 'interface', kind: CompletionItemKind.Function }, | ||
{ label: 'union', kind: CompletionItemKind.Function }, | ||
{ label: 'input', kind: CompletionItemKind.Function }, | ||
{ label: 'scalar', kind: CompletionItemKind.Function }, | ||
{ label: 'schema', kind: CompletionItemKind.Function }, | ||
]); | ||
} | ||
function getSuggestionsForExecutableDefinitions(token) { | ||
return hintList(token, [ | ||
{ label: 'query', kind: CompletionItemKind.Function }, | ||
{ label: 'mutation', kind: CompletionItemKind.Function }, | ||
{ label: 'subscription', kind: CompletionItemKind.Function }, | ||
{ label: 'fragment', kind: CompletionItemKind.Function }, | ||
{ label: '{', kind: CompletionItemKind.Constructor }, | ||
]); | ||
} | ||
function getSuggestionsForExtensionDefinitions(token) { | ||
return hintList(token, [ | ||
{ label: 'type', kind: CompletionItemKind.Function }, | ||
{ label: 'interface', kind: CompletionItemKind.Function }, | ||
{ label: 'union', kind: CompletionItemKind.Function }, | ||
{ label: 'input', kind: CompletionItemKind.Function }, | ||
{ label: 'scalar', kind: CompletionItemKind.Function }, | ||
{ label: 'schema', kind: CompletionItemKind.Function }, | ||
]); | ||
} | ||
function getSuggestionsForFieldNames(token, typeInfo, options) { | ||
@@ -316,3 +462,3 @@ var _a; | ||
const typeMap = schema.getTypeMap(); | ||
possibleTypes = objectValues(typeMap).filter(isCompositeType); | ||
possibleTypes = objectValues(typeMap).filter(type => isCompositeType(type) && !type.name.startsWith('__')); | ||
} | ||
@@ -714,2 +860,28 @@ return hintList(token, possibleTypes.map(type => { | ||
} | ||
export var GraphQLDocumentMode; | ||
(function (GraphQLDocumentMode) { | ||
GraphQLDocumentMode["TYPE_SYSTEM"] = "TYPE_SYSTEM"; | ||
GraphQLDocumentMode["EXECUTABLE"] = "EXECUTABLE"; | ||
})(GraphQLDocumentMode || (GraphQLDocumentMode = {})); | ||
function getDocumentMode(documentText, uri) { | ||
if (uri === null || uri === void 0 ? void 0 : uri.endsWith('.graphqls')) { | ||
return GraphQLDocumentMode.TYPE_SYSTEM; | ||
} | ||
return hasTypeSystemDefinitions(documentText) | ||
? GraphQLDocumentMode.TYPE_SYSTEM | ||
: GraphQLDocumentMode.EXECUTABLE; | ||
} | ||
function unwrapType(state) { | ||
if (state.prevState && | ||
state.kind && | ||
[ | ||
RuleKinds.NAMED_TYPE, | ||
RuleKinds.LIST_TYPE, | ||
RuleKinds.TYPE, | ||
RuleKinds.NON_NULL_TYPE, | ||
].includes(state.kind)) { | ||
return unwrapType(state.prevState); | ||
} | ||
return state; | ||
} | ||
//# sourceMappingURL=getAutocompleteSuggestions.js.map |
@@ -250,3 +250,28 @@ import { opt, list, butNot, t, p } from './RuleHelpers'; | ||
], | ||
ExtendDef: [word('extend'), 'ObjectTypeDef'], | ||
ExtendDef: [word('extend'), 'ExtensionDefinition'], | ||
ExtensionDefinition(token) { | ||
switch (token.value) { | ||
case 'schema': | ||
return Kind.SCHEMA_EXTENSION; | ||
case 'scalar': | ||
return Kind.SCALAR_TYPE_EXTENSION; | ||
case 'type': | ||
return Kind.OBJECT_TYPE_EXTENSION; | ||
case 'interface': | ||
return Kind.INTERFACE_TYPE_EXTENSION; | ||
case 'union': | ||
return Kind.UNION_TYPE_EXTENSION; | ||
case 'enum': | ||
return Kind.ENUM_TYPE_EXTENSION; | ||
case 'input': | ||
return Kind.INPUT_OBJECT_TYPE_EXTENSION; | ||
} | ||
}, | ||
[Kind.SCHEMA_EXTENSION]: ['SchemaDef'], | ||
[Kind.SCALAR_TYPE_EXTENSION]: ['ScalarDef'], | ||
[Kind.OBJECT_TYPE_EXTENSION]: ['ObjectTypeDef'], | ||
[Kind.INTERFACE_TYPE_EXTENSION]: ['InterfaceDef'], | ||
[Kind.UNION_TYPE_EXTENSION]: ['UnionDef'], | ||
[Kind.ENUM_TYPE_EXTENSION]: ['EnumDef'], | ||
[Kind.INPUT_OBJECT_TYPE_EXTENSION]: ['InputDef'], | ||
}; | ||
@@ -253,0 +278,0 @@ function word(value) { |
@@ -72,2 +72,3 @@ import { Kind } from 'graphql'; | ||
EXTEND_DEF: 'ExtendDef'; | ||
EXTENSION_DEFINITION: 'ExtensionDefinition'; | ||
DIRECTIVE_DEF: 'DirectiveDef'; | ||
@@ -102,2 +103,3 @@ IMPLEMENTS: 'Implements'; | ||
EXTEND_DEF: 'ExtendDef'; | ||
EXTENSION_DEFINITION: 'ExtensionDefinition'; | ||
DIRECTIVE_DEF: 'DirectiveDef'; | ||
@@ -104,0 +106,0 @@ IMPLEMENTS: 'Implements'; |
@@ -26,2 +26,3 @@ import { Kind } from 'graphql'; | ||
EXTEND_DEF: 'ExtendDef', | ||
EXTENSION_DEFINITION: 'ExtensionDefinition', | ||
DIRECTIVE_DEF: 'DirectiveDef', | ||
@@ -28,0 +29,0 @@ IMPLEMENTS: 'Implements', |
import type { Diagnostic as DiagnosticType, CompletionItem as CompletionItemType } from 'vscode-languageserver-types'; | ||
export { InsertTextFormat } from 'vscode-languageserver-types'; | ||
import type { ASTNode, GraphQLSchema } from 'graphql'; | ||
@@ -3,0 +4,0 @@ import type { DocumentNode, FragmentDefinitionNode, NamedTypeNode, TypeDefinitionNode, NameNode } from 'graphql/language'; |
@@ -0,1 +1,2 @@ | ||
export { InsertTextFormat } from 'vscode-languageserver-types'; | ||
export const FileChangeTypeKind = { | ||
@@ -2,0 +3,0 @@ Created: 1, |
@@ -156,3 +156,3 @@ import { isEnumType, isInputObjectType, isListType, isNonNullType, isScalarType, } from 'graphql'; | ||
var _a; | ||
const { definition, required, definitions, } = getJSONSchemaFromGraphQLType(type, options); | ||
const { definition, required, definitions } = getJSONSchemaFromGraphQLType(type, options); | ||
jsonSchema.properties[variableName] = definition; | ||
@@ -159,0 +159,0 @@ if (required) { |
{ | ||
"name": "graphql-language-service", | ||
"version": "5.0.7-canary-0ac0349e.0", | ||
"version": "5.1.0", | ||
"description": "The official, runtime independent Language Service for GraphQL", | ||
@@ -8,3 +8,7 @@ "contributors": [ | ||
], | ||
"repository": "http://github.com/graphql/graphiql", | ||
"repository": { | ||
"type": "git", | ||
"url": "http://github.com/graphql/graphiql", | ||
"directory": "packages/graphql-language-service" | ||
}, | ||
"homepage": "https://github.com/graphql/graphiql/tree/main/packages/graphql-language-service#readme", | ||
@@ -35,3 +39,3 @@ "bugs": { | ||
"dependencies": { | ||
"vscode-languageserver-types": "^3.15.1", | ||
"vscode-languageserver-types": "^3.17.1", | ||
"nullthrows": "^1.0.0" | ||
@@ -45,3 +49,3 @@ }, | ||
"graphql": "^16.4.0", | ||
"graphql-config": "^4.3.0", | ||
"graphql-config": "4.3.0", | ||
"lodash": "^4.17.15", | ||
@@ -48,0 +52,0 @@ "platform": "^1.3.5", |
# `graphql-language-service` | ||
[API Docs](https://graphiql-test.netlify.app/typedoc/modules/graphql_language_service.html) | ||
[Discord Channel](https://discord.gg/wkQCKwazxj) | ||
[Changelog](https://github.com/graphql/graphiql/blob/main/packages/graphql-language-service/CHANGELOG.md) | [API Docs](https://graphiql-test.netlify.app/typedoc/modules/graphql_language_service.html) | | ||
[Discord](https://discord.gg/wkQCKwazxj) | ||
@@ -6,0 +6,0 @@ > **Note**: Still mostly experimental, however it depends mostly on stable libraries. |
@@ -92,2 +92,3 @@ /** | ||
externalFragments?: FragmentDefinitionNode[], | ||
uri?: string, | ||
): Array<CompletionItem> { | ||
@@ -98,4 +99,5 @@ return getAutocompleteSuggestions( | ||
point, | ||
null, | ||
undefined, | ||
externalFragments, | ||
{ uri }, | ||
) | ||
@@ -131,7 +133,4 @@ .filter( | ||
console.log({ graphQLVersion }); | ||
// TODO: remove this once defer and stream are merged to `graphql` | ||
if (graphQLVersion.startsWith('16.0.0-experimental-stream-defer')) { | ||
console.log('expect stream'); | ||
expectedDirectiveSuggestions.push({ label: 'stream' }, { label: 'test' }); | ||
@@ -253,2 +252,17 @@ } else { | ||
it('provides correct type suggestions for fragments', () => { | ||
const result = testSuggestions('fragment test on ', new Position(0, 17)); | ||
expect(result).toEqual([ | ||
{ label: 'AnotherInterface' }, | ||
{ label: 'Character' }, | ||
{ label: 'Droid' }, | ||
{ label: 'Human' }, | ||
{ label: 'Query' }, | ||
{ label: 'TestInterface' }, | ||
{ label: 'TestType' }, | ||
{ label: 'TestUnion' }, | ||
]); | ||
}); | ||
it('provides correct field suggestions for fragments', () => { | ||
@@ -369,2 +383,3 @@ const result = testSuggestions( | ||
{ label: 'TestType' }, | ||
{ label: 'TestUnion' }, | ||
]); | ||
@@ -509,3 +524,94 @@ }); | ||
}); | ||
describe('with SDL types', () => { | ||
it('provides correct initial keywords', () => { | ||
expect( | ||
testSuggestions('', new Position(0, 0), [], 'schema.graphqls'), | ||
).toEqual([ | ||
{ label: 'extend' }, | ||
{ label: 'input' }, | ||
{ label: 'interface' }, | ||
{ label: 'scalar' }, | ||
{ label: 'schema' }, | ||
{ label: 'type' }, | ||
{ label: 'union' }, | ||
]); | ||
}); | ||
it('provides correct initial definition keywords', () => { | ||
expect( | ||
testSuggestions('type Type { field: String }\n\n', new Position(0, 31)), | ||
).toEqual([ | ||
{ label: 'extend' }, | ||
{ label: 'input' }, | ||
{ label: 'interface' }, | ||
{ label: 'scalar' }, | ||
{ label: 'schema' }, | ||
{ label: 'type' }, | ||
{ label: 'union' }, | ||
]); | ||
}); | ||
it('provides correct extension keywords', () => { | ||
expect(testSuggestions('extend ', new Position(0, 7))).toEqual([ | ||
{ label: 'input' }, | ||
{ label: 'interface' }, | ||
{ label: 'scalar' }, | ||
{ label: 'schema' }, | ||
{ label: 'type' }, | ||
{ label: 'union' }, | ||
]); | ||
}); | ||
it('provides scalars to be extended', () => { | ||
expect(testSuggestions('extend scalar ', new Position(0, 14))).toEqual([ | ||
{ label: 'Boolean' }, | ||
{ label: 'Int' }, | ||
{ label: 'String' }, | ||
]); | ||
}); | ||
it('provides object types to be extended', () => { | ||
expect(testSuggestions('extend type ', new Position(0, 12))).toEqual([ | ||
{ label: 'Droid' }, | ||
{ label: 'Human' }, | ||
{ label: 'Query' }, | ||
{ label: 'TestType' }, | ||
]); | ||
}); | ||
it('does not provide object type names once extending a type', () => { | ||
expect( | ||
testSuggestions('extend type Query {', new Position(0, 19)), | ||
).toEqual([]); | ||
}); | ||
it('provides interfaces to be extended', () => { | ||
expect(testSuggestions('extend interface ', new Position(0, 17))).toEqual( | ||
[ | ||
{ label: 'AnotherInterface' }, | ||
{ label: 'Character' }, | ||
{ label: 'TestInterface' }, | ||
], | ||
); | ||
}); | ||
it('provides unions to be extended', () => { | ||
expect(testSuggestions('extend union ', new Position(0, 13))).toEqual([ | ||
{ label: 'TestUnion' }, | ||
]); | ||
}); | ||
it('provides enums to be extended', () => { | ||
expect(testSuggestions('extend enum ', new Position(0, 12))).toEqual([ | ||
{ label: 'Episode' }, | ||
]); | ||
}); | ||
it('provides input objects to be extended', () => { | ||
expect(testSuggestions('extend input ', new Position(0, 13))).toEqual([ | ||
{ label: 'InputType' }, | ||
]); | ||
}); | ||
it('provides correct directive suggestions on definitions', () => | ||
@@ -517,7 +623,45 @@ expect(testSuggestions('type Type @', new Position(0, 11))).toEqual([ | ||
expect( | ||
testSuggestions(`type Type {\n aField: s`, new Position(0, 23)), | ||
).toEqual([{ label: 'Episode' }, { label: 'String' }])); | ||
testSuggestions( | ||
`type Type {\n aField: s`, | ||
new Position(0, 23), | ||
[], | ||
'schema.graphqls', | ||
), | ||
).toEqual([ | ||
{ label: 'Episode' }, | ||
{ label: 'String' }, | ||
{ label: 'TestInterface' }, | ||
{ label: 'TestType' }, | ||
{ label: 'TestUnion' }, | ||
])); | ||
it('provides correct suggestions on object fields that are arrays', () => | ||
expect( | ||
testSuggestions( | ||
`type Type {\n aField: []`, | ||
new Position(0, 25), | ||
[], | ||
'schema.graphqls', | ||
), | ||
).toEqual([ | ||
{ label: 'AnotherInterface' }, | ||
{ label: 'Boolean' }, | ||
{ label: 'Character' }, | ||
{ label: 'Droid' }, | ||
{ label: 'Episode' }, | ||
{ label: 'Human' }, | ||
{ label: 'Int' }, | ||
{ label: 'Query' }, | ||
{ label: 'String' }, | ||
{ label: 'TestInterface' }, | ||
{ label: 'TestType' }, | ||
{ label: 'TestUnion' }, | ||
])); | ||
it('provides correct suggestions on input object fields', () => | ||
expect( | ||
testSuggestions(`input Type {\n aField: s`, new Position(0, 23)), | ||
testSuggestions( | ||
`input Type {\n aField: s`, | ||
new Position(0, 23), | ||
[], | ||
'schema.graphqls', | ||
), | ||
).toEqual([{ label: 'Episode' }, { label: 'String' }])); | ||
@@ -524,0 +668,0 @@ it('provides correct directive suggestions on args definitions', () => |
@@ -103,4 +103,4 @@ /** | ||
// @ts-ignore | ||
const fragmentSpread = parse(query).definitions[0].selectionSet | ||
.selections[0]; | ||
const fragmentSpread = | ||
parse(query).definitions[0].selectionSet.selections[0]; | ||
const fragmentDefinition = parse(fragment).definitions[0]; | ||
@@ -107,0 +107,0 @@ const result = await getDefinitionQueryResultForFragmentSpread( |
@@ -9,6 +9,2 @@ /** | ||
*/ | ||
import { | ||
CompletionItemKind, | ||
InsertTextFormat, | ||
} from 'vscode-languageserver-types'; | ||
@@ -33,5 +29,17 @@ import { | ||
isNonNullType, | ||
isScalarType, | ||
isObjectType, | ||
isUnionType, | ||
isEnumType, | ||
isInputObjectType, | ||
isOutputType, | ||
} from 'graphql'; | ||
import { CompletionItem, AllTypeInfo, IPosition } from '../types'; | ||
import { | ||
CompletionItem, | ||
AllTypeInfo, | ||
IPosition, | ||
CompletionItemKind, | ||
InsertTextFormat, | ||
} from '../types'; | ||
@@ -54,2 +62,3 @@ import { | ||
visit, | ||
BREAK, | ||
parse, | ||
@@ -97,5 +106,51 @@ } from 'graphql'; | ||
const typeSystemKinds: Kind[] = [ | ||
// TypeSystemDefinition | ||
Kind.SCHEMA_DEFINITION, | ||
Kind.OPERATION_TYPE_DEFINITION, | ||
Kind.SCALAR_TYPE_DEFINITION, | ||
Kind.OBJECT_TYPE_DEFINITION, | ||
Kind.INTERFACE_TYPE_DEFINITION, | ||
Kind.UNION_TYPE_DEFINITION, | ||
Kind.ENUM_TYPE_DEFINITION, | ||
Kind.INPUT_OBJECT_TYPE_DEFINITION, | ||
Kind.DIRECTIVE_DEFINITION, | ||
// TypeSystemExtension | ||
Kind.SCHEMA_EXTENSION, | ||
Kind.SCALAR_TYPE_EXTENSION, | ||
Kind.OBJECT_TYPE_EXTENSION, | ||
Kind.INTERFACE_TYPE_EXTENSION, | ||
Kind.UNION_TYPE_EXTENSION, | ||
Kind.ENUM_TYPE_EXTENSION, | ||
Kind.INPUT_OBJECT_TYPE_EXTENSION, | ||
]; | ||
const hasTypeSystemDefinitions = (sdl: string | undefined) => { | ||
let hasTypeSystemDef = false; | ||
if (sdl) { | ||
try { | ||
visit(parse(sdl), { | ||
enter(node) { | ||
if (node.kind === 'Document') { | ||
return; | ||
} | ||
if (typeSystemKinds.includes(node.kind)) { | ||
hasTypeSystemDef = true; | ||
return BREAK; | ||
} | ||
return false; | ||
}, | ||
}); | ||
} catch { | ||
return hasTypeSystemDef; | ||
} | ||
} | ||
return hasTypeSystemDef; | ||
}; | ||
export type AutocompleteSuggestionOptions = { | ||
fillLeafsOnComplete?: boolean; | ||
schema?: GraphQLSchema; | ||
uri?: string; | ||
mode?: GraphQLDocumentMode; | ||
}; | ||
@@ -125,2 +180,4 @@ | ||
const mode = options?.mode || getDocumentMode(queryText, options?.uri); | ||
// relieve flow errors by checking if `state` exists | ||
@@ -134,14 +191,101 @@ if (!state) { | ||
const typeInfo = getTypeInfo(schema, token.state); | ||
// Definition kinds | ||
if (kind === RuleKinds.DOCUMENT) { | ||
return hintList(token, [ | ||
{ label: 'query', kind: CompletionItemKind.Function }, | ||
{ label: 'mutation', kind: CompletionItemKind.Function }, | ||
{ label: 'subscription', kind: CompletionItemKind.Function }, | ||
{ label: 'fragment', kind: CompletionItemKind.Function }, | ||
{ label: '{', kind: CompletionItemKind.Constructor }, | ||
]); | ||
if (mode === GraphQLDocumentMode.TYPE_SYSTEM) { | ||
return getSuggestionsForTypeSystemDefinitions(token); | ||
} | ||
return getSuggestionsForExecutableDefinitions(token); | ||
} | ||
if (kind === RuleKinds.EXTEND_DEF) { | ||
return getSuggestionsForExtensionDefinitions(token); | ||
} | ||
if ( | ||
state.prevState?.prevState?.kind === RuleKinds.EXTENSION_DEFINITION && | ||
state.name | ||
) { | ||
return hintList(token, []); | ||
} | ||
// extend scalar | ||
if (state.prevState?.kind === Kind.SCALAR_TYPE_EXTENSION) { | ||
return hintList( | ||
token, | ||
Object.values(schema.getTypeMap()) | ||
.filter(isScalarType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
})), | ||
); | ||
} | ||
// extend object type | ||
if (state.prevState?.kind === Kind.OBJECT_TYPE_EXTENSION) { | ||
return hintList( | ||
token, | ||
Object.values(schema.getTypeMap()) | ||
.filter(type => isObjectType(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
})), | ||
); | ||
} | ||
// extend interface type | ||
if (state.prevState?.kind === Kind.INTERFACE_TYPE_EXTENSION) { | ||
return hintList( | ||
token, | ||
Object.values(schema.getTypeMap()) | ||
.filter(isInterfaceType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
})), | ||
); | ||
} | ||
// extend union type | ||
if (state.prevState?.kind === Kind.UNION_TYPE_EXTENSION) { | ||
return hintList( | ||
token, | ||
Object.values(schema.getTypeMap()) | ||
.filter(isUnionType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
})), | ||
); | ||
} | ||
// extend enum type | ||
if (state.prevState?.kind === Kind.ENUM_TYPE_EXTENSION) { | ||
return hintList( | ||
token, | ||
Object.values(schema.getTypeMap()) | ||
.filter(type => isEnumType(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
})), | ||
); | ||
} | ||
// extend input object type | ||
if (state.prevState?.kind === Kind.INPUT_OBJECT_TYPE_EXTENSION) { | ||
return hintList( | ||
token, | ||
Object.values(schema.getTypeMap()) | ||
.filter(isInputObjectType) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
})), | ||
); | ||
} | ||
if ( | ||
kind === RuleKinds.IMPLEMENTS || | ||
@@ -268,2 +412,34 @@ (kind === RuleKinds.NAMED_TYPE && | ||
const unwrappedState = unwrapType(state); | ||
if ( | ||
(mode === GraphQLDocumentMode.TYPE_SYSTEM && | ||
!unwrappedState.needsAdvance && | ||
state.kind === RuleKinds.NAMED_TYPE) || | ||
state.kind === RuleKinds.LIST_TYPE | ||
) { | ||
if (unwrappedState.kind === RuleKinds.FIELD_DEF) { | ||
return hintList( | ||
token, | ||
Object.values(schema.getTypeMap()) | ||
.filter(type => isOutputType(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
})), | ||
); | ||
} | ||
if (unwrappedState.kind === RuleKinds.INPUT_VALUE_DEF) { | ||
return hintList( | ||
token, | ||
Object.values(schema.getTypeMap()) | ||
.filter(type => isInputType(type) && !type.name.startsWith('__')) | ||
.map(type => ({ | ||
label: type.name, | ||
kind: CompletionItemKind.Function, | ||
})), | ||
); | ||
} | ||
} | ||
// Variable definition types | ||
@@ -317,2 +493,35 @@ if ( | ||
// Helper functions to get suggestions for each kinds | ||
function getSuggestionsForTypeSystemDefinitions(token: ContextToken) { | ||
return hintList(token, [ | ||
{ label: 'extend', kind: CompletionItemKind.Function }, | ||
{ label: 'type', kind: CompletionItemKind.Function }, | ||
{ label: 'interface', kind: CompletionItemKind.Function }, | ||
{ label: 'union', kind: CompletionItemKind.Function }, | ||
{ label: 'input', kind: CompletionItemKind.Function }, | ||
{ label: 'scalar', kind: CompletionItemKind.Function }, | ||
{ label: 'schema', kind: CompletionItemKind.Function }, | ||
]); | ||
} | ||
function getSuggestionsForExecutableDefinitions(token: ContextToken) { | ||
return hintList(token, [ | ||
{ label: 'query', kind: CompletionItemKind.Function }, | ||
{ label: 'mutation', kind: CompletionItemKind.Function }, | ||
{ label: 'subscription', kind: CompletionItemKind.Function }, | ||
{ label: 'fragment', kind: CompletionItemKind.Function }, | ||
{ label: '{', kind: CompletionItemKind.Constructor }, | ||
]); | ||
} | ||
function getSuggestionsForExtensionDefinitions(token: ContextToken) { | ||
return hintList(token, [ | ||
{ label: 'type', kind: CompletionItemKind.Function }, | ||
{ label: 'interface', kind: CompletionItemKind.Function }, | ||
{ label: 'union', kind: CompletionItemKind.Function }, | ||
{ label: 'input', kind: CompletionItemKind.Function }, | ||
{ label: 'scalar', kind: CompletionItemKind.Function }, | ||
{ label: 'schema', kind: CompletionItemKind.Function }, | ||
]); | ||
} | ||
function getSuggestionsForFieldNames( | ||
@@ -563,3 +772,5 @@ token: ContextToken, | ||
const typeMap = schema.getTypeMap(); | ||
possibleTypes = objectValues(typeMap).filter(isCompositeType); | ||
possibleTypes = objectValues(typeMap).filter( | ||
type => isCompositeType(type) && !type.name.startsWith('__'), | ||
); | ||
} | ||
@@ -1089,1 +1300,36 @@ return hintList( | ||
} | ||
export enum GraphQLDocumentMode { | ||
TYPE_SYSTEM = 'TYPE_SYSTEM', | ||
EXECUTABLE = 'EXECUTABLE', | ||
} | ||
function getDocumentMode( | ||
documentText: string, | ||
uri?: string, | ||
): GraphQLDocumentMode { | ||
if (uri?.endsWith('.graphqls')) { | ||
return GraphQLDocumentMode.TYPE_SYSTEM; | ||
} | ||
return hasTypeSystemDefinitions(documentText) | ||
? GraphQLDocumentMode.TYPE_SYSTEM | ||
: GraphQLDocumentMode.EXECUTABLE; | ||
} | ||
function unwrapType(state: State): State { | ||
if ( | ||
state.prevState && | ||
state.kind && | ||
( | ||
[ | ||
RuleKinds.NAMED_TYPE, | ||
RuleKinds.LIST_TYPE, | ||
RuleKinds.TYPE, | ||
RuleKinds.NON_NULL_TYPE, | ||
] as RuleKind[] | ||
).includes(state.kind) | ||
) { | ||
return unwrapType(state.prevState); | ||
} | ||
return state; | ||
} |
@@ -91,5 +91,5 @@ /** | ||
defNodes.forEach(({ filePath, content, definition }) => { | ||
const fieldDefinition = (definition as ObjectTypeDefinitionNode).fields?.find( | ||
item => item.name.value === fieldName, | ||
); | ||
const fieldDefinition = ( | ||
definition as ObjectTypeDefinitionNode | ||
).fields?.find(item => item.name.value === fieldName); | ||
@@ -96,0 +96,0 @@ if (fieldDefinition == null) { |
@@ -80,7 +80,5 @@ /** | ||
type OutlineTreeConverterType = Partial< | ||
{ | ||
[key in OutlineableKinds]: (node: any) => OutlineTreeResult; | ||
} | ||
>; | ||
type OutlineTreeConverterType = Partial<{ | ||
[key in OutlineableKinds]: (node: any) => OutlineTreeResult; | ||
}>; | ||
@@ -96,3 +94,3 @@ export function getOutline(documentText: string): Outline | null { | ||
const visitorFns = outlineTreeConverter(documentText); | ||
const outlineTrees = (visit(ast, { | ||
const outlineTrees = visit(ast, { | ||
leave(node) { | ||
@@ -105,3 +103,3 @@ if (visitorFns !== undefined && node.kind in visitorFns) { | ||
}, | ||
}) as unknown) as OutlineTree[]; | ||
}) as unknown as OutlineTree[]; | ||
@@ -137,3 +135,3 @@ return { outlineTrees }; | ||
buildToken('whitespace', ' '), | ||
buildToken('class-name', (node.name as unknown) as string), | ||
buildToken('class-name', node.name as unknown as string), | ||
], | ||
@@ -140,0 +138,0 @@ ...meta(node), |
@@ -41,3 +41,4 @@ /** | ||
// Note the closing quote is made optional as an IDE experience improvement. | ||
String: /^(?:"""(?:\\"""|[^"]|"[^"]|""[^"])*(?:""")?|"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?)/, | ||
String: | ||
/^(?:"""(?:\\"""|[^"]|"[^"]|""[^"])*(?:""")?|"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?)/, | ||
@@ -306,3 +307,28 @@ // Comments consume entire lines. | ||
], | ||
ExtendDef: [word('extend'), 'ObjectTypeDef'], | ||
ExtendDef: [word('extend'), 'ExtensionDefinition'], | ||
ExtensionDefinition(token: Token): RuleKind | void { | ||
switch (token.value) { | ||
case 'schema': | ||
return Kind.SCHEMA_EXTENSION; | ||
case 'scalar': | ||
return Kind.SCALAR_TYPE_EXTENSION; | ||
case 'type': | ||
return Kind.OBJECT_TYPE_EXTENSION; | ||
case 'interface': | ||
return Kind.INTERFACE_TYPE_EXTENSION; | ||
case 'union': | ||
return Kind.UNION_TYPE_EXTENSION; | ||
case 'enum': | ||
return Kind.ENUM_TYPE_EXTENSION; | ||
case 'input': | ||
return Kind.INPUT_OBJECT_TYPE_EXTENSION; | ||
} | ||
}, | ||
[Kind.SCHEMA_EXTENSION]: ['SchemaDef'], | ||
[Kind.SCALAR_TYPE_EXTENSION]: ['ScalarDef'], | ||
[Kind.OBJECT_TYPE_EXTENSION]: ['ObjectTypeDef'], | ||
[Kind.INTERFACE_TYPE_EXTENSION]: ['InterfaceDef'], | ||
[Kind.UNION_TYPE_EXTENSION]: ['UnionDef'], | ||
[Kind.ENUM_TYPE_EXTENSION]: ['EnumDef'], | ||
[Kind.INPUT_OBJECT_TYPE_EXTENSION]: ['InputDef'], | ||
}; | ||
@@ -309,0 +335,0 @@ |
@@ -82,2 +82,3 @@ import { Kind } from 'graphql'; | ||
EXTEND_DEF: 'ExtendDef', | ||
EXTENSION_DEFINITION: 'ExtensionDefinition', | ||
DIRECTIVE_DEF: 'DirectiveDef', | ||
@@ -113,2 +114,3 @@ IMPLEMENTS: 'Implements', | ||
EXTEND_DEF: 'ExtendDef'; | ||
EXTENSION_DEFINITION: 'ExtensionDefinition'; | ||
DIRECTIVE_DEF: 'DirectiveDef'; | ||
@@ -115,0 +117,0 @@ IMPLEMENTS: 'Implements'; |
@@ -14,2 +14,4 @@ /** | ||
export { InsertTextFormat } from 'vscode-languageserver-types'; | ||
import type { ASTNode, GraphQLSchema } from 'graphql'; | ||
@@ -16,0 +18,0 @@ |
@@ -306,7 +306,4 @@ /** | ||
Object.entries(variableToType).forEach(([variableName, type]) => { | ||
const { | ||
definition, | ||
required, | ||
definitions, | ||
} = getJSONSchemaFromGraphQLType(type, options); | ||
const { definition, required, definitions } = | ||
getJSONSchemaFromGraphQLType(type, options); | ||
jsonSchema.properties[variableName] = definition; | ||
@@ -313,0 +310,0 @@ if (required) { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
775929
14412
0
0