Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incremental rebuilds #6142

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Experimental cache for watch mode
kamilkisiela committed Apr 9, 2021
commit 2a6fe254a3d6304a81b6ddb01721faf213629b90
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -117,7 +117,12 @@
"graphql": "15.5.0",
"graphql-language-service-interface": "2.8.2",
"**/apollo-language-server/graphql": "^15.0.0",
"**/@types/graphql-upload/graphql": "^15.0.0"
"**/@types/graphql-upload/graphql": "^15.0.0",
"@graphql-tools/utils": "7.8.0-alpha-1dce565c.0",
"@graphql-tools/code-file-loader": "6.4.0-alpha-1dce565c.0",
"@graphql-tools/graphql-file-loader": "6.3.0-alpha-1dce565c.0",
"@graphql-tools/json-file-loader": "6.3.0-alpha-1dce565c.0",
"@graphql-tools/module-loader": "6.3.0-alpha-1dce565c.0"
},
"dependencies": {
"dotenv": "8.2.0",
5 changes: 1 addition & 4 deletions packages/graphql-codegen-cli/package.json
Original file line number Diff line number Diff line change
@@ -58,9 +58,9 @@
"chokidar": "^3.4.3",
"common-tags": "^1.8.0",
"cosmiconfig": "^7.0.0",
"debounce": "^1.2.0",
"dependency-graph": "^0.11.0",
"detect-indent": "^6.0.0",
"fs-extra": "^9.1.0",
"glob": "^7.1.6",
"graphql-config": "^3.2.0",
"indent-string": "^4.0.0",
@@ -72,7 +72,6 @@
"listr-update-renderer": "^0.5.0",
"log-symbols": "^4.0.0",
"minimatch": "^3.0.4",
"mkdirp": "^1.0.4",
"string-env-interpolation": "^1.0.1",
"ts-log": "^2.2.3",
"tslib": "~2.2.0",
@@ -83,7 +82,6 @@
},
"devDependencies": {
"@types/chokidar": "2.1.3",
"@types/debounce": "1.2.0",
"@types/detect-indent": "6.0.0",
"@types/glob": "7.1.3",
"@types/inquirer": "7.3.1",
@@ -92,7 +90,6 @@
"@types/listr": "0.14.2",
"@types/log-symbols": "3.0.0",
"@types/minimatch": "3.0.4",
"@types/mkdirp": "1.0.1",
"@types/valid-url": "1.0.3",
"bdd-stdin": "0.2.0",
"dotenv": "8.2.0",
28 changes: 27 additions & 1 deletion packages/graphql-codegen-cli/src/codegen.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import {
import { codegen } from '@graphql-codegen/core';

import { Renderer, ErrorRenderer } from './utils/listr-renderer';
import { GraphQLError, GraphQLSchema, DocumentNode, parse } from 'graphql';
import { GraphQLError, GraphQLSchema, DocumentNode, parse, Source as GraphQLSource } from 'graphql';
import { getPluginByName } from './plugins';
import { getPresetByName } from './presets';
import { debugLog } from './utils/debugging';
@@ -186,6 +186,24 @@ export async function executeCodegen(input: CodegenContext | Types.Config): Prom
title: hasPreset
? `Generate to ${filename} (using EXPERIMENTAL preset "${outputConfig.preset}")`
: `Generate ${filename}`,
skip() {
const skip = !context.shouldGenerate(filename);

if (skip) {
// TODO: support presets
// preset.buildGeneratesSection creates a list of files that we can't predict at that point...

// Super important to still push a result even though it's not generated,
// otherwise file is going to be removed in watch mode
result.push({
filename,
content: 'Skipped because of cache...',
noEmit: true, // prevent an empty file from being emitted
});
}

return skip;
},
task: () => {
let outputSchemaAst: GraphQLSchema;
let outputSchema: DocumentNode;
@@ -232,6 +250,14 @@ export async function executeCodegen(input: CodegenContext | Types.Config): Prom
task: wrapTask(async () => {
debugLog(`[CLI] Generating output`);

context.setDependencies(
filename,
[]
.concat(outputSchemaAst.extensions?.sources?.map((source: GraphQLSource) => source.name))
.concat(outputDocuments.map(d => d.location))
.filter(Boolean)
);

const normalizedPluginsArray = normalizeConfig(outputConfig.plugins);
const pluginLoader = config.pluginLoader || makeDefaultLoader(context.cwd);
const pluginPackages = await Promise.all(
133 changes: 131 additions & 2 deletions packages/graphql-codegen-cli/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
import { resolve } from 'path';
import { resolve, isAbsolute } from 'path';
import { DetailedError, Types } from '@graphql-codegen/plugin-helpers';
import { env } from 'string-env-interpolation';
import yargs from 'yargs';
@@ -8,6 +8,8 @@ import { findAndLoadGraphQLConfig } from './graphql-config';
import { loadSchema, loadDocuments, defaultSchemaLoadOptions, defaultDocumentsLoadOptions } from './load';
import { GraphQLSchema } from 'graphql';
import yaml from 'yaml';
import { Source } from '@graphql-tools/utils';
import { cwd } from 'process';

export type YamlCliFlags = {
config: string;
@@ -17,6 +19,7 @@ export type YamlCliFlags = {
project: string;
silent: boolean;
errorsOnly: boolean;
experimentalCache: boolean;
};

function generateSearchPlaces(moduleName: string) {
@@ -171,6 +174,10 @@ export function buildOptions() {
describe: 'Name of a project in GraphQL Config',
type: 'string' as const,
},
experimentalCache: {
describe: 'Use experimental cache for watch mode',
type: 'boolean' as const,
},
};
}

@@ -190,14 +197,18 @@ export async function createContext(cliFlags: YamlCliFlags = parseArgv(process.a
}

export function updateContextWithCliFlags(context: CodegenContext, cliFlags: YamlCliFlags) {
const config: Partial<Types.Config & { configFilePath?: string }> = {
const config: Partial<Types.Config & { configFilePath?: string; experimentalCache?: boolean }> = {
configFilePath: context.filepath,
};

if (cliFlags.watch) {
config.watch = cliFlags.watch;
}

if (cliFlags.experimentalCache) {
config.experimentalCache = true;
}

if (cliFlags.overwrite === true) {
config.overwrite = cliFlags.overwrite;
}
@@ -217,12 +228,97 @@ export function updateContextWithCliFlags(context: CodegenContext, cliFlags: Yam
context.updateConfig(config);
}

function isPromiseLike<T>(value: Promise<T> | T): value is Promise<T> {
return typeof (value as any).then === 'function';
}

class Cache {
isEnabled: () => boolean = () => false;
private invalidated: string[] = [];
private sources = new Map<string, Source>();
private dependencies = new Map<string, string[]>();

cacheSource(fn: (pointer: string, options: any) => Source, pointer: string, options: any): Source;
cacheSource(fn: (pointer: string, options: any) => Promise<Source>, pointer: string, options: any): Promise<Source>;
cacheSource(fn: (pointer: string, options: any) => Promise<Source> | Source, pointer: string, options: any) {
if (!this.isEnabled()) {
return fn(pointer, options);
}

const absolutePointer = ensureAbsolutePath(pointer, options);

if (this.sources.has(absolutePointer)) {
return this.sources.get(absolutePointer)!;
}

const result = fn(pointer, options);

if (isPromiseLike(result)) {
return result.then(source => {
this.sources.set(absolutePointer, source);
return source;
});
}

this.sources.set(absolutePointer, result);

return result;
}

invalidate(filepaths: string[]) {
if (!this.isEnabled()) {
return;
}

this.invalidated = filepaths.map(filepath => {
const absoluteFilepath = ensureAbsolutePath(filepath, {});
this.sources.delete(absoluteFilepath);

return absoluteFilepath;
});
}

shouldGenerate(filepath: string): boolean {
if (!this.isEnabled()) {
return true;
}

// TODO: if new file - generate everything
if (this.dependencies.has(filepath)) {
if (this.invalidated.length) {
const regenerate = this.dependencies.get(filepath).some(f => this.invalidated.includes(f));

if (regenerate) {
return true;
}
}

return false;
}

return true;
}

setDependencies(filepath: string, deps: string[]) {
if (!this.isEnabled()) {
return;
}

this.dependencies.set(
filepath,
deps.map(dep => ensureAbsolutePath(dep, {}))
);
}
}

export class CodegenContext {
private _config: Types.Config;
private _graphqlConfig?: GraphQLConfig;
private config: Types.Config;
private _project?: string;
private _pluginContext: { [key: string]: any } = {};
private cache = new Cache();

cwd: string;
filepath: string;

@@ -239,6 +335,7 @@ export class CodegenContext {
this._graphqlConfig = graphqlConfig;
this.filepath = this._graphqlConfig ? this._graphqlConfig.filepath : filepath;
this.cwd = this._graphqlConfig ? this._graphqlConfig.dirpath : process.cwd();
this.cache.isEnabled = () => (this.config as any).experimentalCache === true;
}

useProject(name?: string) {
@@ -264,6 +361,9 @@ export class CodegenContext {
return {
...extraConfig,
...this.config,
includeSources: true,
cacheable: this.cacheable.bind(this),
cacheableSync: this.cacheableSync.bind(this),
};
}

@@ -298,8 +398,37 @@ export class CodegenContext {

return loadDocuments(pointer, config);
}

invalidate(filepaths: string[]): void {
this.cache.invalidate(filepaths);
}

shouldGenerate(filepath: string) {
return this.cache.shouldGenerate(filepath);
}

setDependencies(filepath: string, deps: string[]) {
return this.cache.setDependencies(filepath, deps);
}

private cacheable(fn: (pointer: string, options: any) => Promise<Source>, pointer: string, options: any) {
return this.cache.cacheSource(fn, pointer, options);
}

private cacheableSync(fn: (pointer: string, options: any) => Source, pointer: string, options: any) {
return this.cache.cacheSource(fn, pointer, options);
}
}

export function ensureContext(input: CodegenContext | Types.Config): CodegenContext {
return input instanceof CodegenContext ? input : new CodegenContext({ config: input });
}

function ensureAbsolutePath(
pointer: string,
options: {
cwd?: string;
}
): string {
return isAbsolute(pointer) ? pointer : resolve(options.cwd || cwd(), pointer);
}
23 changes: 11 additions & 12 deletions packages/graphql-codegen-cli/src/generate-and-save.ts
Original file line number Diff line number Diff line change
@@ -2,8 +2,7 @@ import { lifecycleHooks } from './hooks';
import { Types } from '@graphql-codegen/plugin-helpers';
import { executeCodegen } from './codegen';
import { createWatcher } from './utils/watcher';
import { fileExists, readSync, writeSync, unlinkFile } from './utils/file-system';
import { sync as mkdirpSync } from 'mkdirp';
import { fileExists, readFile, writeFile, unlinkFile, mkdirp } from './utils/file-system';
import { dirname, join, isAbsolute } from 'path';
import { debugLog } from './utils/debugging';
import { CodegenContext, ensureContext } from './config';
@@ -42,18 +41,20 @@ export async function generate(
const recentOutputHash = new Map<string, string>();
async function writeOutput(generationResult: Types.FileOutput[]) {
if (!saveToFile) {
return generationResult;
return;
}

if (config.watch) {
removeStaleFiles(config, generationResult);
}

await lifecycleHooks(config.hooks).beforeAllFileWrite(generationResult.map(r => r.filename));
const resultsToEmit = generationResult.filter(f => !f.noEmit);

await lifecycleHooks(config.hooks).beforeAllFileWrite(resultsToEmit.map(r => r.filename));

await Promise.all(
generationResult.map(async (result: Types.FileOutput) => {
const exists = fileExists(result.filename);
resultsToEmit.map(async (result: Types.FileOutput) => {
const exists = await fileExists(result.filename);

if (!shouldOverwrite(config, result.filename) && exists) {
return;
@@ -64,7 +65,7 @@ export async function generate(
let previousHash = recentOutputHash.get(result.filename);

if (!previousHash && exists) {
previousHash = hash(readSync(result.filename));
previousHash = hash(await readFile(result.filename));
}

if (previousHash && currentHash === previousHash) {
@@ -81,19 +82,17 @@ export async function generate(
const basedir = dirname(result.filename);
await lifecycleHooks(result.hooks).beforeOneFileWrite(result.filename);
await lifecycleHooks(config.hooks).beforeOneFileWrite(result.filename);
mkdirpSync(basedir);
await mkdirp(basedir);
const absolutePath = isAbsolute(result.filename)
? result.filename
: join(input.cwd || process.cwd(), result.filename);
writeSync(absolutePath, result.content);
await writeFile(absolutePath, result.content);
await lifecycleHooks(result.hooks).afterOneFileWrite(result.filename);
await lifecycleHooks(config.hooks).afterOneFileWrite(result.filename);
})
);

await lifecycleHooks(config.hooks).afterAllFileWrite(generationResult.map(r => r.filename));

return generationResult;
await lifecycleHooks(config.hooks).afterAllFileWrite(resultsToEmit.map(r => r.filename));
}

// watch mode
19 changes: 11 additions & 8 deletions packages/graphql-codegen-cli/src/utils/file-system.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { writeFileSync, statSync, readFileSync, unlink } from 'fs';
import { writeFile as fsWriteFile, stat as fsStat, readFile as fsReadFile, unlink as fsUnlink } from 'fs-extra';
export { mkdirp } from 'fs-extra';

export function writeSync(filepath: string, content: string) {
return writeFileSync(filepath, content);
export function writeFile(filepath: string, content: string) {
return fsWriteFile(filepath, content, {
encoding: 'utf-8',
});
}

export function readSync(filepath: string) {
return readFileSync(filepath, 'utf-8');
export function readFile(filepath: string) {
return fsReadFile(filepath, 'utf-8');
}

export function fileExists(filePath: string): boolean {
export async function fileExists(filePath: string): Promise<boolean> {
try {
return statSync(filePath).isFile();
return (await fsStat(filePath)).isFile();
} catch (err) {
return false;
}
}

export function unlinkFile(filePath: string, cb?: (err?: Error) => any): void {
unlink(filePath, cb);
fsUnlink(filePath, cb);
}
58 changes: 51 additions & 7 deletions packages/graphql-codegen-cli/src/utils/watcher.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@ import { executeCodegen } from '../codegen';
import { Types, normalizeInstanceOrArray, normalizeOutputParam } from '@graphql-codegen/plugin-helpers';

import isGlob from 'is-glob';
import debounce from 'debounce';
import logSymbols from 'log-symbols';
import { debugLog } from './debugging';
import { getLogger } from './logger';
@@ -23,7 +22,7 @@ function emitWatching() {

export const createWatcher = (
initalContext: CodegenContext,
onNext: (result: Types.FileOutput[]) => Promise<Types.FileOutput[]>
onNext: (result: Types.FileOutput[]) => Promise<void>
): Promise<void> => {
debugLog(`[Watcher] Starting watcher...`);
let config: Types.Config & { configFilePath?: string } = initalContext.getConfig();
@@ -65,11 +64,22 @@ export const createWatcher = (
const chokidar = await import('chokidar');
let isShutdown = false;

const debouncedExec = debounce(() => {
const enqueue = createQueue();
const debouncedExec = debounceAndCollect((filepaths: string[]) => {
if (!isShutdown) {
executeCodegen(initalContext)
.then(onNext, () => Promise.resolve())
.then(() => emitWatching());
filepaths.forEach(filepath => {
getLogger().info(` ${logSymbols.info} File: ${filepath}`);
});
enqueue(() => {
const startedAt = Date.now();
initalContext.invalidate(filepaths);
return executeCodegen(initalContext)
.then(onNext, () => Promise.resolve())
.then(() => {
log(`${logSymbols.success} Done in ${((Date.now() - startedAt) / 1000).toFixed(2)}s.`);
emitWatching();
});
});
}
}, 100);
emitWatching();
@@ -133,7 +143,7 @@ export const createWatcher = (
initalContext.updateConfig(config);
}

debouncedExec();
debouncedExec(path);
});

process.once('SIGINT', shutdown);
@@ -151,3 +161,37 @@ export const createWatcher = (
});
});
};

/**
* Debounce but also collect arguments
*/
function debounceAndCollect<A>(fn: (arg: A[]) => any, time: number) {
let t: any;
let args: A[] = [];

return function debounced(arg: A) {
args.push(arg);
clearTimeout(t);
t = setTimeout(() => {
const collected = args.slice().filter(unique);
args = [];
fn(collected);
}, time);
};
}

function unique<T>(value: T, i: number, list: T[]): boolean {
return list.indexOf(value) === i;
}

/**
* Creates a queue when resolved Promise starts next Promise, concurrency 1
*/
function createQueue() {
let active: Promise<void> = Promise.resolve();

return function enqueue(fn: () => Promise<void>) {
active = active.then(fn, fn);
return active;
};
}
22 changes: 11 additions & 11 deletions packages/graphql-codegen-cli/tests/generate-and-save.spec.ts
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ describe('generate-and-save', () => {

test('allow to specify overwrite for specific output (should write file)', async () => {
const filename = 'overwrite.ts';
const writeSpy = jest.spyOn(fs, 'writeSync').mockImplementation();
const writeSpy = jest.spyOn(fs, 'writeFile').mockImplementation();

const output = await generate(
{
@@ -47,10 +47,10 @@ describe('generate-and-save', () => {

test('allow to specify overwrite for specific output (should not write file)', async () => {
const filename = 'overwrite.ts';
const writeSpy = jest.spyOn(fs, 'writeSync').mockImplementation();
const writeSpy = jest.spyOn(fs, 'writeFile').mockImplementation();
// forces file to exist
const fileExistsSpy = jest.spyOn(fs, 'fileExists');
fileExistsSpy.mockImplementation(file => file === filename);
fileExistsSpy.mockImplementation(async file => file === filename);

const output = await generate(
{
@@ -78,7 +78,7 @@ describe('generate-and-save', () => {

test('should use global overwrite option and write a file', async () => {
const filename = 'overwrite.ts';
const writeSpy = jest.spyOn(fs, 'writeSync').mockImplementation();
const writeSpy = jest.spyOn(fs, 'writeFile').mockImplementation();

const output = await generate(
{
@@ -103,10 +103,10 @@ describe('generate-and-save', () => {

test('should use global overwrite option and not write a file', async () => {
const filename = 'overwrite.ts';
const writeSpy = jest.spyOn(fs, 'writeSync').mockImplementation();
const writeSpy = jest.spyOn(fs, 'writeFile').mockImplementation();
// forces file to exist
const fileExistsSpy = jest.spyOn(fs, 'fileExists');
fileExistsSpy.mockImplementation(file => file === filename);
fileExistsSpy.mockImplementation(async file => file === filename);

const output = await generate(
{
@@ -133,12 +133,12 @@ describe('generate-and-save', () => {

test('should overwrite a file by default', async () => {
const filename = 'overwrite.ts';
const writeSpy = jest.spyOn(fs, 'writeSync').mockImplementation();
const readSpy = jest.spyOn(fs, 'readSync').mockImplementation();
readSpy.mockImplementation(_f => '');
const writeSpy = jest.spyOn(fs, 'writeFile').mockImplementation();
const readSpy = jest.spyOn(fs, 'readFile').mockImplementation();
readSpy.mockImplementation(async _f => '');
// forces file to exist
const fileExistsSpy = jest.spyOn(fs, 'fileExists');
fileExistsSpy.mockImplementation(file => file === filename);
fileExistsSpy.mockImplementation(async file => file === filename);

const output = await generate(
{
@@ -195,7 +195,7 @@ describe('generate-and-save', () => {
});
test('should extract a document from the gql tag (imported from apollo-server)', async () => {
const filename = 'overwrite.ts';
const writeSpy = jest.spyOn(fs, 'writeSync').mockImplementation();
const writeSpy = jest.spyOn(fs, 'writeFile').mockImplementation();

const output = await generate(
{
1 change: 1 addition & 0 deletions packages/utils/plugins-helpers/src/types.ts
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ export namespace Types {
export type FileOutput = {
filename: string;
content: string;
noEmit?: boolean;
hooks?: {
beforeOneFileWrite?: LifecycleHooksDefinition['beforeOneFileWrite'];
afterOneFileWrite?: LifecycleHooksDefinition['afterOneFileWrite'];
193 changes: 80 additions & 113 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -1058,6 +1058,11 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.16.tgz#cc31257419d2c3189d394081635703f549fc1ed4"
integrity sha512-c/+u9cqV6F0+4Hpq01jnJO+GLp2DdT63ppz9Xa+6cHaajM9VFzK/iDXiKK65YtpeVwu+ctfS6iqlMqRgQRzeCw==

"@babel/parser@7.13.15", "@babel/parser@^7.13.15":
version "7.13.15"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.15.tgz#8e66775fb523599acb6a289e12929fa5ab0954d8"
integrity sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==

"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.7.5", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0":
version "7.9.4"
resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8"
@@ -2567,6 +2572,20 @@
globals "^11.1.0"
lodash "^4.17.19"

"@babel/traverse@7.13.15":
version "7.13.15"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.15.tgz#c38bf7679334ddd4028e8e1f7b3aa5019f0dada7"
integrity sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ==
dependencies:
"@babel/code-frame" "^7.12.13"
"@babel/generator" "^7.13.9"
"@babel/helper-function-name" "^7.12.13"
"@babel/helper-split-export-declaration" "^7.12.13"
"@babel/parser" "^7.13.15"
"@babel/types" "^7.13.14"
debug "^4.1.0"
globals "^11.1.0"

"@babel/traverse@^7.0.0":
version "7.10.3"
resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.3.tgz#0b01731794aa7b77b214bcd96661f18281155d7e"
@@ -2681,6 +2700,15 @@
lodash "^4.17.19"
to-fast-properties "^2.0.0"

"@babel/types@7.13.14", "@babel/types@^7.13.14":
version "7.13.14"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d"
integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==
dependencies:
"@babel/helper-validator-identifier" "^7.12.11"
lodash "^4.17.19"
to-fast-properties "^2.0.0"

"@babel/types@^7.0.0", "@babel/types@^7.10.3", "@babel/types@^7.3.3", "@babel/types@^7.9.5":
version "7.10.3"
resolved "https://registry.npmjs.org/@babel/types/-/types-7.10.3.tgz#6535e3b79fea86a6b09e012ea8528f935099de8e"
@@ -3439,24 +3467,14 @@
is-promise "4.0.0"
tslib "~2.0.1"

"@graphql-tools/code-file-loader@6.3.1":
version "6.3.1"
resolved "https://registry.yarnpkg.com/@graphql-tools/code-file-loader/-/code-file-loader-6.3.1.tgz#42dfd4db5b968acdb453382f172ec684fa0c34ed"
integrity sha512-ZJimcm2ig+avgsEOWWVvAaxZrXXhiiSZyYYOJi0hk9wh5BxZcLUNKkTp6EFnZE/jmGUwuos3pIjUD3Hwi3Bwhg==
"@graphql-tools/code-file-loader@6.3.1", "@graphql-tools/code-file-loader@6.4.0-alpha-1dce565c.0", "@graphql-tools/code-file-loader@^6":
version "6.4.0-alpha-1dce565c.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/code-file-loader/-/code-file-loader-6.4.0-alpha-1dce565c.0.tgz#1981ec8a128f6233667699851d983b4d232c7dfc"
integrity sha512-rDPxEb+xviJXJylC3lnkE5s19JbIoL8gk0z2c3jIpWgyueEdqD2RMshOK8OXMD9noFSV4cHxWDquDZi7gf0Xyw==
dependencies:
"@graphql-tools/graphql-tag-pluck" "^6.5.1"
"@graphql-tools/utils" "^7.0.0"
tslib "~2.1.0"

"@graphql-tools/code-file-loader@^6":
version "6.2.5"
resolved "https://registry.yarnpkg.com/@graphql-tools/code-file-loader/-/code-file-loader-6.2.5.tgz#02832503e96c6c537083570208bd55ca1fbfaa68"
integrity sha512-KMy8c/I4NeQZUI9InydR14qP1pqPeJfgVJLri0RgJRWDiLAj/nIb2oDioN9AgBX3XYNijJT+pH0//B5EOO0BiA==
dependencies:
"@graphql-tools/graphql-tag-pluck" "^6.2.6"
"@graphql-tools/utils" "^7.0.0"
fs-extra "9.0.1"
tslib "~2.0.1"
"@graphql-tools/graphql-tag-pluck" "6.5.2-alpha-1dce565c.0"
"@graphql-tools/utils" "7.8.0-alpha-1dce565c.0"
tslib "~2.2.0"

"@graphql-tools/delegate@^7.0.0", "@graphql-tools/delegate@^7.0.1":
version "7.0.1"
@@ -3512,23 +3530,25 @@
cross-fetch "3.0.6"
tslib "~2.0.1"

"@graphql-tools/graphql-file-loader@6.2.7":
version "6.2.7"
resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-file-loader/-/graphql-file-loader-6.2.7.tgz#d3720f2c4f4bb90eb2a03a7869a780c61945e143"
integrity sha512-5k2SNz0W87tDcymhEMZMkd6/vs6QawDyjQXWtqkuLTBF3vxjxPD1I4dwHoxgWPIjjANhXybvulD7E+St/7s9TQ==
"@graphql-tools/graphql-file-loader@6.2.7", "@graphql-tools/graphql-file-loader@6.3.0-alpha-1dce565c.0", "@graphql-tools/graphql-file-loader@^6", "@graphql-tools/graphql-file-loader@^6.0.0":
version "6.3.0-alpha-1dce565c.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-file-loader/-/graphql-file-loader-6.3.0-alpha-1dce565c.0.tgz#db54ec9ad2d187b35a0ace0fffe5ef1f9864c840"
integrity sha512-l/EQhNU63SK2I+HgRVbggN5tfMIXvYRcsPsd9GWx9IMmk1eMmAPVDpT257XSUHBW8VltziX2ZDcwieYhP/E/Cw==
dependencies:
"@graphql-tools/import" "^6.2.6"
"@graphql-tools/utils" "^7.0.0"
tslib "~2.1.0"
"@graphql-tools/utils" "7.8.0-alpha-1dce565c.0"
tslib "~2.2.0"

"@graphql-tools/graphql-file-loader@^6", "@graphql-tools/graphql-file-loader@^6.0.0":
version "6.2.6"
resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-file-loader/-/graphql-file-loader-6.2.6.tgz#5b907d21b0f947df892ed837db74cd3f6d771c34"
integrity sha512-L+RdYl5C6+X0zdOTUotY0K5zwqvSGpqI/qcZpVvCDenoAcVTyaNLmnd/ViErwedhCaGqAAV0wI1nPtyKFPlMUg==
"@graphql-tools/graphql-tag-pluck@6.5.2-alpha-1dce565c.0":
version "6.5.2-alpha-1dce565c.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-6.5.2-alpha-1dce565c.0.tgz#765a0dbca87e1beeb5351a6d5dc571e47b673e72"
integrity sha512-3ewl5YmMvW8ofUKDju1g4y2beRKUWHlqjfCQvp8RIUNM4ZUBVXxt6z93RwEVNvp+ya6PiB5bXpEpcgLs63Rw0g==
dependencies:
"@graphql-tools/import" "^6.2.5"
"@graphql-tools/utils" "^7.0.0"
tslib "~2.0.1"
"@babel/parser" "7.13.15"
"@babel/traverse" "7.13.15"
"@babel/types" "7.13.14"
"@graphql-tools/utils" "7.8.0-alpha-1dce565c.0"
tslib "~2.2.0"

"@graphql-tools/graphql-tag-pluck@^6.2.6", "@graphql-tools/graphql-tag-pluck@^6.5.1":
version "6.5.1"
@@ -3541,14 +3561,6 @@
"@graphql-tools/utils" "^7.0.0"
tslib "~2.1.0"

"@graphql-tools/import@^6.2.5":
version "6.2.5"
resolved "https://registry.yarnpkg.com/@graphql-tools/import/-/import-6.2.5.tgz#5f279815229320128a07cad188c4860be18cb422"
integrity sha512-ZGXT5tDod7m+LO38fc+o0JzR1LstL0RF35HKEWoUdxRIVaaeYH9VMuan9Gn+9M9RDME3RnzEa9aGzf9ATj8bTA==
dependencies:
resolve-from "5.0.0"
tslib "~2.0.1"

"@graphql-tools/import@^6.2.6":
version "6.2.6"
resolved "https://registry.yarnpkg.com/@graphql-tools/import/-/import-6.2.6.tgz#c5f899f0b87e9fe0523b889be8a59cb30aa164ad"
@@ -3557,13 +3569,13 @@
resolve-from "5.0.0"
tslib "~2.1.0"

"@graphql-tools/json-file-loader@6.2.6", "@graphql-tools/json-file-loader@^6", "@graphql-tools/json-file-loader@^6.0.0":
version "6.2.6"
resolved "https://registry.yarnpkg.com/@graphql-tools/json-file-loader/-/json-file-loader-6.2.6.tgz#830482cfd3721a0799cbf2fe5b09959d9332739a"
integrity sha512-CnfwBSY5926zyb6fkDBHnlTblHnHI4hoBALFYXnrg0Ev4yWU8B04DZl/pBRUc459VNgO2x8/mxGIZj2hPJG1EA==
"@graphql-tools/json-file-loader@6.2.6", "@graphql-tools/json-file-loader@6.3.0-alpha-1dce565c.0", "@graphql-tools/json-file-loader@^6", "@graphql-tools/json-file-loader@^6.0.0":
version "6.3.0-alpha-1dce565c.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/json-file-loader/-/json-file-loader-6.3.0-alpha-1dce565c.0.tgz#8061e69108fffb890effe7f8baf4e73871b3f385"
integrity sha512-bCEipUJXsJ5xI5wZzcOFbCCGZz5YWjtevxxG2fY7jV4+N6h8MHpnFZDPjMspDTWto8rD+1D9fZVGPS9S0yWKqQ==
dependencies:
"@graphql-tools/utils" "^7.0.0"
tslib "~2.0.1"
"@graphql-tools/utils" "7.8.0-alpha-1dce565c.0"
tslib "~2.2.0"

"@graphql-tools/load@6.2.4":
version "6.2.4"
@@ -3628,6 +3640,14 @@
"@graphql-tools/utils" "^7.5.0"
tslib "~2.1.0"

"@graphql-tools/module-loader@6.3.0-alpha-1dce565c.0":
version "6.3.0-alpha-1dce565c.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/module-loader/-/module-loader-6.3.0-alpha-1dce565c.0.tgz#e59062cc340893c7f78b328cac67e4d9f4295658"
integrity sha512-blcAa1ohlS/SF0Ke/idWehhjnnJLnlitObcGgyoK6kWoJ20dwRfjQ4gIYhqPnfY4+CgHBEqlK1bD4P2Qd/OUdg==
dependencies:
"@graphql-tools/utils" "7.8.0-alpha-1dce565c.0"
tslib "~2.2.0"

"@graphql-tools/optimize@^1.0.1":
version "1.0.1"
resolved "https://registry.npmjs.org/@graphql-tools/optimize/-/optimize-1.0.1.tgz#9933fffc5a3c63f95102b1cb6076fb16ac7bb22d"
@@ -3763,59 +3783,14 @@
valid-url "1.0.9"
websocket "1.0.32"

"@graphql-tools/utils@7.7.1":
version "7.7.1"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.7.1.tgz#81f32cb4819b34b3a378d51ab2cd60935977f0b4"
integrity sha512-SFT4/dTfrwWer1wSOLU+jqgv3oa/xTR8q+MiNbE9nCH2FXyMsqIOaXKm9wHfKIWFWHozqBdcnwFkQZrdD7H2TQ==
dependencies:
"@ardatan/aggregate-error" "0.0.6"
camel-case "4.1.2"
tslib "~2.1.0"

"@graphql-tools/utils@^6.0.0", "@graphql-tools/utils@^6.2.4":
version "6.2.4"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-6.2.4.tgz#38a2314d2e5e229ad4f78cca44e1199e18d55856"
integrity sha512-ybgZ9EIJE3JMOtTrTd2VcIpTXtDrn2q6eiYkeYMKRVh3K41+LZa6YnR2zKERTXqTWqhobROwLt4BZbw2O3Aeeg==
dependencies:
"@ardatan/aggregate-error" "0.0.6"
camel-case "4.1.1"
tslib "~2.0.1"

"@graphql-tools/utils@^7.0.0", "@graphql-tools/utils@^7.5.0":
version "7.5.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.5.0.tgz#8485d42eea0f723748dca4cc09344f032bd1e2fa"
integrity sha512-8f//RSqHmKRdg9A3GHlZdxzlVfF/938ZD9edXLW7EriSABg1BXu3veru9W02VqORypArb2S/Tyeyvsk2gForqA==
dependencies:
"@ardatan/aggregate-error" "0.0.6"
camel-case "4.1.2"
tslib "~2.1.0"

"@graphql-tools/utils@^7.0.1":
version "7.0.1"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.0.1.tgz#8bf54676de65878d2b1ba34fcd58ef4d8ae0b589"
integrity sha512-DsV7XfEJE6rPQ3Ysusf28MPun/YL+pc7L0hiBOph/F8+/H1pW1ndRqRrnmX3Owrq9xW1EHSw2WU8qvdjn8kOjw==
dependencies:
"@ardatan/aggregate-error" "0.0.6"
camel-case "4.1.1"
tslib "~2.0.1"

"@graphql-tools/utils@^7.0.2", "@graphql-tools/utils@^7.1.2", "@graphql-tools/utils@^7.1.4":
version "7.1.4"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.1.4.tgz#5baf27e908aa56c44ed3992f4607718a37f186a0"
integrity sha512-4lxmstMpgHSM1ULD+1X5AcPFaizkdBubB7H9Rqr7Wh6L9bxUHBHFB3bhaFXT7FI0xE01Pt0IMsZadOIlhVTXrg==
"@graphql-tools/utils@7.7.1", "@graphql-tools/utils@7.8.0-alpha-1dce565c.0", "@graphql-tools/utils@^6.0.0", "@graphql-tools/utils@^6.2.4", "@graphql-tools/utils@^7.0.0", "@graphql-tools/utils@^7.0.1", "@graphql-tools/utils@^7.0.2", "@graphql-tools/utils@^7.1.2", "@graphql-tools/utils@^7.1.4", "@graphql-tools/utils@^7.1.5", "@graphql-tools/utils@^7.5.0":
version "7.8.0-alpha-1dce565c.0"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.8.0-alpha-1dce565c.0.tgz#ce7bf3b67d62bcd08b1742176b0948721604b00a"
integrity sha512-a54Ixg596l2MPfqyLxRRNz/NVsf+/0M0vny/wIhet3K/G3KY4O2AFfICt2AsCXFsrPk3e9vcXJXn/Tox0au1mQ==
dependencies:
"@ardatan/aggregate-error" "0.0.6"
camel-case "4.1.2"
tslib "~2.0.1"

"@graphql-tools/utils@^7.1.5":
version "7.1.5"
resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-7.1.5.tgz#82eb9fd1d796bf9455ccf8f3d8775674a4582eb3"
integrity sha512-utJgoKJNhAUz0i+MGF1uvz7i4fxxz1TE21c68R38Hs4kmXO6A6H5e18jwzGdjspyf3IZOS621fmN9GQPzIazHg==
dependencies:
"@ardatan/aggregate-error" "0.0.6"
camel-case "4.1.2"
tslib "~2.0.1"
tslib "~2.2.0"

"@graphql-tools/wrap@^7.0.0":
version "7.0.0"
@@ -7421,14 +7396,6 @@ callsites@^3.0.0:
resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==

camel-case@4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547"
integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==
dependencies:
pascal-case "^3.1.1"
tslib "^1.10.0"

camel-case@4.1.2, camel-case@^4.1.1, camel-case@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
@@ -10475,16 +10442,6 @@ fs-extra@9.0.0:
jsonfile "^6.0.1"
universalify "^1.0.0"

fs-extra@9.0.1, fs-extra@^9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc"
integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==
dependencies:
at-least-node "^1.0.0"
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^1.0.0"

fs-extra@9.1.0, fs-extra@^9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
@@ -10504,6 +10461,16 @@ fs-extra@^7.0.0, fs-extra@^7.0.1:
jsonfile "^4.0.0"
universalify "^0.1.0"

fs-extra@^9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc"
integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==
dependencies:
at-least-node "^1.0.0"
graceful-fs "^4.2.0"
jsonfile "^6.0.1"
universalify "^1.0.0"

fs-minipass@^2.0.0, fs-minipass@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
@@ -15385,7 +15352,7 @@ parseurl@^1.3.2, parseurl@~1.3.2, parseurl@~1.3.3:
resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==

pascal-case@^3.1.1, pascal-case@^3.1.2:
pascal-case@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==