Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

microfiber

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

microfiber - npm Package Compare versions

Comparing version 0.0.6 to 0.0.7

dist/etc.js

971

dist/index.js

@@ -6,958 +6,27 @@ "use strict";

});
exports.Microfiber = exports.KINDS = void 0;
exports.digUnderlyingType = digUnderlyingType;
exports.isReservedType = isReservedType;
exports.typesAreSame = typesAreSame;
var _lodash = _interopRequireDefault(require("lodash.get"));
var _microfiber = require("./microfiber");
var _lodash2 = _interopRequireDefault(require("lodash.unset"));
var _lodash3 = _interopRequireDefault(require("lodash.defaults"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
// Constructor Options
const ANALYZE_DEFAULT = true;
const NORMALIZE_DEFAULT = true;
const FIX_QUERY_MUTATION_TYPES_DEFAULT = true;
const REMOVE_UNUSED_TYPES_DEFAULT = true; // Method options
// const REMOVE_FIELDS_OF_TYPE_DEFAULT = true
// const REMOVE_INPUT_FIELDS_OF_TYPE_DEFAULT = true
// const REMOVE_POSSIBLE_TYPES_OF_TYPE_DEFAULT = true
// const REMOVE_ARGS_OF_TYPE_DEFAULT = true
const CLEANUP_DEFAULT = true; // GraphQL constants
const KIND_SCALAR = 'SCALAR';
const KIND_OBJECT = 'OBJECT';
const KIND_INTERFACE = 'INTERFACE';
const KIND_UNION = 'UNION';
const KIND_ENUM = 'ENUM';
const KIND_INPUT_OBJECT = 'INPUT_OBJECT';
const KIND_LIST = 'LIST';
const KIND_NON_NULL = 'NON_NULL';
const KINDS = Object.freeze({
SCALAR: KIND_SCALAR,
OBJECT: KIND_OBJECT,
INTERFACE: KIND_INTERFACE,
UNION: KIND_UNION,
ENUM: KIND_ENUM,
INPUT_OBJECT: KIND_INPUT_OBJECT,
LIST: KIND_LIST,
NON_NULL: KIND_NON_NULL
}); // TODO:
//
// interfaces
//
// optimize to only clean if "dirty" and when pulling schema out
exports.KINDS = KINDS;
const defaultOpts = Object.freeze({
analyze: ANALYZE_DEFAULT,
normalize: NORMALIZE_DEFAULT,
fixQueryAndMutationTypes: FIX_QUERY_MUTATION_TYPES_DEFAULT,
// Remove Types that are not referenced anywhere by anything
removeUnusedTypes: REMOVE_UNUSED_TYPES_DEFAULT,
// Remove things whose Types are not found due to being removed
removeFieldsWithMissingTypes: true,
removeArgsWithMissingTypes: true,
removeInputFieldsWithMissingTypes: true,
removePossibleTypesOfMissingTypes: true,
// Remove all the types and things that are unreferenced immediately?
cleanupSchemaImmediately: true
}); // Map some opts to their corresponding removeType params for proper defaulting
const optsToRemoveTypeParamsMap = Object.freeze({
// removeFieldsOfType: 'removeFieldsWithMissingTypes',
// removeArgsOfType: 'removeArgsWithMissingTypes',
// removeInputFieldsOfType: 'removeInputFieldsWithMissingTypes',
// removePossibleTypesOfType: 'removePossibleTypesOfMissingTypes',
removeFieldsWithMissingTypes: 'removeFieldsOfType',
removeArgsWithMissingTypes: 'removeArgsOfType',
removeInputFieldsWithMissingTypes: 'removeInputFieldsOfType',
removePossibleTypesOfMissingTypes: 'removePossibleTypesOfType'
Object.keys(_microfiber).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _microfiber[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _microfiber[key];
}
});
});
const kindToFieldPropertyMap = Object.freeze({
[KIND_OBJECT]: 'fields',
[KIND_INPUT_OBJECT]: 'inputFields' // [KIND_INTERFACE]: 'interfaces',
});
var _etc = require("./etc");
function digUnderlyingType(type) {
while ([KIND_NON_NULL, KIND_LIST].includes(type.kind)) {
type = type.ofType;
}
return type;
}
function isReservedType(type) {
return type.name.startsWith('__');
}
class Microfiber {
constructor(response, opts = {}) {
if (!response) {
throw new Error('No response provided!');
Object.keys(_etc).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (key in exports && exports[key] === _etc[key]) return;
Object.defineProperty(exports, key, {
enumerable: true,
get: function () {
return _etc[key];
}
opts = (0, _lodash3.default)({}, opts, defaultOpts);
this.setOpts(opts); // The rest of the initialization can be handled by this public method
this.setResponse(response);
}
setOpts(opts) {
this.opts = opts || {};
} // Set/change the response on the instance
setResponse(responseIn) {
const response = JSON.parse(JSON.stringify(responseIn));
const normalizedResponse = Microfiber.normalizeIntrospectionResponse(response);
if (normalizedResponse !== response) {
this._wasNormalized = true;
}
this.schema = (0, _lodash.default)(normalizedResponse, '__schema');
if (this.opts.fixQueryAndMutationTypes) {
this.fixQueryAndMutationTypes();
} // OK, time to validate
this.validate();
if (this.opts.analyze) {
this.analyze();
}
if (this.opts.cleanupSchemaImmediately) {
this._cleanSchema();
}
}
static normalizeIntrospectionResponse(response) {
if (response && response.data) {
return response.data;
}
return response;
}
static digUnderlyingType(type) {
return digUnderlyingType(type);
}
validate() {
if (!this.schema) {
throw new Error('No schema property detected!');
}
if (!this.schema.types) {
throw new Error('No types detected!');
} // Must have a Query type...but not necessarily a Mutation type
if (!(0, _lodash.default)(this.schema, `queryType.name`)) {
throw new Error(`No queryType detected!`);
}
}
analyze() {
// Map the kind + name to the index in the types array
this.typeToIndexMap = {};
this.fieldsOfTypeMap = {};
this.inputFieldsOfTypeMap = {}; // AKA Unions
this.possibleTypesOfTypeMap = {};
this.argsOfTypeMap = {}; // Need to keep track of these so that we never remove them for not being referenced
this.queryTypeName = (0, _lodash.default)(this.schema, 'queryType.name');
this.mutationTypeName = (0, _lodash.default)(this.schema, 'mutationType.name');
this.subscriptionTypeName = (0, _lodash.default)(this.schema, 'subscriptionType.name');
for (let typesIdx = 0; typesIdx < this.schema.types.length; typesIdx++) {
const type = this.schema.types[typesIdx];
if (isUndef(type)) {
continue;
}
const {
kind,
name
} = type; // These come in as null, not undefined
const fields = type.fields || [];
const inputFields = type.inputFields || [];
const possibleTypes = type.possibleTypes || [];
const typesKey = buildKey({
kind,
name
});
this.typeToIndexMap[typesKey] = typesIdx;
for (let fieldsIdx = 0; fieldsIdx < fields.length; fieldsIdx++) {
const field = fields[fieldsIdx];
if (isUndef(field)) {
continue;
}
const fieldType = digUnderlyingType(field.type); // This should always be arrays...maybe empty, never null
const args = field.args || [];
const fieldsKey = buildKey(fieldType);
if (!this.fieldsOfTypeMap[fieldsKey]) {
this.fieldsOfTypeMap[fieldsKey] = [];
}
const fieldPath = `types.${typesIdx}.fields.${fieldsIdx}`;
this.fieldsOfTypeMap[fieldsKey].push(fieldPath);
for (let argsIdx = 0; argsIdx < args.length; argsIdx++) {
const arg = args[argsIdx];
if (isUndef(arg)) {
continue;
}
const argType = digUnderlyingType(arg.type);
const argsKey = buildKey(argType);
if (!this.argsOfTypeMap[argsKey]) {
this.argsOfTypeMap[argsKey] = [];
}
const argPath = `${fieldPath}.args.${argsIdx}`;
this.argsOfTypeMap[argsKey].push(argPath);
}
}
for (let inputFieldsIdx = 0; inputFieldsIdx < inputFields.length; inputFieldsIdx++) {
const inputField = inputFields[inputFieldsIdx];
if (isUndef(inputField)) {
continue;
}
const inputFieldType = digUnderlyingType(inputField.type);
const inputFieldsKey = buildKey(inputFieldType);
if (!this.inputFieldsOfTypeMap[inputFieldsKey]) {
this.inputFieldsOfTypeMap[inputFieldsKey] = [];
}
const inputFieldPath = `types.${typesIdx}.inputFields.${inputFieldsIdx}`;
this.inputFieldsOfTypeMap[inputFieldsKey].push(inputFieldPath);
}
for (let possibleTypesIdx = 0; possibleTypesIdx < possibleTypes.length; possibleTypesIdx++) {
const possibleType = possibleTypes[possibleTypesIdx];
if (isUndef(possibleType)) {
continue;
}
const possibleTypeType = digUnderlyingType(possibleType);
const possibleTypeKey = buildKey(possibleTypeType);
if (!this.possibleTypesOfTypeMap[possibleTypeKey]) {
this.possibleTypesOfTypeMap[possibleTypeKey] = [];
}
const possibleTypePath = `types.${typesIdx}.possibleTypes.${possibleTypesIdx}`;
this.possibleTypesOfTypeMap[possibleTypeKey].push(possibleTypePath);
}
}
}
getResponse() {
const clonedResponse = {
__schema: this._cloneSchema()
};
if (this._wasNormalized) {
return {
data: clonedResponse
};
}
return clonedResponse;
}
getType({
kind = KIND_OBJECT,
name
}) {
return this.schema.types[this.getTypeIndex({
kind,
name
})];
}
getAllTypes({
includeReserved = false,
includeQuery = false,
includeMutation = false,
includeSubscription = false
} = {}) {
const queryType = this.getQueryType();
const mutationType = this.getMutationType();
const subscriptionType = this.getSubscriptionType();
return this.schema.types.filter(type => {
if (!includeReserved && isReservedType(type)) {
return false;
}
if (queryType && !includeQuery && typesAreSame(type, queryType)) {
return false;
}
if (mutationType && !includeMutation && typesAreSame(type, mutationType)) {
return false;
}
if (subscriptionType && !includeSubscription && typesAreSame(type, subscriptionType)) {
return false;
}
return true;
});
}
getTypeIndex({
kind,
name
}) {
const key = buildKey({
kind,
name
});
if (Object.prototype.hasOwnProperty.call(this.typeToIndexMap, key)) {
return this.typeToIndexMap[key];
}
return false;
}
getQueryType() {
if (!this.queryTypeName) {
return false;
}
return this.getType({
kind: KIND_OBJECT,
name: this.queryTypeName
});
}
getQuery({
name
}) {
const queryType = this.getQueryType();
if (!queryType) {
return false;
}
return this.getField({
typeKind: queryType.kind,
typeName: queryType.name,
fieldName: name
});
}
getMutationType() {
if (!this.mutationTypeName) {
return false;
}
return this.getType({
kind: KIND_OBJECT,
name: this.mutationTypeName
});
}
getMutation({
name
}) {
const mutationType = this.getMutationType();
if (!mutationType) {
return false;
}
return this.getField({
typeKind: mutationType.kind,
typeName: mutationType.name,
fieldName: name
});
}
getSubscriptionType() {
if (!this.subscriptionTypeName) {
return false;
}
return this.getType({
kind: KIND_OBJECT,
name: this.subscriptionTypeName
});
}
getSubscription({
name
}) {
const subscriptionType = this.getSubscriptionType();
if (!subscriptionType) {
return false;
}
return this.getField({
typeKind: subscriptionType.kind,
typeName: subscriptionType.name,
fieldName: name
});
}
getField({
typeKind = KIND_OBJECT,
typeName,
fieldName
}) {
const type = this.getType({
kind: typeKind,
name: typeName
});
if (!type) {
return;
}
const fieldsProperty = kindToFieldPropertyMap[typeKind];
if (!(fieldsProperty && type[fieldsProperty])) {
return;
}
return type[fieldsProperty].find(field => field.name === fieldName);
}
getInputField({
inputName,
inputFieldName
}) {
return this.getField({
typeName: inputName,
typeKind: KIND_INPUT_OBJECT,
fieldName: inputFieldName
});
}
getArg({
typeKind,
typeName,
fieldName,
argName
}) {
const field = this.getField({
typeKind,
typeName,
fieldName
});
if (!(field && field.args.length)) {
return;
}
return field.args.find(arg => arg.name === argName);
}
fixQueryAndMutationTypes(response) {
for (const [key, defaultTypeName] of [['queryType', 'Query'], ['mutationType', 'Mutation']]) {
const queryOrMutationTypeName = (0, _lodash.default)(response, `__schema.${key}.name`);
if (queryOrMutationTypeName && !this.getType({
kind: KIND_OBJECT,
name: queryOrMutationTypeName
})) {
this.schema[key] = {
name: defaultTypeName
};
}
}
}
removeType({
kind = KIND_OBJECT,
name,
removeFieldsOfType,
removeInputFieldsOfType,
removePossibleTypesOfType,
removeArgsOfType,
cleanup = CLEANUP_DEFAULT
}) {
const typeKey = buildKey({
kind,
name
});
if (!Object.prototype.hasOwnProperty.call(this.typeToIndexMap, typeKey)) {
return false;
}
const typeIndex = this.typeToIndexMap[typeKey];
if (isUndef(typeIndex)) {
return false;
} // Create an object of some of the opts, but mapped to keys that match the params
// of this method. They will then be used as the default value for the params
// so that constructor opts will be the default, but they can be overridden in
// the call.
const mappedOpts = mapProps({
props: this.opts,
map: optsToRemoveTypeParamsMap
});
const mergedOpts = (0, _lodash3.default)({
removeFieldsOfType,
removeInputFieldsOfType,
removePossibleTypesOfType,
removeArgsOfType
}, mappedOpts); // If we are going to clean up afterwards, then the others should not have to
const shouldOthersClean = !cleanup;
const originalSchema = this._cloneSchema();
try {
delete this.schema.types[typeIndex];
delete this.typeToIndexMap[typeKey];
if (mergedOpts.removeArgsOfType) {
this.removeArgumentsOfType({
kind,
name,
cleanup: shouldOthersClean
});
}
if (mergedOpts.removeFieldsOfType) {
this.removeFieldsOfType({
kind,
name,
cleanup: shouldOthersClean
});
}
if (mergedOpts.removeInputFieldsOfType) {
this.removeInputFieldsOfType({
kind,
name,
cleanup: shouldOthersClean
});
} // AKA Unions
if (mergedOpts.removePossibleTypesOfType) {
this.removePossibleTypesOfType({
kind,
name,
cleanup: shouldOthersClean
});
}
if (cleanup) {
this._cleanSchema();
}
return true;
} catch (err) {
this.schema = originalSchema;
throw err;
}
}
removeField({
typeKind,
typeName,
fieldName,
cleanup = CLEANUP_DEFAULT
}) {
const type = this.getType({
kind: typeKind,
name: typeName
});
if (!(type && type.fields)) {
return false;
} // TODO: build a map for the locations of fields on types?
type.fields = type.fields.filter(field => field.name !== fieldName);
if (cleanup) {
this._cleanSchema();
}
}
removeArg({
typeKind,
typeName,
fieldName,
argName,
cleanup = CLEANUP_DEFAULT
}) {
const field = this.getField({
typeKind,
typeName,
fieldName
}); // field.args should alwys be an array, never null
if (!field) {
return false;
} // TODO: build a map for the locations of args on fields?
field.args = field.args.filter(arg => arg.name !== argName);
if (cleanup) {
this._cleanSchema();
}
}
removeQuery({
name,
cleanup = CLEANUP_DEFAULT
}) {
if (!this.queryTypeName) {
return false;
}
this.removeField({
typeKind: KIND_OBJECT,
typeName: this.queryTypeName,
fieldName: name,
cleanup
});
}
removeMutation({
name,
cleanup = CLEANUP_DEFAULT
}) {
if (!this.mutationTypeName) {
return false;
}
this.removeField({
typeKind: KIND_OBJECT,
typeName: this.mutationTypeName,
fieldName: name,
cleanup
});
}
removeSubscription({
name,
cleanup = CLEANUP_DEFAULT
}) {
if (!this.subscriptionTypeName) {
return false;
}
this.removeField({
typeKind: KIND_OBJECT,
typeName: this.subscriptionTypeName,
fieldName: name,
cleanup
});
}
removeFieldsOfType({
kind,
name,
cleanup = CLEANUP_DEFAULT
}) {
return this._removeThingsOfType({
kind,
name,
map: this.fieldsOfTypeMap,
cleanup
});
}
removeInputFieldsOfType({
kind,
name,
cleanup = CLEANUP_DEFAULT
}) {
return this._removeThingsOfType({
kind,
name,
map: this.inputFieldsOfTypeMap,
cleanup
});
} // AKA Unions
removePossibleTypesOfType({
kind,
name,
cleanup = CLEANUP_DEFAULT
}) {
return this._removeThingsOfType({
kind,
name,
map: this.possibleTypesOfTypeMap,
cleanup
});
}
removeArgumentsOfType({
kind,
name,
cleanup = CLEANUP_DEFAULT
}) {
return this._removeThingsOfType({
kind,
name,
map: this.argsOfTypeMap,
cleanup
});
} // Remove just a single possible value for an Enum, but not the whole Enum
removeEnumValue({
name,
value
}) {
const type = this.getType({
kind: KIND_ENUM,
name
});
if (!(type && type.enumValues)) {
return false;
}
type.enumValues = type.enumValues.filter(enumValue => enumValue.name !== value);
} // private
_removeThingsOfType({
kind,
name,
map,
cleanup = CLEANUP_DEFAULT
}) {
const key = buildKey({
kind,
name
});
for (const path of map[key] || []) {
(0, _lodash2.default)(this.schema, path);
}
delete map[key];
if (cleanup) {
this._cleanSchema();
}
}
_cloneSchema() {
return JSON.parse(JSON.stringify(this.schema));
} // Removes all the undefined gaps created by various removals
_cleanSchema() {
// Used to compare the schema before and after it was cleaned
const schemaToStart = JSON.stringify(this.schema);
const typesEncountered = new Set();
const types = []; // The Query, Mutation and Subscription Types should never be removed due to not being referenced
// by anything
if (this.queryTypeName) {
typesEncountered.add(buildKey({
kind: KIND_OBJECT,
name: this.queryTypeName
}));
}
if (this.mutationTypeName) {
typesEncountered.add(buildKey({
kind: KIND_OBJECT,
name: this.mutationTypeName
}));
}
if (this.subscriptionTypeName) {
typesEncountered.add(buildKey({
kind: KIND_OBJECT,
name: this.subscriptionTypeName
}));
}
for (const type of this.schema.types) {
if (!type) {
continue;
}
types.push(type);
const fields = [];
for (const field of type.fields || []) {
if (isUndef(field)) {
continue;
}
const fieldType = digUnderlyingType(field.type); // Don't add it if its return type does not exist
if (!this._hasType(fieldType)) {
continue;
} // Keep track of this so we know what we can remove
typesEncountered.add(buildKey(fieldType));
const args = [];
for (const arg of field.args || []) {
if (isUndef(arg)) {
continue;
}
const argType = digUnderlyingType(arg.type); // Don't add it if its return type does not exist
if (!this._hasType(argType)) {
continue;
} // Keep track of this so we know what we can remove
typesEncountered.add(buildKey(argType));
args.push(arg);
} // Args will always be an array. Possible empty, but never null
field.args = args;
fields.push(field);
} // Fields will be null rather than empty array if no fields
type.fields = fields.length ? fields : null;
const inputFields = []; // Don't add it in if it's undefined, or the type is gone
for (const inputField of type.inputFields || []) {
if (isUndef(inputField)) {
continue;
}
const inputFieldType = digUnderlyingType(inputField.type); // Don't add it if its return type does not exist
if (!this._hasType(inputFieldType)) {
continue;
} // Keep track of this so we know what we can remove
typesEncountered.add(buildKey(inputFieldType));
inputFields.push(inputField);
} // InputFields will be null rather than empty array if no inputFields
type.inputFields = inputFields.length ? inputFields : null;
const possibleTypes = [];
for (const possibleType of type.possibleTypes || []) {
if (isUndef(possibleType)) {
continue;
} // possibleTypes array entries have no envelope for the type
// so do not do possibleType.type here
const possibleTypeType = digUnderlyingType(possibleType); // Don't add it if its return type does not exist
if (!this._hasType(possibleTypeType)) {
continue;
} // Keep track of this so we know what we can remove
typesEncountered.add(buildKey(possibleTypeType));
possibleTypes.push(possibleType);
} // PossibleTypes will be null rather than emptry array if no possibleTypes
type.possibleTypes = possibleTypes.length ? possibleTypes : null;
} // Only include Types that we encountered - if the options say to do so
const possiblyFilteredTypes = this.opts.removeUnusedTypes ? types.filter(type => isReservedType(type) || typesEncountered.has(buildKey(type))) : types; // Replace the Schema
this.schema = _objectSpread(_objectSpread({}, this.schema), {}, {
types: possiblyFilteredTypes
}); // Need to re-analyze it, too
this.analyze(); // If the schema was changed by this cleanup, we should run it again to see if other things
// should be removed...and continue to do so until the schema is stable.
if (schemaToStart !== JSON.stringify(this.schema)) {
return this._cleanSchema();
}
}
_hasType({
kind,
name
}) {
const key = buildKey({
kind,
name
});
return Object.prototype.hasOwnProperty.call(this.typeToIndexMap, key);
}
}
exports.Microfiber = Microfiber;
function buildKey({
kind,
name
}) {
return kind + ':' + name;
}
function isUndef(item) {
return typeof item === 'undefined';
}
function typesAreSame(typeA, typeB) {
return typeA.kind === typeB.kind && typeA.name === typeB.name;
}
function mapProps({
props,
map
}) {
return Object.entries(map).reduce((acc, [from, to]) => {
if (Object.prototype.hasOwnProperty.call(props, from)) {
acc[to] = props[to];
}
return acc;
}, {});
}
});
});
{
"name": "microfiber",
"version": "0.0.6",
"version": "0.0.7",
"description": "A library to query and manipulate GraphQL Introspection Query results in some useful ways.",

@@ -5,0 +5,0 @@ "author": "Chris Newhouse",

@@ -8,11 +8,344 @@ <a href="https://www.useanvil.com"><img src="/static/anvil.png" width="50"></a>

A library to query and manipulate GraphQL Introspection Query results in some useful ways. What ways you ask?
A library to query and manipulate GraphQL Introspection Query results in some useful ways.
How about:
- Digging through your Introspection Query Results for a specific Query, Mutation, Type, Field, Argument or Subscription.
- Removing a specific Query, Mutation, Type, Field/InputField, Argument or Subscription from your Introspection Query Results.
- Removing Queries, Mutations, Fields/InputFields or Arguments that refer to Type that does not exist in - or has been removed from - your Introspection Query Results.
Yay!
It's called `microfiber` because it is heavily used to do the cleaning and manipulation in [SpectaQL][spectaql]...it *cleans* the *spectacles*, get it?!
But, we also wanted to have a more intuitive, literal name so that people could find it. Hence it's also known as `@anvilco/graphql-introspection-tools`.
## Getting Started
1. Install `microfiber`
```sh
npm install microfiber
# OR
yarn add microfiber
```
2. Clean your GraphQL Introspection Query Results
```node
import { Microfiber } from 'microfiber'
const introspectionQueryResults = {...}
const microfiber = new Microfiber(introspectionQueryResults)
// ...do some things to your schema with `microfiber`
const cleanedIntrospectonQueryResults = microfiber.getResponse()
// ...do something with your cleaned Introspection Query Results.
```
## Usage
Coming soon! Please avoid usage until then as things are changing rapidly.
### class Microfiber
Most of the useful stuff in this library is done through creating a new Microfiber class instance with your Introspection Query Results, and querying or manipulating it via that instance. Here are most of the interesting bits to know about class behavior.
---
#### constructor
```node
const introspectionQueryResponse = {...}
// Here are the publicly supported options and their sane defaults:
const options = {
// Some GraphQL implementations have non-standard Query, Mutation and/or Subscription
// type names. This option will fix them if they're messed up in the Introspection Query
// Results
fixQueryAndMutationAndSubscriptionTypes: true,
// Remove Types that are not referenced anywhere by anything
removeUnusedTypes: true,
// Remove things whose Types are not found due to being removed
removeFieldsWithMissingTypes: true,
removeArgsWithMissingTypes: true,
removeInputFieldsWithMissingTypes: true,
removePossibleTypesOfMissingTypes: true,
// Remove all the types and things that are unreferenced immediately?
cleanupSchemaImmediately: true,
}
const microfiber = new Microfiber(introspectionQueryResponse, options)
```
---
#### cleanSchema
Clean up the schema by removing:
- Fields or Input Fields whose Type does not exist in the schema.
- Args whose Type does not exist in the schema.
- Possible Types in a Union that do not exist in the schema.
- Queries or Mutations whose return Type does not exist in the schema.
This method is usually called after altering the schema in any way so as to not leave any dangling/orphaned things around the schema.
```node
microfiber.cleanSchema()
```
---
#### getResponse
Get out the Introspection Query Result that you have manipulated with Microfiber as an Object.
```node
const cleanedResponse = microfiber.getResponse()
```
---
#### getAllTypes
Get all the Types from your schema as an Array of Objects. Supported options and their sane defaults are shown.
```node
const allTypes = microfiber.getAllTypes({
// Include reserved GraphQL types?
includeReserved: false,
// Include the Query type?
includeQuery: false,
// Include the Mutation type?
includeMutation: false,
// Include the Subscription type?
includeSubscription: false,
})
```
---
#### getType
Get a specific Type from yoyur schema. Supported params and their sane defaults are shown.
```node
const type = microfiber.getType({ kind: 'OBJECT', name })
```
---
#### getQueryType
Get the Query Type from your schema.
```node
const queryType = microfiber.getQueryType()
```
---
#### getQuery
Get a specific Query from your schema.
```node
const query = microfiber.getQuery({ name })
```
---
#### getMutationType
Get the Mutation Type from your schema.
```node
const mutationType = microfiber.getMutationType()
```
---
#### getMutation
Get a specific Mutation from your schema.
```node
const mutation = microfiber.getMutation({ name })
```
---
#### getSubscriptionType
Get the Subscription Type from your schema.
```node
const subscriptionType = microfiber.getSubscription()
```
---
#### getSubscription
Get a specific Subscription from your schema.
```node
const subscription = microfiber.getSubscription({ name })
```
---
#### getField
Get a specific Field from your schema. Supported params and their sane defaults are shown.
```node
const field = microfiber.getField({ typeKind: 'OBJECT', typeName, fieldName })
```
---
#### getInputField
Get a specific InputField from your schema.
```node
const inputField = microfiber.getInputField({ typeName, fieldName })
```
---
#### getArg
Get a specific Arg from your schema. Supported params and their sane defaults are shown.
```node
const arg = microfiber.getArg({ typeKind: 'OBJECT', typeName, fieldName, argName })
```
---
#### removeType
Remove a Type from your schema, and optionally the references to that Type elsewhere in your schema. Supported params and their sane defaults are shown.
```node
microfiber.removeType({
kind: 'OBJECT',
name,
// Clean up the schema afterwards?
cleanup: true,
// Remove occurances of this Type from other places?
removeFieldsOfType: constructorOptions.removeFieldsWithMissingTypes,
removeInputFieldsOfType: constructorOptions.removeInputFieldsWithMissingTypes,
removePossibleTypesOfType: constructorOptions.removePossibleTypesOfMissingTypes,
removeArgsOfType: constructorOptions.removeArgsWithMissingTypes,
})
```
---
#### removeField
Remove a specific Field from a specific Type in your schema. Supported params and their sane defaults are shown.
```node
microfiber.removeField({
typeKind: 'OBJECT',
typeName,
fieldName,
// Clean up the schema afterwards?
cleanup: true,
})
```
---
#### removeInputField
Remove a specific Input Field from a specific Input Object in your schema. Supported params and their sane defaults are shown.
```node
microfiber.removeInputField({
typeName,
fieldName,
// Clean up the schema afterwards?
cleanup: true,
})
```
---
#### removeArg
Remove a specific Arg from a specific Field or Input Field in your schema. Supported params and their sane defaults are shown.
```node
microfiber.removeArg({
typeKind,
typeName,
fieldName,
argName,
// Clean up the schema afterwards?
cleanup: true,
})
```
---
#### removeEnumValue
Remove a specifc Enum value from an Enum Type in your schema. Supported params are shown.
```node
microfiber.removeEnumValue({
// The name of the Enum Type
name,
// The Enum value you want to remove
value,
})
```
---
#### removePossibleType
Remove a Possible Type from a specific Union Type in your schema. Supported params and sane defaults are shown.
```node
microfiber.removePossibleType({
// The name of the Union Type
typeName,
// The Kind of the possible Type you want to remove
possibleTypeKind,
// The name of the possible Type you want to remove
possibleTypeName,
// Clean up the schema afterwards?
cleanup: true,
})
```
---
#### removeQuery
Remove a specific Query from your schema. Supported params and their sane defaults are shown.
```node
microfiber.removeQuery({
name,
// Clean up the schema afterwards?
cleanup: true,
})
```
---
#### removeMutation
Remove a specific Mutation from your schema. Supported params and their sane defaults are shown.
```node
microfiber.removeMutation({
name,
// Clean up the schema afterwards?
cleanup: true,
})
```
---
#### removeSubscription
Remove a specific Subscription from your schema. Supported params and their sane defaults are shown.
```node
microfiber.removeSubscription({
name,
// Clean up the schema afterwards?
cleanup: true,
})
```
### Other exports from this library
There are some other exports from this library, not just the `Microfiber` class.
---
#### KINDS
An Object containing all the GraphQL Kind values you may encounter.
```node
import { KINDS } from 'microfiber'
console.log(KINDS)
// {
// SCALAR: 'SCALAR',
// OBJECT: 'OBJECT',
// INTERFACE: 'INTERFACE',
// UNION: 'UNION',
// ENUM: 'ENUM',
// INPUT_OBJECT: 'INPUT_OBJECT',
// LIST: 'LIST',
// NON_NULL: 'NON_NULL'
// }
```
---
#### typesAreSame
A function that compares 2 types and determines if they have the same Kind and Name.
```node
import { typesAreSame } from 'microfiber'
const typeA = { kind: 'OBJECT', name: 'Foo' }
const typeB = { kind: 'OBJECT', name: 'Bar' }
typesAreSame(typeA, typeB) // false
typesAreSame(typeA, typeA) // true
```
---
#### digUnderlyingType
A function that digs through any Non-Null and List nesting and returns the underlying Type.
```node
import { digUnderlyingType } from 'microfiber'
const nonNullableString = {
name: null,
kind: 'NON_NULL',
ofType: {
name: null,
kind: 'LIST',
ofType: {
name: 'String',
kind: 'SCALAR',
}
}
}
digUnderlyingType(nonNullableString) // { name: 'String', kind: 'SCALAR' }=
```
---
#### isReservedType
A function that returns a Boolean indicating whether a Type is special GraphQL reserved Type.
```node
import { isReservedType } from 'microfiber'
const myType = { name: 'Foo', ... }
const reservedType = { name: '__Foo', ... }
isReservedType(myType) // false
isReservedType(reservedType) // true
```
[npm]: https://badge.fury.io/js/microfiber.svg
[npm-downloads]: https://img.shields.io/npm/dw/microfiber
[npm-url]: https://www.npmjs.com/package/microfiber
[npm-url]: https://www.npmjs.com/package/microfiber
[spectaql]: https://github.com/anvilco/spectaql
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc