-
-
Notifications
You must be signed in to change notification settings - Fork 13
Perf: Pre-merge global elements at normalization time #99
Description
Since global elements will always end up being applied to every file (if they are going to be processed at all), then all the global elements { !files } are going to need to be merged again and again for every file config fetched (that's not cached).
Rather than repeat this for potentially every file, I'd propose that during the normalization process, all global elements be pre-merged backwards through the array and eliminated.
This obviously has the benefit of each individual file having to process fewer array elements when its config is fetched, and the number of merge operations therefore required. And depending on the merge function of individual schemas, it could significantly reduce the work they have to do overall if the global elements apply things that reduce the amount of processing required.
It does have some upfront cost, but we're using a O(n) operation once at normalisation time to reduce the n in a O(n * fileCount) at getConfig time.
This process could also be used to gather all the global ignores and eliminate those elements as well, doing the work that this.ignores usually has to do for "free".
So, to be more concrete, here's some very quick and dirty example code of what this might look like:
function preMergeGlobals(configs) {
const [...preMergedConfigs, globalIgnores] = [...preMergeGlobalsInner(configs.reverse())];
this.length = 0;
this.push(...preMergedConfigs.reverse());
// TODO: Figure out where to put the global ignores so that `this.ignores` doesn't have to traverse the array
}
function* preMergeGlobalsInner(reversedConfigs) {
const globalIgnores = [];
let currentGlobalToMerge = undefined;
for (const config in reversedConfigs) {
if (!config.files && !config.ignores) {
currentGlobalToMerge = currentGlobalToMerge
? this[ConfigArraySymbol.schema].merge(config, currentGlobalToMerge) // We're iterating backwards, so apply the earlier config on top of this one
: config;
} else if (config.ignores && Object.keys(config).length === 1) {
globalIgnores.push(config.ignores);
} else {
yield currentGlobalToMerge
? this[ConfigArraySymbol.schema].merge(config, currentGlobalToMerge) // We're iterating backwards, so apply the earlier config on top of this one
: config;
}
}
yield { ignores: globalIgnores.reverse().flat() };
}Happy to put together a PR with properly thought out code for this if you think it's worth implementing.