@graphql-tools/module-loader
Version:
A set of utils for faster development of GraphQL tools
126 lines (125 loc) • 4.18 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ModuleLoader = void 0;
const tslib_1 = require("tslib");
const fs_1 = require("fs");
const graphql_1 = require("graphql");
const { access } = fs_1.promises;
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()],
* })
* ```
*/
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 (0, fs_1.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 ((0, graphql_1.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 Promise.resolve(`${modulePath}`).then(s => tslib_1.__importStar(require(s)));
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);
}
}
exports.ModuleLoader = ModuleLoader;