UNPKG

@graphql-tools/code-file-loader

Version:

A set of utils for faster development of GraphQL tools

281 lines (280 loc) • 10.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CodeFileLoader = void 0; const tslib_1 = require("tslib"); const fs_1 = require("fs"); const module_1 = require("module"); const path_1 = require("path"); const process_1 = require("process"); const globby_1 = tslib_1.__importDefault(require("globby")); const graphql_1 = require("graphql"); const unixify_1 = tslib_1.__importDefault(require("unixify")); const graphql_tag_pluck_1 = require("@graphql-tools/graphql-tag-pluck"); const utils_1 = require("@graphql-tools/utils"); const load_from_module_js_1 = require("./load-from-module.js"); const { readFile, access } = fs_1.promises; const FILE_EXTENSIONS = [ '.ts', '.mts', '.cts', '.tsx', '.js', '.mjs', 'cjs', '.jsx', '.vue', '.svelte', '.astro', '.gts', '.gjs', ]; function createGlobbyOptions(options) { return { absolute: true, ...options, ignore: [] }; } const buildIgnoreGlob = (path) => `!${path}`; /** * This loader loads GraphQL documents and type definitions from code files * using `graphql-tag-pluck`. * * ```js * const documents = await loadDocuments('queries/*.js', { * loaders: [ * new CodeFileLoader() * ] * }); * ``` * * Supported extensions include: `.ts`, `.mts`, `.cts`, `.tsx`, `.js`, `.mjs`, * `.cjs`, `.jsx`, `.vue`, `.svelte`, `.astro`, `.gts`, `.gjs`. */ class CodeFileLoader { config; constructor(config) { this.config = config ?? {}; } getMergedOptions(options) { return { ...this.config, ...options, pluckConfig: { ...(this.config.pluckConfig || {}), ...(options.pluckConfig || {}) }, }; } async canLoad(pointer, options) { options = this.getMergedOptions(options); if ((0, utils_1.isValidPath)(pointer)) { if (FILE_EXTENSIONS.find(extension => pointer.endsWith(extension))) { const normalizedFilePath = (0, path_1.isAbsolute)(pointer) ? pointer : (0, path_1.resolve)(options.cwd || (0, process_1.cwd)(), pointer); try { await access(normalizedFilePath); return true; } catch { return false; } } } return false; } canLoadSync(pointer, options) { options = this.getMergedOptions(options); if ((0, utils_1.isValidPath)(pointer)) { if (FILE_EXTENSIONS.find(extension => pointer.endsWith(extension))) { const normalizedFilePath = (0, path_1.isAbsolute)(pointer) ? pointer : (0, path_1.resolve)(options.cwd || (0, process_1.cwd)(), pointer); return (0, fs_1.existsSync)(normalizedFilePath); } } return false; } _buildGlobs(glob, options) { const ignores = (0, utils_1.asArray)(options.ignore || []); const globs = [(0, unixify_1.default)(glob), ...ignores.map(v => buildIgnoreGlob((0, unixify_1.default)(v)))]; return globs; } async resolveGlobs(glob, options) { options = this.getMergedOptions(options); const globs = this._buildGlobs(glob, options); return (0, globby_1.default)(globs, createGlobbyOptions(options)); } resolveGlobsSync(glob, options) { options = this.getMergedOptions(options); const globs = this._buildGlobs(glob, options); return globby_1.default.sync(globs, createGlobbyOptions(options)); } async load(pointer, options) { options = this.getMergedOptions(options); const resolvedPaths = await this.resolveGlobs(pointer, options); const finalResult = []; const errors = []; await Promise.all(resolvedPaths.map(async (path) => { try { const result = await this.handleSinglePath(path, options); result?.forEach(result => finalResult.push(result)); } catch (e) { if (process_1.env['DEBUG']) { console.error(e); } errors.push(e); } })); if (errors.length > 0 && (options.noSilentErrors || finalResult.length === 0)) { if (errors.length === 1) { throw errors[0]; } throw new AggregateError(errors, `Reading from ${pointer} failed ; \n ` + errors.map((e) => e.message).join('\n')); } return finalResult; } loadSync(pointer, options) { options = this.getMergedOptions(options); const resolvedPaths = this.resolveGlobsSync(pointer, options); const finalResult = []; const errors = []; for (const path of resolvedPaths) { if (this.canLoadSync(path, options)) { try { const result = this.handleSinglePathSync(path, options); result?.forEach(result => finalResult.push(result)); } catch (e) { if (process_1.env['DEBUG']) { console.error(e); } errors.push(e); } } } if (errors.length > 0 && (options.noSilentErrors || finalResult.length === 0)) { if (errors.length === 1) { throw errors[0]; } throw new AggregateError(errors, `Reading from ${pointer} failed ; \n ` + errors.map((e) => e.message).join('\n')); } return finalResult; } async handleSinglePath(location, options) { if (!(await this.canLoad(location, options))) { return []; } options = this.getMergedOptions(options); const normalizedFilePath = ensureAbsolutePath(location, options); const errors = []; if (!options.noPluck) { try { const content = await readFile(normalizedFilePath, { encoding: 'utf-8' }); const sources = await (0, graphql_tag_pluck_1.gqlPluckFromCodeString)(normalizedFilePath, content, options.pluckConfig); if (sources.length) { return sources.map(source => ({ rawSDL: source.body, document: (0, graphql_1.parse)(source), location, })); } } catch (e) { if (process_1.env['DEBUG']) { console.error(`Failed to load schema from code file "${normalizedFilePath}": ${e.message}`); } errors.push(e); } } if (!options.noRequire) { try { if (options && options.require) { await Promise.all((0, utils_1.asArray)(options.require).map(m => Promise.resolve(`${m}`).then(s => tslib_1.__importStar(require(s))))); } const loaded = await (0, load_from_module_js_1.tryToLoadFromExport)(normalizedFilePath); const sources = (0, utils_1.asArray)(loaded) .map(value => resolveSource(location, value, options)) .filter(Boolean); if (sources.length) { return sources; } } catch (e) { errors.push(e); } } if (errors.length > 0) { throw errors[0]; } return []; } handleSinglePathSync(location, options) { if (!this.canLoadSync(location, options)) { return []; } options = this.getMergedOptions(options); const normalizedFilePath = ensureAbsolutePath(location, options); const errors = []; if (!options.noPluck) { try { const content = (0, fs_1.readFileSync)(normalizedFilePath, { encoding: 'utf-8' }); const sources = (0, graphql_tag_pluck_1.gqlPluckFromCodeStringSync)(normalizedFilePath, content, options.pluckConfig); if (sources.length) { return sources.map(source => ({ rawSDL: source.body, document: (0, graphql_1.parse)(source), location, })); } } catch (e) { if (process_1.env['DEBUG']) { console.error(`Failed to load schema from code file "${normalizedFilePath}": ${e.message}`); } errors.push(e); } } if (!options.noRequire) { try { if (options && options.require) { const cwdRequire = (0, module_1.createRequire)(options.cwd || (0, process_1.cwd)()); for (const m of (0, utils_1.asArray)(options.require)) { cwdRequire(m); } } const loaded = (0, load_from_module_js_1.tryToLoadFromExportSync)(normalizedFilePath); const sources = (0, utils_1.asArray)(loaded) .map(value => resolveSource(location, value, options)) .filter(Boolean); if (sources.length) { return sources; } } catch (e) { errors.push(e); } } if (errors.length > 0) { throw errors[0]; } return null; } } exports.CodeFileLoader = CodeFileLoader; function resolveSource(pointer, value, options) { if (typeof value === 'string') { return (0, utils_1.parseGraphQLSDL)(pointer, value, options); } else if ((0, graphql_1.isSchema)(value)) { return { location: pointer, schema: value, }; } else if ((0, utils_1.isDocumentNode)(value)) { return { location: pointer, document: value, }; } return null; } function ensureAbsolutePath(pointer, options) { return (0, path_1.isAbsolute)(pointer) ? pointer : (0, path_1.resolve)(options.cwd || (0, process_1.cwd)(), pointer); }