import {FixedMatcher} from './FixedMatcher.js';
import {PropertyMatcher} from './PropertyMatcher.js';
import {Matching} from './Matching.js';
import {HashMatcher} from './HashMatcher.js';
import {SimilarityMatcher} from './SimilarityMatcher.js';
import {SandwichMatcher} from './SandwichMatcher.js';
import {Logger} from '../../util/Logger.js';
import {PathMatcher} from './PathMatcher.js';
import {Comparator} from './Comparator.js';
import {DiffConfig} from '../../config/DiffConfig.js';
/**
* Wrapper for an ordered sequence of matching modules (matchers for short).
*/
export class MatchPipeline {
/**
* Enum for the possible match modes.
* @type {Object}
*/
static MATCH_MODES = {
FAST: 'fast',
BALANCED: 'balanced',
QUALITY: 'quality',
};
/** @type {Array<MatcherInterface>} */
#matchers;
/**
* @param {Array<MatcherInterface>} matchers The list of matchers
* constituting this pipeline.
*/
constructor(matchers) {
const len = matchers.length;
// FixedMatcher is always the first matching algorithm in the pipeline
if (len === 0 || matchers[0].constructor !== FixedMatcher) {
matchers.unshift(new FixedMatcher());
}
// PropertyMatcher is always the last matching algorithm in the pipeline
if (len === 0 || matchers[len - 1].constructor !== PropertyMatcher) {
matchers.push(new PropertyMatcher());
}
this.#matchers = matchers;
}
/**
* Construct a matching pipeline based on the selected matching mode.
* @return {MatchPipeline}
*/
static fromMode() {
return new MatchPipeline(
[
new FixedMatcher(),
new HashMatcher(),
new SimilarityMatcher(
DiffConfig.MATCH_MODE === MatchPipeline.MATCH_MODES.FAST),
new PathMatcher(
DiffConfig.MATCH_MODE === MatchPipeline.MATCH_MODES.QUALITY),
new PathMatcher(false),
new SandwichMatcher(),
new PropertyMatcher(),
]);
}
/**
* Construct a matching between the passed process trees by executing the
* matching pipeline in order.
* @param {Node} oldTree The root of the old (original) process tree.
* @param {Node} newTree The root of the new (changed) process tree.
* @param {Matching} matching An existing matching (used by the merger).
* @return {Matching}
*/
execute(oldTree, newTree, matching = new Matching()) {
const comparator = new Comparator();
for (const matcher of this.#matchers) {
Logger.info('Running matching module ' +
matcher.constructor.name + '...', this);
Logger.startTimed();
const prevMatches = matching.size();
matcher.match(oldTree, newTree, matching, comparator);
Logger.stat('Matching module ' +
matcher.constructor.name + ' took ' + Logger.endTimed() +
'ms and found ' + (matching.size() - prevMatches) +
' matches', this);
}
return matching;
}
}