@platformos/pos-cli
Version:
Manage your platformOS application
204 lines (170 loc) • 6.9 kB
JavaScript
;
var _graphql = require("graphql");
var _codemirror = _interopRequireDefault(require("codemirror"));
var _getTypeInfo = _interopRequireDefault(require("./utils/getTypeInfo"));
var _SchemaReference = require("./utils/SchemaReference");
require("./utils/info-addon");
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 GraphQL "info" tooltips for CodeMirror.
*
* When hovering over a token, this presents a tooltip explaining it.
*
* Options:
*
* - schema: GraphQLSchema provides positionally relevant info.
* - hoverTime: The number of ms to wait before showing info. (Default 500)
* - renderDescription: Convert a description to some HTML, Useful since
* descriptions are often Markdown formatted.
* - onClick: A function called when a named thing is clicked.
*
*/
_codemirror.default.registerHelper('info', 'graphql', (token, options) => {
if (!options.schema || !token.state) {
return;
}
const state = token.state;
const kind = state.kind;
const step = state.step;
const typeInfo = (0, _getTypeInfo.default)(options.schema, token.state); // Given a Schema and a Token, produce the contents of an info tooltip.
// To do this, create a div element that we will render "into" and then pass
// it to various rendering functions.
if (kind === 'Field' && step === 0 && typeInfo.fieldDef || kind === 'AliasedField' && step === 2 && typeInfo.fieldDef) {
const into = document.createElement('div');
renderField(into, typeInfo, options);
renderDescription(into, options, typeInfo.fieldDef);
return into;
} else if (kind === 'Directive' && step === 1 && typeInfo.directiveDef) {
const into = document.createElement('div');
renderDirective(into, typeInfo, options);
renderDescription(into, options, typeInfo.directiveDef);
return into;
} else if (kind === 'Argument' && step === 0 && typeInfo.argDef) {
const into = document.createElement('div');
renderArg(into, typeInfo, options);
renderDescription(into, options, typeInfo.argDef);
return into;
} else if (kind === 'EnumValue' && typeInfo.enumValue && typeInfo.enumValue.description) {
const into = document.createElement('div');
renderEnumValue(into, typeInfo, options);
renderDescription(into, options, typeInfo.enumValue);
return into;
} else if (kind === 'NamedType' && typeInfo.type && typeInfo.type.description) {
const into = document.createElement('div');
renderType(into, typeInfo, options, typeInfo.type);
renderDescription(into, options, typeInfo.type);
return into;
}
});
function renderField(into, typeInfo, options) {
renderQualifiedField(into, typeInfo, options);
renderTypeAnnotation(into, typeInfo, options, typeInfo.type);
}
function renderQualifiedField(into, typeInfo, options) {
const fieldName = typeInfo.fieldDef.name;
if (fieldName.slice(0, 2) !== '__') {
renderType(into, typeInfo, options, typeInfo.parentType);
text(into, '.');
}
text(into, fieldName, 'field-name', options, (0, _SchemaReference.getFieldReference)(typeInfo));
}
function renderDirective(into, typeInfo, options) {
const name = '@' + typeInfo.directiveDef.name;
text(into, name, 'directive-name', options, (0, _SchemaReference.getDirectiveReference)(typeInfo));
}
function renderArg(into, typeInfo, options) {
if (typeInfo.directiveDef) {
renderDirective(into, typeInfo, options);
} else if (typeInfo.fieldDef) {
renderQualifiedField(into, typeInfo, options);
}
const name = typeInfo.argDef.name;
text(into, '(');
text(into, name, 'arg-name', options, (0, _SchemaReference.getArgumentReference)(typeInfo));
renderTypeAnnotation(into, typeInfo, options, typeInfo.inputType);
text(into, ')');
}
function renderTypeAnnotation(into, typeInfo, options, t) {
text(into, ': ');
renderType(into, typeInfo, options, t);
}
function renderEnumValue(into, typeInfo, options) {
const name = typeInfo.enumValue.name;
renderType(into, typeInfo, options, typeInfo.inputType);
text(into, '.');
text(into, name, 'enum-value', options, (0, _SchemaReference.getEnumValueReference)(typeInfo));
}
function renderType(into, typeInfo, options, t) {
if (t instanceof _graphql.GraphQLNonNull) {
renderType(into, typeInfo, options, t.ofType);
text(into, '!');
} else if (t instanceof _graphql.GraphQLList) {
text(into, '[');
renderType(into, typeInfo, options, t.ofType);
text(into, ']');
} else {
text(into, t.name, 'type-name', options, (0, _SchemaReference.getTypeReference)(typeInfo, t));
}
}
function renderDescription(into, options, def) {
const description = def.description;
if (description) {
const descriptionDiv = document.createElement('div');
descriptionDiv.className = 'info-description';
if (options.renderDescription) {
descriptionDiv.innerHTML = options.renderDescription(description);
} else {
descriptionDiv.appendChild(document.createTextNode(description));
}
into.appendChild(descriptionDiv);
}
renderDeprecation(into, options, def);
}
function renderDeprecation(into, options, def) {
const reason = def.deprecationReason;
if (reason) {
const deprecationDiv = document.createElement('div');
deprecationDiv.className = 'info-deprecation';
if (options.renderDescription) {
deprecationDiv.innerHTML = options.renderDescription(reason);
} else {
deprecationDiv.appendChild(document.createTextNode(reason));
}
const label = document.createElement('span');
label.className = 'info-deprecation-label';
label.appendChild(document.createTextNode('Deprecated: '));
deprecationDiv.insertBefore(label, deprecationDiv.firstChild);
into.appendChild(deprecationDiv);
}
}
function text(into, content, className, options = {
onClick: null
}, ref) {
if (className) {
const onClick = options.onClick;
let node;
if (onClick) {
node = document.createElement('a'); // Providing a href forces proper a tag behavior, though we don't actually
// want clicking the node to navigate anywhere.
node.href = 'javascript:void 0'; // eslint-disable-line no-script-url
node.addEventListener('click', e => {
onClick(ref, e);
});
} else {
node = document.createElement('span');
}
node.className = className;
node.appendChild(document.createTextNode(content));
into.appendChild(node);
} else {
into.appendChild(document.createTextNode(content));
}
}