@graphql-codegen/cli 3.3.2-rc-20230512163241-1dedabd22 → 3.3.2-rc-20230512164352-dd85e9e33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,92 @@
1
+ var _a, _b;
2
+ import { EventEmitter } from 'events';
3
+ import { debugLog } from './debugging.js';
4
+ /**
5
+ * Node v14 does not have AbortSignal or AbortController, so to safely use it in
6
+ * another module, you can import it from here.
7
+ *
8
+ * Node v14.7+ does have it, but only with flag --experimental-abortcontroller
9
+ *
10
+ * We don't actually use AbortController anywhere except in tests, but it
11
+ * still gets called in watcher.ts, so by polyfilling it we can avoid breaking
12
+ * existing installations using Node v14 without flag --experimental-abortcontroller,
13
+ * and we also ensure that tests continue to pass under Node v14 without any new flags.
14
+ *
15
+ * This polyfill was adapted (TypeScript-ified) from here:
16
+ * https://github.com/southpolesteve/node-abort-controller/blob/master/index.js
17
+ */
18
+ class AbortSignalPolyfill {
19
+ constructor() {
20
+ this.eventEmitter = new EventEmitter();
21
+ this.onabort = null;
22
+ this.aborted = false;
23
+ this.reason = undefined;
24
+ }
25
+ toString() {
26
+ return '[object AbortSignal]';
27
+ }
28
+ get [Symbol.toStringTag]() {
29
+ return 'AbortSignal';
30
+ }
31
+ removeEventListener(name, handler) {
32
+ this.eventEmitter.removeListener(name, handler);
33
+ }
34
+ addEventListener(name, handler) {
35
+ this.eventEmitter.on(name, handler);
36
+ }
37
+ // @ts-expect-error No Event type in Node 14
38
+ dispatchEvent(type) {
39
+ const event = { type, target: this };
40
+ const handlerName = `on${event.type}`;
41
+ if (typeof this[handlerName] === 'function')
42
+ this[handlerName](event);
43
+ return this.eventEmitter.emit(event.type, event);
44
+ }
45
+ throwIfAborted() {
46
+ if (this.aborted) {
47
+ throw this.reason;
48
+ }
49
+ }
50
+ static abort(reason) {
51
+ const controller = new AbortController();
52
+ controller.abort(reason);
53
+ return controller.signal;
54
+ }
55
+ static timeout(time) {
56
+ const controller = new AbortController();
57
+ setTimeout(() => controller.abort(new Error('TimeoutError')), time);
58
+ return controller.signal;
59
+ }
60
+ }
61
+ const AbortSignal = (_a = global.AbortSignal) !== null && _a !== void 0 ? _a : AbortSignalPolyfill;
62
+ class AbortControllerPolyfill {
63
+ constructor() {
64
+ debugLog('Using polyfilled AbortController');
65
+ // @ts-expect-error No Event type in Node 14
66
+ this.signal = new AbortSignal();
67
+ }
68
+ abort(reason) {
69
+ if (this.signal.aborted)
70
+ return;
71
+ // @ts-expect-error Not a read only property when polyfilling
72
+ this.signal.aborted = true;
73
+ if (reason) {
74
+ // @ts-expect-error Not a read only property when polyfilling
75
+ this.signal.reason = reason;
76
+ }
77
+ else {
78
+ // @ts-expect-error Not a read only property when polyfilling
79
+ this.signal.reason = new Error('AbortError');
80
+ }
81
+ // @ts-expect-error No Event type in Node 14
82
+ this.signal.dispatchEvent('abort');
83
+ }
84
+ toString() {
85
+ return '[object AbortController]';
86
+ }
87
+ get [Symbol.toStringTag]() {
88
+ return 'AbortController';
89
+ }
90
+ }
91
+ const AbortController = (_b = global.AbortController) !== null && _b !== void 0 ? _b : AbortControllerPolyfill;
92
+ export { AbortController };
@@ -1,5 +1,8 @@
1
1
  import { promises, unlink as fsUnlink } from 'fs';
2
- const { writeFile: fsWriteFile, readFile: fsReadFile, mkdir } = promises;
2
+ const { access: fsAccess, writeFile: fsWriteFile, readFile: fsReadFile, mkdir } = promises;
3
+ export function access(...args) {
4
+ return fsAccess(...args);
5
+ }
3
6
  export function writeFile(filepath, content) {
4
7
  return fsWriteFile(filepath, content);
5
8
  }
@@ -0,0 +1,226 @@
1
+ import { isAbsolute, relative } from 'path';
2
+ import { isValidPath } from '@graphql-tools/utils';
3
+ import { normalizeInstanceOrArray } from '@graphql-codegen/plugin-helpers';
4
+ import isGlob from 'is-glob';
5
+ import mm from 'micromatch';
6
+ /**
7
+ * Flatten a list of pattern sets to be a list of only the affirmative patterns
8
+ * are contained in all of them.
9
+ *
10
+ * This can be used, for example, to find the "longest common prefix directory"
11
+ * by examining `mm.scan(pattern).base` for each `pattern`.
12
+ */
13
+ export const allAffirmativePatternsFromPatternSets = (patternSets) => {
14
+ return patternSets.flatMap(patternSet => [
15
+ ...patternSet.watch.affirmative,
16
+ ...patternSet.documents.affirmative,
17
+ ...patternSet.schemas.affirmative,
18
+ ]);
19
+ };
20
+ /**
21
+ * Create a rebuild trigger that follows the algorithm described here:
22
+ * https://github.com/dotansimha/graphql-code-generator/issues/9270#issuecomment-1496765045
23
+ *
24
+ * There is a flow chart diagram in that comment.
25
+ *
26
+ * Basically:
27
+ *
28
+ * * "Global" patterns are defined at top level of config file, and "local"
29
+ * patterns are defined for each output target
30
+ * * Each pattern can have "watch", "documents", and "schemas"
31
+ * * Watch patterns (global and local) always take precedence over documents and
32
+ * schemas patterns, i.e. a watch negation always negates, and a watch match is
33
+ * a match even if it would be negated by some pattern in documents or schemas
34
+ * * The trigger returns true if any output target's local patterns result in
35
+ * a match, after considering the precedence of any global and local negations
36
+ */
37
+ export const makeShouldRebuild = ({ globalPatternSet, localPatternSets, }) => {
38
+ const localMatchers = localPatternSets.map(localPatternSet => {
39
+ return (path) => {
40
+ // Is path negated by any negating watch pattern?
41
+ if (matchesAnyNegatedPattern(path, [...globalPatternSet.watch.negated, ...localPatternSet.watch.negated])) {
42
+ // Short circut: negations in watch patterns take priority
43
+ return false;
44
+ }
45
+ // Does path match any affirmative watch pattern?
46
+ if (matchesAnyAffirmativePattern(path, [
47
+ ...globalPatternSet.watch.affirmative,
48
+ ...localPatternSet.watch.affirmative,
49
+ ])) {
50
+ // Immediately return true: Watch pattern takes priority, even if documents or schema would negate it
51
+ return true;
52
+ }
53
+ // Does path match documents patterns (without being negated)?
54
+ if (matchesAnyAffirmativePattern(path, [
55
+ ...globalPatternSet.documents.affirmative,
56
+ ...localPatternSet.documents.affirmative,
57
+ ]) &&
58
+ !matchesAnyNegatedPattern(path, [...globalPatternSet.documents.negated, ...localPatternSet.documents.negated])) {
59
+ return true;
60
+ }
61
+ // Does path match schemas patterns (without being negated)?
62
+ if (matchesAnyAffirmativePattern(path, [
63
+ ...globalPatternSet.schemas.affirmative,
64
+ ...localPatternSet.schemas.affirmative,
65
+ ]) &&
66
+ !matchesAnyNegatedPattern(path, [...globalPatternSet.schemas.negated, ...localPatternSet.schemas.negated])) {
67
+ return true;
68
+ }
69
+ // Otherwise, there is no match
70
+ return false;
71
+ };
72
+ });
73
+ /**
74
+ * Return `true` if `path` should trigger a rebuild
75
+ */
76
+ return ({ path: absolutePath }) => {
77
+ if (!isAbsolute(absolutePath)) {
78
+ throw new Error('shouldRebuild trigger should be called with absolute path');
79
+ }
80
+ const path = relative(process.cwd(), absolutePath);
81
+ const shouldRebuild = localMatchers.some(matcher => matcher(path));
82
+ return shouldRebuild;
83
+ };
84
+ };
85
+ /**
86
+ * Create the pattern set for the "global" (top level) config.
87
+ *
88
+ * In the `shouldRebuild` algorithm, any of these watch patterns will take
89
+ * precedence over local configs, and any schemas and documents patterns will be
90
+ * mixed into the pattern set of each local config.
91
+ */
92
+ export const makeGlobalPatternSet = (initialContext) => {
93
+ var _a;
94
+ const config = initialContext.getConfig();
95
+ return {
96
+ watch: sortPatterns([
97
+ ...(typeof config.watch === 'boolean' ? [] : normalizeInstanceOrArray((_a = config.watch) !== null && _a !== void 0 ? _a : [])),
98
+ relative(process.cwd(), initialContext.filepath),
99
+ ]),
100
+ schemas: sortPatterns(makePatternsFromSchemas(normalizeInstanceOrArray(config.schema))),
101
+ documents: sortPatterns(makePatternsFromDocuments(normalizeInstanceOrArray(config.documents))),
102
+ };
103
+ };
104
+ /**
105
+ * Create the pattern set for a "local" (output target) config
106
+ *
107
+ * In the `shouldRebuild` algorithm, any of these watch patterns will take
108
+ * precedence over documents or schemas patterns, and the documents and schemas
109
+ * patterns will be mixed into the pattern set of their respective gobal pattern
110
+ * set equivalents.
111
+ */
112
+ export const makeLocalPatternSet = (conf) => {
113
+ return {
114
+ watch: sortPatterns(normalizeInstanceOrArray(conf.watchPattern)),
115
+ documents: sortPatterns(makePatternsFromDocuments(normalizeInstanceOrArray(conf.documents))),
116
+ schemas: sortPatterns(makePatternsFromSchemas(normalizeInstanceOrArray(conf.schema))),
117
+ };
118
+ };
119
+ /**
120
+ * Parse a list of micromatch patterns from a list of documents, which should
121
+ * already have been normalized from their raw config values.
122
+ */
123
+ const makePatternsFromDocuments = (documents) => {
124
+ const patterns = [];
125
+ if (documents) {
126
+ for (const doc of documents) {
127
+ if (typeof doc === 'string') {
128
+ patterns.push(doc);
129
+ }
130
+ else {
131
+ patterns.push(...Object.keys(doc));
132
+ }
133
+ }
134
+ }
135
+ return patterns;
136
+ };
137
+ /**
138
+ * Parse a list of micromatch patterns from a list of schemas, which should
139
+ * already have been normalized from their raw config values.
140
+ */
141
+ const makePatternsFromSchemas = (schemas) => {
142
+ const patterns = [];
143
+ for (const s of schemas) {
144
+ const schema = s;
145
+ if (isGlob(schema) || isValidPath(schema)) {
146
+ patterns.push(schema);
147
+ }
148
+ }
149
+ return patterns;
150
+ };
151
+ /**
152
+ * Given a list of micromatch patterns, sort them into `patterns` (all of them),
153
+ * `affirmative` (only the affirmative patterns), and `negated` (only the negated patterns)
154
+ *
155
+ * @param patterns List of micromatch patterns
156
+ */
157
+ export const sortPatterns = (patterns) => ({
158
+ patterns,
159
+ affirmative: onlyAffirmativePatterns(patterns),
160
+ negated: onlyNegatedPatterns(patterns),
161
+ });
162
+ /**
163
+ * Filter the provided list of patterns to include only "affirmative" (non-negated) patterns.
164
+ *
165
+ * @param patterns List of micromatch patterns (or paths) to filter
166
+ */
167
+ const onlyAffirmativePatterns = (patterns) => {
168
+ return patterns.filter(pattern => !mm.scan(pattern).negated);
169
+ };
170
+ /**
171
+ * Filter the provided list of patterns to include only negated patterns.
172
+ *
173
+ * @param patterns List of micromatch patterns (or paths) to filter
174
+ */
175
+ const onlyNegatedPatterns = (patterns) => {
176
+ return patterns.filter(pattern => mm.scan(pattern).negated);
177
+ };
178
+ /**
179
+ * Given a list of negated patterns, invert them by removing their negation prefix
180
+ *
181
+ * If there is a non-negated pattern in the list, throw an error, because this
182
+ * function should only be called after filtering the list to be only negated patterns
183
+ *
184
+ * @param patterns List of negated micromatch patterns
185
+ */
186
+ const invertNegatedPatterns = (patterns) => {
187
+ return patterns.map(pattern => {
188
+ const scanned = mm.scan(pattern);
189
+ if (!scanned.negated) {
190
+ throw new Error(`onlyNegatedPatterns got a non-negated pattern: ${pattern}`);
191
+ }
192
+ // Remove the leading prefix (NOTE: this is not always "!")
193
+ // e.g. mm.scan("!./foo/bar/never-watch.graphql").prefix === '!./'
194
+ return pattern.slice(scanned.prefix.length);
195
+ });
196
+ };
197
+ /**
198
+ * Return true if relativeCandidatePath matches any of the affirmativePatterns
199
+ *
200
+ * @param relativeCandidatePath A relative path to evaluate against the supplied affirmativePatterns
201
+ * @param affirmativePatterns A list of patterns, containing no negated patterns, to evaluate
202
+ */
203
+ const matchesAnyAffirmativePattern = (relativeCandidatePath, affirmativePatterns) => {
204
+ if (isAbsolute(relativeCandidatePath)) {
205
+ throw new Error('matchesAny should only be called with relative candidate path');
206
+ }
207
+ // Developer error: This function is not intended to work with pattern sets including negations
208
+ if (affirmativePatterns.some(pattern => mm.scan(pattern).negated)) {
209
+ throw new Error('matchesAnyAffirmativePattern should only include affirmative patterns');
210
+ }
211
+ // micromatch.isMatch does not omit matches that are negated by negation patterns,
212
+ // which is why we require this function only examine affirmative patterns
213
+ return mm.isMatch(relativeCandidatePath, affirmativePatterns);
214
+ };
215
+ /**
216
+ * Return true if relativeCandidatePath matches any of the negatedPatterns
217
+ *
218
+ * This function will invert the negated patterns and then call matchesAnyAffirmativePattern
219
+ *
220
+ * @param relativeCandidatePath A relative path to evaluate against the suppliednegatedPatterns
221
+ * @param negatedPatterns A list of patterns, containing no negated patterns, to evaluate
222
+ */
223
+ const matchesAnyNegatedPattern = (relativeCandidatePath, negatedPatterns) => {
224
+ // NOTE: No safety check that negatedPatterns contains only negated, because that will happen in invertedNegatedPatterns
225
+ return matchesAnyAffirmativePattern(relativeCandidatePath, invertNegatedPatterns(negatedPatterns));
226
+ };
@@ -1,16 +1,16 @@
1
- import { access } from 'node:fs/promises';
2
- import { join, isAbsolute, resolve, sep } from 'path';
3
- import { normalizeInstanceOrArray, normalizeOutputParam } from '@graphql-codegen/plugin-helpers';
4
- import { isValidPath } from '@graphql-tools/utils';
1
+ import { join, isAbsolute, relative, resolve, sep } from 'path';
2
+ import { normalizeOutputParam } from '@graphql-codegen/plugin-helpers';
5
3
  import debounce from 'debounce';
6
- import isGlob from 'is-glob';
7
4
  import mm from 'micromatch';
8
5
  import logSymbols from 'log-symbols';
9
6
  import { executeCodegen } from '../codegen.js';
10
7
  import { loadContext } from '../config.js';
11
8
  import { lifecycleHooks } from '../hooks.js';
9
+ import { access } from './file-system.js';
12
10
  import { debugLog } from './debugging.js';
13
11
  import { getLogger } from './logger.js';
12
+ import { allAffirmativePatternsFromPatternSets, makeGlobalPatternSet, makeLocalPatternSet, makeShouldRebuild, } from './patterns.js';
13
+ import { AbortController } from './abort-controller-polyfill.js';
14
14
  function log(msg) {
15
15
  // double spaces to inline the message with Listr
16
16
  getLogger().info(` ${msg}`);
@@ -18,47 +18,25 @@ function log(msg) {
18
18
  function emitWatching(watchDir) {
19
19
  log(`${logSymbols.info} Watching for changes in ${watchDir}...`);
20
20
  }
21
- export const createWatcher = (initalContext, onNext) => {
21
+ export const createWatcher = (initialContext, onNext) => {
22
22
  debugLog(`[Watcher] Starting watcher...`);
23
- let config = initalContext.getConfig();
24
- const files = [initalContext.filepath].filter(a => a);
25
- const documents = normalizeInstanceOrArray(config.documents);
26
- const schemas = normalizeInstanceOrArray(config.schema);
27
- // Add schemas and documents from "generates"
28
- for (const conf of Object.keys(config.generates).map(filename => normalizeOutputParam(config.generates[filename]))) {
29
- schemas.push(...normalizeInstanceOrArray(conf.schema));
30
- documents.push(...normalizeInstanceOrArray(conf.documents));
31
- files.push(...normalizeInstanceOrArray(conf.watchPattern));
32
- }
33
- if (documents) {
34
- for (const doc of documents) {
35
- if (typeof doc === 'string') {
36
- files.push(doc);
37
- }
38
- else {
39
- files.push(...Object.keys(doc));
40
- }
41
- }
42
- }
43
- for (const s of schemas) {
44
- const schema = s;
45
- if (isGlob(schema) || isValidPath(schema)) {
46
- files.push(schema);
47
- }
48
- }
49
- if (typeof config.watch !== 'boolean') {
50
- files.push(...normalizeInstanceOrArray(config.watch));
51
- }
23
+ let config = initialContext.getConfig();
24
+ const globalPatternSet = makeGlobalPatternSet(initialContext);
25
+ const localPatternSets = Object.keys(config.generates)
26
+ .map(filename => normalizeOutputParam(config.generates[filename]))
27
+ .map(conf => makeLocalPatternSet(conf));
28
+ const allAffirmativePatterns = allAffirmativePatternsFromPatternSets([globalPatternSet, ...localPatternSets]);
29
+ const shouldRebuild = makeShouldRebuild({ globalPatternSet, localPatternSets });
52
30
  let watcherSubscription;
53
- const runWatcher = async () => {
31
+ const runWatcher = async (abortSignal) => {
54
32
  var _a;
55
- const watchDirectory = await findHighestCommonDirectory(files);
33
+ const watchDirectory = await findHighestCommonDirectory(allAffirmativePatterns);
56
34
  const parcelWatcher = await import('@parcel/watcher');
57
35
  debugLog(`[Watcher] Parcel watcher loaded...`);
58
36
  let isShutdown = false;
59
37
  const debouncedExec = debounce(() => {
60
38
  if (!isShutdown) {
61
- executeCodegen(initalContext)
39
+ executeCodegen(initialContext)
62
40
  .then(onNext, () => Promise.resolve())
63
41
  .then(() => emitWatching(watchDirectory));
64
42
  }
@@ -69,34 +47,35 @@ export const createWatcher = (initalContext, onNext) => {
69
47
  filename,
70
48
  config: normalizeOutputParam(config.generates[filename]),
71
49
  }))) {
50
+ // ParcelWatcher expects relative ignore patterns to be relative from watchDirectory,
51
+ // but we expect filename from config to be relative from cwd, so we need to convert
52
+ const filenameRelativeFromWatchDirectory = relative(watchDirectory, resolve(process.cwd(), entry.filename));
72
53
  if (entry.config.preset) {
73
54
  const extension = (_a = entry.config.presetConfig) === null || _a === void 0 ? void 0 : _a.extension;
74
55
  if (extension) {
75
- ignored.push(join(entry.filename, '**', '*' + extension));
56
+ ignored.push(join(filenameRelativeFromWatchDirectory, '**', '*' + extension));
76
57
  }
77
58
  }
78
59
  else {
79
- ignored.push(entry.filename);
60
+ ignored.push(filenameRelativeFromWatchDirectory);
80
61
  }
81
62
  }
82
63
  watcherSubscription = await parcelWatcher.subscribe(watchDirectory, async (_, events) => {
83
64
  // it doesn't matter what has changed, need to run whole process anyway
84
- await Promise.all(events.map(async ({ type: eventName, path }) => {
85
- /**
86
- * @parcel/watcher has no way to run watcher on specific files (https://github.com/parcel-bundler/watcher/issues/42)
87
- * But we can use micromatch to filter out events that we don't care about
88
- */
89
- if (!mm.contains(path, files))
65
+ await Promise.all(
66
+ // NOTE: @parcel/watcher always provides path as an absolute path
67
+ events.map(async ({ type: eventName, path }) => {
68
+ if (!shouldRebuild({ path })) {
90
69
  return;
70
+ }
91
71
  lifecycleHooks(config.hooks).onWatchTriggered(eventName, path);
92
72
  debugLog(`[Watcher] triggered due to a file ${eventName} event: ${path}`);
93
- const fullPath = join(watchDirectory, path);
94
73
  // In ESM require is not defined
95
74
  try {
96
- delete require.cache[fullPath];
75
+ delete require.cache[path];
97
76
  }
98
77
  catch (err) { }
99
- if (eventName === 'update' && config.configFilePath && fullPath === config.configFilePath) {
78
+ if (eventName === 'update' && config.configFilePath && path === config.configFilePath) {
100
79
  log(`${logSymbols.info} Config file has changed, reloading...`);
101
80
  const context = await loadContext(config.configFilePath);
102
81
  const newParsedConfig = context.getConfig();
@@ -105,35 +84,76 @@ export const createWatcher = (initalContext, onNext) => {
105
84
  newParsedConfig.overwrite = config.overwrite;
106
85
  newParsedConfig.configFilePath = config.configFilePath;
107
86
  config = newParsedConfig;
108
- initalContext.updateConfig(config);
87
+ initialContext.updateConfig(config);
109
88
  }
110
89
  debouncedExec();
111
90
  }));
112
91
  }, { ignore: ignored });
113
92
  debugLog(`[Watcher] Started`);
114
- const shutdown = () => {
93
+ const shutdown = (
94
+ /** Optional callback to execute after shutdown has completed its async tasks */
95
+ afterShutdown) => {
115
96
  isShutdown = true;
116
97
  debugLog(`[Watcher] Shutting down`);
117
98
  log(`Shutting down watch...`);
118
- watcherSubscription.unsubscribe();
119
- lifecycleHooks(config.hooks).beforeDone();
99
+ const pendingUnsubscribe = watcherSubscription.unsubscribe();
100
+ const pendingBeforeDoneHook = lifecycleHooks(config.hooks).beforeDone();
101
+ if (afterShutdown && typeof afterShutdown === 'function') {
102
+ Promise.allSettled([pendingUnsubscribe, pendingBeforeDoneHook]).then(afterShutdown);
103
+ }
120
104
  };
121
- process.once('SIGINT', shutdown);
122
- process.once('SIGTERM', shutdown);
105
+ abortSignal.addEventListener('abort', () => shutdown(abortSignal.reason));
106
+ process.once('SIGINT', () => shutdown());
107
+ process.once('SIGTERM', () => shutdown());
123
108
  };
124
- // the promise never resolves to keep process running
125
- return new Promise((resolve, reject) => {
126
- executeCodegen(initalContext)
109
+ // Use an AbortController for shutdown signals
110
+ // NOTE: This will be polyfilled on Node 14 (or any environment without it defined)
111
+ const abortController = new AbortController();
112
+ /**
113
+ * Send shutdown signal and return a promise that only resolves after the
114
+ * runningWatcher has resolved, which only resolved after the shutdown signal has been handled
115
+ */
116
+ const stopWatching = async function () {
117
+ // stopWatching.afterShutdown is lazily set to resolve pendingShutdown promise
118
+ abortController.abort(stopWatching.afterShutdown);
119
+ // SUBTLE: runningWatcher waits for pendingShutdown before it resolves itself, so
120
+ // by awaiting it here, we are awaiting both the shutdown handler, and runningWatcher itself
121
+ await stopWatching.runningWatcher;
122
+ };
123
+ stopWatching.afterShutdown = () => {
124
+ debugLog('Shutdown watcher before it started');
125
+ };
126
+ stopWatching.runningWatcher = Promise.resolve();
127
+ /** Promise will resolve after the shutdown() handler completes */
128
+ const pendingShutdown = new Promise(afterShutdown => {
129
+ // afterShutdown will be passed to shutdown() handler via abortSignal.reason
130
+ stopWatching.afterShutdown = afterShutdown;
131
+ });
132
+ /**
133
+ * Promise that resolves after the watch server has shutdown, either because
134
+ * stopWatching() was called or there was an error inside it
135
+ */
136
+ stopWatching.runningWatcher = new Promise((resolve, reject) => {
137
+ executeCodegen(initialContext)
127
138
  .then(onNext, () => Promise.resolve())
128
- .then(runWatcher)
139
+ .then(() => runWatcher(abortController.signal))
129
140
  .catch(err => {
130
141
  watcherSubscription.unsubscribe();
131
142
  reject(err);
143
+ })
144
+ .then(() => pendingShutdown)
145
+ .finally(() => {
146
+ debugLog('Done watching.');
147
+ resolve();
132
148
  });
133
149
  });
150
+ return {
151
+ stopWatching,
152
+ runningWatcher: stopWatching.runningWatcher,
153
+ };
134
154
  };
135
155
  /**
136
- * Given a list of file paths (each of which may be absolute, or relative to
156
+ * Given a list of file paths (each of which may be absolute, or relative from
137
157
  * `process.cwd()`), find absolute path of the "highest" common directory,
138
158
  * i.e. the directory that contains all the files in the list.
139
159
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-codegen/cli",
3
- "version": "3.3.2-rc-20230512163241-1dedabd22",
3
+ "version": "3.3.2-rc-20230512164352-dd85e9e33",
4
4
  "peerDependencies": {
5
5
  "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"
6
6
  },
@@ -9,7 +9,7 @@
9
9
  "@babel/template": "^7.18.10",
10
10
  "@babel/types": "^7.18.13",
11
11
  "@graphql-codegen/core": "^3.1.0",
12
- "@graphql-codegen/plugin-helpers": "4.2.1-rc-20230512163241-1dedabd22",
12
+ "@graphql-codegen/plugin-helpers": "4.2.1-rc-20230512164352-dd85e9e33",
13
13
  "@graphql-tools/apollo-engine-loader": "^7.3.6",
14
14
  "@graphql-tools/code-file-loader": "^7.3.17",
15
15
  "@graphql-tools/git-loader": "^7.2.13",
@@ -0,0 +1,5 @@
1
+ declare const AbortController: {
2
+ new (): AbortController;
3
+ prototype: AbortController;
4
+ };
5
+ export { AbortController };
@@ -0,0 +1,5 @@
1
+ declare const AbortController: {
2
+ new (): AbortController;
3
+ prototype: AbortController;
4
+ };
5
+ export { AbortController };
@@ -1,4 +1,9 @@
1
+ /// <reference types="node" />
2
+ import { promises } from 'fs';
3
+ declare const fsAccess: typeof promises.access;
4
+ export declare function access(...args: Parameters<typeof fsAccess>): Promise<void>;
1
5
  export declare function writeFile(filepath: string, content: string): Promise<void>;
2
6
  export declare function readFile(filepath: string): Promise<string>;
3
7
  export declare function unlinkFile(filePath: string, cb?: (err?: Error) => any): void;
4
8
  export declare function mkdirp(filePath: string): Promise<string>;
9
+ export {};
@@ -1,4 +1,9 @@
1
+ /// <reference types="node" />
2
+ import { promises } from 'fs';
3
+ declare const fsAccess: typeof promises.access;
4
+ export declare function access(...args: Parameters<typeof fsAccess>): Promise<void>;
1
5
  export declare function writeFile(filepath: string, content: string): Promise<void>;
2
6
  export declare function readFile(filepath: string): Promise<string>;
3
7
  export declare function unlinkFile(filePath: string, cb?: (err?: Error) => any): void;
4
8
  export declare function mkdirp(filePath: string): Promise<string>;
9
+ export {};