Skip to content

Commit

Permalink
Make it smarter and support glob patterns
Browse files Browse the repository at this point in the history
This way when a new file is added, we generate only relevant outputs, not everything
  • Loading branch information
kamilkisiela committed Apr 12, 2021
1 parent 97235b1 commit a918b14
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 23 deletions.
6 changes: 6 additions & 0 deletions packages/graphql-codegen-cli/src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,12 @@ export async function executeCodegen(input: CodegenContext | Types.Config): Prom
.concat(outputDocuments.map(d => d.location))
.filter(Boolean)
);
context.setPointers(filename, [
...rootSchemas,
...outputSpecificSchemas,
...rootDocuments,
...outputSpecificDocuments,
]);

const normalizedPluginsArray = normalizeConfig(outputConfig.plugins);
const pluginLoader = config.pluginLoader || makeDefaultLoader(context.cwd);
Expand Down
101 changes: 88 additions & 13 deletions packages/graphql-codegen-cli/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { cosmiconfig, defaultLoaders } from 'cosmiconfig';
import { resolve, isAbsolute } from 'path';
import { DetailedError, Types } from '@graphql-codegen/plugin-helpers';
import isGlob from 'is-glob';
import { env } from 'string-env-interpolation';
import yargs from 'yargs';
import { GraphQLConfig } from 'graphql-config';
import { findAndLoadGraphQLConfig } from './graphql-config';
import { loadSchema, loadDocuments, defaultSchemaLoadOptions, defaultDocumentsLoadOptions } from './load';
import minimatch from 'minimatch';
import { GraphQLSchema } from 'graphql';
import yaml from 'yaml';
import { Source } from '@graphql-tools/utils';
import { cwd } from 'process';
import { DetailedError, Types } from '@graphql-codegen/plugin-helpers';
import { findAndLoadGraphQLConfig } from './graphql-config';
import { loadSchema, loadDocuments, defaultSchemaLoadOptions, defaultDocumentsLoadOptions } from './load';

export type YamlCliFlags = {
config: string;
Expand Down Expand Up @@ -237,7 +239,15 @@ class Cache {
isEnabled: () => boolean = () => false;
private invalidated: string[] = [];
private sources = new Map<string, Source>();
private dependencies = new Map<string, string[]>();
private outputs = new Map<
string,
{
pointers: string[];
dependencies: string[];
}
>();

constructor(private cwd: 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>;
Expand Down Expand Up @@ -272,7 +282,9 @@ class Cache {
}

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

return absoluteFilepath;
Expand All @@ -285,11 +297,31 @@ class Cache {
}

// TODO: if new file - generate everything
if (this.dependencies.has(filepath)) {

// check if output was already processeed
// if not, mark as "to generate"
if (this.outputs.has(filepath)) {
// if nothing to invalidate, do not generate
if (this.invalidated.length) {
const regenerate = this.dependencies.get(filepath).some(f => this.invalidated.includes(f));
// filepath matches a pointer
if (
// iterate over all related pointers
this.outputs.get(filepath).pointers.some(
pointer =>
// collect only matching paths and check if the list is not empty
this.invalidated.filter(
minimatch.filter(pointer, {
matchBase: true,
})
).length > 0
)
) {
// in case we found matching files, generate the output
return true;
}

if (regenerate) {
// filepath is already a dependency of the output
if (this.outputs.get(filepath).dependencies.some(f => this.invalidated.includes(f))) {
return true;
}
}
Expand All @@ -305,10 +337,48 @@ class Cache {
return;
}

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

setPointers(filepath: string, pointers: (Types.Schema | Types.OperationDocument)[]) {
if (!this.isEnabled()) {
return;
}

this.ensureOutput(filepath);
this.outputs.get(filepath).pointers = pointers
.map(pointer => {
if (typeof pointer === 'string') {
// collect only globs
return isGlob(pointer) ? ensureAbsolutePath(pointer, { cwd: this.cwd }) : null;
}

if (typeof pointer === 'object') {
for (const key in pointer) {
const options = pointer[key];

// if it has a loader, we can't assume it's pure and does not provide any extra contents
if (options && 'loader' in options) {
return null;
}

return isGlob(key) ? ensureAbsolutePath(key, { cwd: this.cwd }) : null;
}
}

return null;
})
.filter(val => typeof val === 'string');
}

private ensureOutput(filepath: string) {
if (!this.outputs.has(filepath)) {
this.outputs.set(filepath, {
pointers: [],
dependencies: [],
});
}
}
}

Expand All @@ -318,7 +388,7 @@ export class CodegenContext {
private config: Types.Config;
private _project?: string;
private _pluginContext: { [key: string]: any } = {};
private cache = new Cache();
private cache: Cache;

cwd: string;
filepath: string;
Expand All @@ -336,6 +406,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 = new Cache(this.cwd);
this.cache.isEnabled = () => (this.config as any).experimentalCache === true;
}

Expand Down Expand Up @@ -412,6 +483,10 @@ export class CodegenContext {
return this.cache.setDependencies(filepath, deps);
}

setPointers(filepath: string, pointers: (Types.Schema | Types.OperationDocument)[]) {
return this.cache.setPointers(filepath, pointers);
}

private cacheable(fn: (pointer: string, options: any) => Promise<Source>, pointer: string, options: any) {
return this.cache.cacheSource(fn, pointer, options);
}
Expand Down
10 changes: 0 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4799,11 +4799,6 @@
dependencies:
"@types/express" "*"

"@types/debounce@1.2.0":
version "1.2.0"
resolved "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.0.tgz#9ee99259f41018c640b3929e1bb32c3dcecdb192"
integrity sha512-bWG5wapaWgbss9E238T0R6bfo5Fh3OkeoSt245CM7JJwVwpw6MEBCbIxLq5z8KzsE3uJhzcIuQkyiZmzV3M/Dw==

"@types/detect-indent@6.0.0":
version "6.0.0"
resolved "https://registry.npmjs.org/@types/detect-indent/-/detect-indent-6.0.0.tgz#5ff60617bfa71950694f53bcca86309414534f19"
Expand Down Expand Up @@ -8709,11 +8704,6 @@ date-fns@^1.27.2:
resolved "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==

debounce@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131"
integrity sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==

debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
Expand Down

0 comments on commit a918b14

Please sign in to comment.