UNPKG

@platformos/pos-cli

Version:

Manage your platformOS application

146 lines (123 loc) 5.21 kB
"use strict"; var _codemirror = _interopRequireDefault(require("codemirror")); var _graphql = require("graphql"); var _forEachState = _interopRequireDefault(require("../utils/forEachState")); var _hintList = _interopRequireDefault(require("../utils/hintList")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Copyright (c) 2019 GraphQL Contributors * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ /** * Registers a "hint" helper for CodeMirror. * * Using CodeMirror's "hint" addon: https://codemirror.net/demo/complete.html * Given an editor, this helper will take the token at the cursor and return a * list of suggested tokens. * * Options: * * - variableToType: { [variable: string]: GraphQLInputType } * * Additional Events: * * - hasCompletion (codemirror, data, token) - signaled when the hinter has a * new list of completion suggestions. * */ _codemirror.default.registerHelper('hint', 'graphql-variables', (editor, options) => { const cur = editor.getCursor(); const token = editor.getTokenAt(cur); const results = getVariablesHint(cur, token, options); if (results && results.list && results.list.length > 0) { results.from = _codemirror.default.Pos(results.from.line, results.from.column); results.to = _codemirror.default.Pos(results.to.line, results.to.column); _codemirror.default.signal(editor, 'hasCompletion', editor, results, token); } return results; }); function getVariablesHint(cur, token, options) { // If currently parsing an invalid state, attempt to hint to the prior state. const state = token.state.kind === 'Invalid' ? token.state.prevState : token.state; const kind = state.kind; const step = state.step; // Variables can only be an object literal. if (kind === 'Document' && step === 0) { return (0, _hintList.default)(cur, token, [{ text: '{' }]); } const variableToType = options.variableToType; if (!variableToType) { return; } const typeInfo = getTypeInfo(variableToType, token.state); // Top level should typeahead possible variables. if (kind === 'Document' || kind === 'Variable' && step === 0) { const variableNames = Object.keys(variableToType); return (0, _hintList.default)(cur, token, variableNames.map(name => ({ text: `"${name}": `, type: variableToType[name] }))); } // Input Object fields if (kind === 'ObjectValue' || kind === 'ObjectField' && step === 0) { if (typeInfo.fields) { const inputFields = Object.keys(typeInfo.fields).map(fieldName => typeInfo.fields[fieldName]); return (0, _hintList.default)(cur, token, inputFields.map(field => ({ text: `"${field.name}": `, type: field.type, description: field.description }))); } } // Input values. if (kind === 'StringValue' || kind === 'NumberValue' || kind === 'BooleanValue' || kind === 'NullValue' || kind === 'ListValue' && step === 1 || kind === 'ObjectField' && step === 2 || kind === 'Variable' && step === 2) { const namedInputType = (0, _graphql.getNamedType)(typeInfo.type); if (namedInputType instanceof _graphql.GraphQLInputObjectType) { return (0, _hintList.default)(cur, token, [{ text: '{' }]); } else if (namedInputType instanceof _graphql.GraphQLEnumType) { const valueMap = namedInputType.getValues(); const values = Object.keys(valueMap).map(name => valueMap[name]); return (0, _hintList.default)(cur, token, values.map(value => ({ text: `"${value.name}"`, type: namedInputType, description: value.description }))); } else if (namedInputType === _graphql.GraphQLBoolean) { return (0, _hintList.default)(cur, token, [{ text: 'true', type: _graphql.GraphQLBoolean, description: 'Not false.' }, { text: 'false', type: _graphql.GraphQLBoolean, description: 'Not true.' }]); } } } // Utility for collecting rich type information given any token's state // from the graphql-variables-mode parser. function getTypeInfo(variableToType, tokenState) { const info = { type: null, fields: null }; (0, _forEachState.default)(tokenState, state => { if (state.kind === 'Variable') { info.type = variableToType[state.name]; } else if (state.kind === 'ListValue') { const nullableType = (0, _graphql.getNullableType)(info.type); info.type = nullableType instanceof _graphql.GraphQLList ? nullableType.ofType : null; } else if (state.kind === 'ObjectValue') { const objectType = (0, _graphql.getNamedType)(info.type); info.fields = objectType instanceof _graphql.GraphQLInputObjectType ? objectType.getFields() : null; } else if (state.kind === 'ObjectField') { const objectField = state.name && info.fields ? info.fields[state.name] : null; info.type = objectField && objectField.type; } }); return info; }