graphql-config
Version:
The easiest way to configure your development environment with your GraphQL schema (supported by most tools, editors & IDEs)
125 lines (124 loc) • 4.31 kB
JavaScript
import { dirname, isAbsolute, relative, normalize } from 'path';
import { minimatch } from 'minimatch';
import { ExtensionMissingError } from './errors.js';
import { isLegacyProjectConfig } from './helpers/index.js';
export class GraphQLProjectConfig {
constructor({ filepath, name, config, extensionsRegistry, }) {
this.filepath = filepath;
this.dirpath = dirname(filepath);
this.name = name;
this.extensions = config.extensions || {};
if (isLegacyProjectConfig(config)) {
this.schema = config.schemaPath;
this.include = config.includes;
this.exclude = config.excludes;
this.isLegacy = true;
}
else {
this.schema = config.schema;
this.documents = config.documents;
this.include = config.include;
this.exclude = config.exclude;
this.isLegacy = false;
}
this._extensionsRegistry = extensionsRegistry;
}
hasExtension(name) {
return Boolean(this.extensions[name]);
}
extension(name) {
if (this.isLegacy) {
const extension = this.extensions[name];
if (!extension) {
throw new ExtensionMissingError(`Project ${this.name} is missing ${name} extension`);
}
return extension;
}
const extension = this._extensionsRegistry.get(name);
if (!extension) {
throw new ExtensionMissingError(`Project ${this.name} is missing ${name} extension`);
}
return {
...this.extensions[name],
schema: this.schema,
documents: this.documents,
include: this.include,
exclude: this.exclude,
};
}
async getSchema(out) {
return this.loadSchema(this.schema, out);
}
getSchemaSync(out) {
return this.loadSchemaSync(this.schema, out);
}
// Get Documents
async getDocuments() {
if (!this.documents) {
return [];
}
return this.loadDocuments(this.documents);
}
getDocumentsSync() {
if (!this.documents) {
return [];
}
return this.loadDocumentsSync(this.documents);
}
async loadSchema(pointer, out, options) {
return this._extensionsRegistry.loaders.schema.loadSchema(pointer, out, options);
}
loadSchemaSync(pointer, out, options) {
return this._extensionsRegistry.loaders.schema.loadSchemaSync(pointer, out, options);
}
// Load Documents
async loadDocuments(pointer, options) {
if (!pointer) {
return [];
}
return this._extensionsRegistry.loaders.documents.loadDocuments(pointer, options);
}
loadDocumentsSync(pointer, options) {
if (!pointer) {
return [];
}
return this._extensionsRegistry.loaders.documents.loadDocumentsSync(pointer, options);
}
// Rest
match(filepath) {
const isSchemaOrDocument = [this.schema, this.documents].some((pointer) => match(filepath, this.dirpath, pointer));
if (isSchemaOrDocument) {
return true;
}
const isExcluded = this.exclude ? match(filepath, this.dirpath, this.exclude) : false;
if (isExcluded) {
return false;
}
return this.include ? match(filepath, this.dirpath, this.include) : false;
}
}
function isSDLSchemaLike(schema) {
return schema.includes('\n');
}
// XXX: it works but uses Node.js - expose normalization of file and dir paths in config
function match(filepath, dirpath, pointer) {
if (!pointer) {
return false;
}
if (Array.isArray(pointer)) {
return pointer.some((p) => match(filepath, dirpath, p));
}
if (typeof pointer === 'string') {
if (isSDLSchemaLike(pointer)) {
return false;
}
const normalizedFilepath = normalize(isAbsolute(filepath) ? relative(dirpath, filepath) : filepath)
.split('\\')
.join('/');
return minimatch(normalizedFilepath, normalize(pointer).split('\\').join('/'), { dot: true });
}
if (typeof pointer === 'object') {
return match(filepath, dirpath, Object.keys(pointer)[0]);
}
return false;
}