UNPKG

@graphql-tools/module-loader

Version:

A set of utils for faster development of GraphQL tools

121 lines (120 loc) 3.95 kB
import { existsSync, promises as fsPromises } from 'fs'; import { isSchema } from 'graphql'; const { access } = fsPromises; const InvalidError = new Error(`Imported object was not a string, DocumentNode or GraphQLSchema`); const createLoadError = (error) => new Error('Unable to load schema from module: ' + `${error.message || /* istanbul ignore next */ error}`); // module:node/module#export function extractData(pointer) { const parts = pointer.replace(/^module\:/i, '').split('#'); if (!parts || parts.length > 2) { throw new Error('Schema pointer should match "module:path/to/module#export"'); } return { modulePath: parts[0], exportName: parts[1], }; } /** * * This loader loads documents and type definitions from a Node module * * ```js * const schema = await loadSchema('module:someModuleName#someNamedExport', { * loaders: [new ModuleLoader()], * }) * ``` */ export class ModuleLoader { isExpressionValid(pointer) { return typeof pointer === 'string' && pointer.toLowerCase().startsWith('module:'); } async canLoad(pointer) { if (this.isExpressionValid(pointer)) { const { modulePath } = extractData(pointer); try { const moduleAbsolutePath = require.resolve(modulePath); await access(moduleAbsolutePath); return true; } catch (e) { return false; } } return false; } canLoadSync(pointer) { if (this.isExpressionValid(pointer)) { const { modulePath } = extractData(pointer); try { const moduleAbsolutePath = require.resolve(modulePath); return existsSync(moduleAbsolutePath); } catch (e) { return false; } } return false; } async load(pointer) { try { const result = this.parse(pointer, await this.importModule(pointer)); if (result) { return [result]; } throw InvalidError; } catch (error) { throw createLoadError(error); } } loadSync(pointer) { try { const result = this.parse(pointer, this.importModuleSync(pointer)); if (result) { return [result]; } throw InvalidError; } catch (error) { throw createLoadError(error); } } parse(pointer, importedModule) { if (isSchema(importedModule)) { return { schema: importedModule, location: pointer, }; } else if (typeof importedModule === 'string') { return { location: pointer, rawSDL: importedModule, }; } else if (typeof importedModule === 'object' && importedModule.kind === 'Document') { return { location: pointer, document: importedModule, }; } } extractFromModule(mod, modulePath, identifier) { const thing = identifier ? mod[identifier] : mod; if (!thing) { throw new Error('Unable to import an object from module: ' + modulePath); } return thing; } // Sync and Async async importModule(pointer) { const { modulePath, exportName } = extractData(pointer); const imported = await import(modulePath); return this.extractFromModule(imported, modulePath, exportName || 'default'); } importModuleSync(pointer) { const { modulePath, exportName } = extractData(pointer); // eslint-disable-next-line @typescript-eslint/no-require-imports const imported = require(modulePath); return this.extractFromModule(imported, modulePath, exportName); } }