@platformos/pos-cli
Version:
Manage your platformOS application
146 lines (123 loc) • 5.21 kB
JavaScript
"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;
}