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

improve life cycle hooks typings #8652

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/plenty-bottles-prove.md
@@ -0,0 +1,6 @@
---
'@graphql-codegen/cli': patch
'@graphql-codegen/plugin-helpers': major
---

improve typings for life cycle hooks
56 changes: 30 additions & 26 deletions packages/graphql-codegen-cli/src/hooks.ts
Expand Up @@ -4,7 +4,7 @@ import { exec } from 'child_process';
import { delimiter, sep } from 'path';
import { quote } from 'shell-quote';

const DEFAULT_HOOKS: Types.LifecycleHooksDefinition<string[]> = {
const DEFAULT_HOOKS: Types.LifecycleHooksDefinition = {
afterStart: [],
beforeDone: [],
onWatchTriggered: [],
Expand All @@ -15,35 +15,38 @@ const DEFAULT_HOOKS: Types.LifecycleHooksDefinition<string[]> = {
beforeAllFileWrite: [],
};

function normalizeHooks(
_hooks: Partial<Types.LifecycleHooksDefinition>
): Types.LifecycleHooksDefinition<(string | Types.HookFunction)[]> {
function normalizeHooks(_hooks: Partial<Types.LifecycleHooksDefinition>): {
[key in keyof Types.LifecycleHooksDefinition]: (string | Types.HookFunction)[];
} {
const keys = Object.keys({
...DEFAULT_HOOKS,
..._hooks,
});

return keys.reduce((prev: Types.LifecycleHooksDefinition<(string | Types.HookFunction)[]>, hookName: string) => {
if (typeof _hooks[hookName] === 'string') {
return {
...prev,
[hookName]: [_hooks[hookName]] as string[],
};
}
if (typeof _hooks[hookName] === 'function') {
return {
...prev,
[hookName]: [_hooks[hookName]],
};
}
if (Array.isArray(_hooks[hookName])) {
return {
...prev,
[hookName]: _hooks[hookName] as string[],
};
}
return prev;
}, {} as Types.LifecycleHooksDefinition<(string | Types.HookFunction)[]>);
return keys.reduce(
(prev: { [key in keyof Types.LifecycleHooksDefinition]: (string | Types.HookFunction)[] }, hookName: string) => {
if (typeof _hooks[hookName] === 'string') {
return {
...prev,
[hookName]: [_hooks[hookName]] as string[],
};
}
if (typeof _hooks[hookName] === 'function') {
return {
...prev,
[hookName]: [_hooks[hookName]],
};
}
if (Array.isArray(_hooks[hookName])) {
return {
...prev,
[hookName]: _hooks[hookName] as string[],
};
}
return prev;
},
{} as { [key in keyof Types.LifecycleHooksDefinition]: (string | Types.HookFunction)[] }
);
}

function execShellCommand(cmd: string): Promise<string> {
Expand Down Expand Up @@ -72,10 +75,11 @@ function execShellCommand(cmd: string): Promise<string> {

async function executeHooks(
hookName: string,
scripts: (string | Types.HookFunction)[] = [],
_scripts: Types.LifeCycleHookValue = [],
args: string[] = []
): Promise<void> {
debugLog(`Running lifecycle hook "${hookName}" scripts...`);
const scripts = Array.isArray(_scripts) ? _scripts : [_scripts];

const quotedArgs = quote(args);
for (const script of scripts) {
Expand Down
20 changes: 11 additions & 9 deletions packages/utils/plugins-helpers/src/types.ts
Expand Up @@ -524,58 +524,60 @@ export namespace Types {
export type PluginOutput = string | ComplexPluginOutput;
export type HookFunction = (...args: any[]) => void | Promise<void>;

export type LifeCycleHookValue = string | HookFunction | (string | HookFunction)[];

/**
* @description All available lifecycle hooks
* @additionalProperties false
*/
export type LifecycleHooksDefinition<T = string | HookFunction | (string | HookFunction)[]> = {
export type LifecycleHooksDefinition = {
jantimon marked this conversation as resolved.
Show resolved Hide resolved
/**
* @description Triggered with no arguments when the codegen starts (after the `codegen.yml` has beed parsed).
*
* Specify a shell command to run.
*/
afterStart: T;
afterStart: LifeCycleHookValue;
/**
* @description Triggered with no arguments, right before the codegen closes, or when watch mode is stopped.
*
* Specify a shell command to run.
*/
beforeDone: T;
beforeDone: LifeCycleHookValue;
/**
* @description Triggered every time a file changes when using watch mode.
* Triggered with two arguments: the type of the event (for example, `changed`) and the path of the file.
*/
onWatchTriggered: T;
onWatchTriggered: LifeCycleHookValue;
/**
* @description Triggered in case of a general error in the codegen. The argument is a string containing the error.
*/
onError: T;
onError: LifeCycleHookValue;
/**
* @description Triggered after a file is written to the file-system. Executed with the path for the file.
* If the content of the file hasn't changed since last execution - this hooks won't be triggered.
*
* > This is a very useful hook, you can use it for integration with Prettier or other linters.
*/
afterOneFileWrite: T;
afterOneFileWrite: LifeCycleHookValue;
/**
* @description Executed after writing all the files to the file-system.
* Triggered with multiple arguments - paths for all files.
*/
afterAllFileWrite: T;
afterAllFileWrite: LifeCycleHookValue;
/**
* @description Triggered before a file is written to the file-system. Executed with the path for the file.
*
* If the content of the file hasn't changed since last execution - this hooks won't be triggered.
*/
beforeOneFileWrite: T;
beforeOneFileWrite: LifeCycleHookValue;
/**
* @description Executed after the codegen has done creating the output and before writing the files to the file-system.
*
* Triggered with multiple arguments - paths for all relevant files.
*
* > Not all the files will be actually written to the file-system, because this is triggered before checking if the file has changed since last execution.
*/
beforeAllFileWrite: T;
beforeAllFileWrite: LifeCycleHookValue;
};

export type SkipDocumentsValidationOptions =
Expand Down