Home Identifier Source Repository

src/lib/get-matches-from-children.js

import collectMatches from './collect-matches'
import filter from 'lodash/collection/filter'
import flatten from 'lodash/array/flatten'
import includes from 'lodash/collection/includes'
import isArray from 'lodash/lang/isArray'
import isRequirementName from './is-requirement-name'
import keys from 'lodash/object/keys'
import map from 'lodash/collection/map'
import pluck from 'lodash/collection/pluck'
import stringify from 'json-stable-stringify'
import uniq from 'lodash/array/uniq'

/**
 * Extract the matched courses from all children.
 * @private
 * @param {Object} expr - the current result expression
 * @param {Requirement} ctx - the host requirement
 * @returns {Course[]} - the list of matched courses
 */
export default function getMatchesFromChildren(expr, ctx) {
	// grab all the child requirement names from this requirement
	let childKeys = filter(keys(ctx), isRequirementName)

	// either use all of the child requirements in the computation,
	if (expr.$children === '$all') { // eslint-disable-line no-empty
		// do nothing; the default case.
	}

	// or just use some of them (those listed in expr.$children)
	else if (isArray(expr.$children)) {
		const requested = pluck(expr.$children, '$requirement')
		childKeys = filter(childKeys, key => includes(requested, key))
	}

	// `uniq` had the same problem here that the dirty course stuff struggles
	// with. That is, uniq works on a per-object basis, so when you write down
	// the same course for several reqs, they'll be different objects.
	// Therefore, we turn each object into a sorted JSON representation of
	// itself, and uniq based on that.
	// (I opted for passing iteratee to uniq, rather than mapping, to let lodash optimize a bit.)

	// finally, collect the matching courses from the requested children
	const matches = map(childKeys, key => collectMatches(ctx[key]))
	const flatMatches = flatten(matches)
	const uniquedMatches = uniq(flatMatches, stringify)

	return uniquedMatches
}