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