lib/props-tree-builder.js
function buildPropsTreeBranches(
	recordTypes, topPropDesc, clause, baseValueExprCtx, scopePropPath,
	propPatterns, options) {

	// create the branching tree top node
	const topNode = PropertyTreeNode.createTopNode(
		recordTypes, topPropDesc, baseValueExprCtx, clause);

	// add direct patterns
	const valuePropsTrees = new Map();
	const excludedPaths = new Set();
	let wcPatterns = (!(options && options.noWildcards) && new Array());
	for (let propPattern of propPatterns) {
		if (propPattern.startsWith('-'))
			excludedPaths.add(propPattern.substring(1));
		else
			addProperty(
				topNode, scopePropPath, propPattern, clause, options,
				valuePropsTrees, wcPatterns);
	}

	// add wildcard patterns
	while (wcPatterns && (wcPatterns.length > 0)) {
		const wcPatterns2 = new Array();
		wcPatterns.forEach(propPattern => {
			if (!excludedPaths.has(propPattern))
				addProperty(
					topNode, scopePropPath, propPattern, clause, options,
					valuePropsTrees, wcPatterns2);
		});
		wcPatterns = wcPatterns2;
	}

	// add scope if requested
	if (options && options.includeScopeProp && scopePropPath &&
		!topNode.includesProp(scopePropPath)) {
		const scopeOptions = Object.create(options);
		scopeOptions.includeScopeProp = false;
		scopeOptions.noCalculated = true;
		scopeOptions.allowLeafObjects = true;
		addProperty(topNode, null, scopePropPath, clause, scopeOptions);
	}

	// de-branch the tree and merge in the value trees
	const assertSingleBranch = (branches, enable) => {
		if (enable && (branches.length > 1))
			throw new Error('Internal X2 error: unexpected multiple branches.');
		return branches;
	};
	const valuePropsTreesArray = Array.from(valuePropsTrees.entries());
	return assertSingleBranch(topNode.debranch().map(
		branch => valuePropsTreesArray.reduce((res, pair) => {
			const valuePropPath = pair[0];
			const valuePropsTree = pair[1];
			if (!res.includesProp(valuePropPath))
				return res;
			return res.combine(valuePropsTree);
		}, branch)
	), scopePropPath);
}
function buildPropsTreeBranches(
	recordTypes, topPropDesc, clause, baseValueExprCtx, scopePropPath,
	propPatterns, options) {

	// create the branching tree top node
	const topNode = PropertyTreeNode.createTopNode(
		recordTypes, topPropDesc, baseValueExprCtx, clause);

	// add direct patterns
	const valuePropsTrees = new Map();
	const excludedPaths = new Set();
	let wcPatterns = (!(options && options.noWildcards) && new Array());
	for (let propPattern of propPatterns) {
		if (propPattern.startsWith('-'))
			excludedPaths.add(propPattern.substring(1));
		else
			addProperty(
				topNode, scopePropPath, propPattern, clause, options,
				valuePropsTrees, wcPatterns);
	}

	// add wildcard patterns
	while (wcPatterns && (wcPatterns.length > 0)) {
		const wcPatterns2 = new Array();
		wcPatterns.forEach(propPattern => {
			if (!excludedPaths.has(propPattern))
				addProperty(
					topNode, scopePropPath, propPattern, clause, options,
					valuePropsTrees, wcPatterns2);
		});
		wcPatterns = wcPatterns2;
	}

	// add scope if requested
	if (options && options.includeScopeProp && scopePropPath &&
		!topNode.includesProp(scopePropPath)) {
		const scopeOptions = Object.create(options);
		scopeOptions.includeScopeProp = false;
		scopeOptions.noCalculated = true;
		scopeOptions.allowLeafObjects = true;
		addProperty(topNode, null, scopePropPath, clause, scopeOptions);
	}

	// de-branch the tree and merge in the value trees
	const assertSingleBranch = (branches, enable) => {
		if (enable && (branches.length > 1))
			throw new Error('Internal X2 error: unexpected multiple branches.');
		return branches;
	};
	const valuePropsTreesArray = Array.from(valuePropsTrees.entries());
	return assertSingleBranch(topNode.debranch().map(
		branch => valuePropsTreesArray.reduce((res, pair) => {
			const valuePropPath = pair[0];
			const valuePropsTree = pair[1];
			if (!res.includesProp(valuePropPath))
				return res;
			return res.combine(valuePropsTree);
		}, branch)
	), scopePropPath);
}
function buildPropsTreeBranches ( recordTypes , topPropDesc , clause , baseValueExprCtx , scopePropPath , propPatterns , options ) { // create the branching tree top node const topNode = PropertyTreeNode . createTopNode ( recordTypes , topPropDesc , baseValueExprCtx , clause ) ; // add direct patterns const valuePropsTrees = new Map ( ) ; const excludedPaths = new Set ( ) ; let wcPatterns = ( ! ( options && options . noWildcards ) && new Array ( ) ) ; for ( let propPattern of propPatterns ) { if ( propPattern . startsWith ( '-' ) ) excludedPaths . add ( propPattern . substring ( 1 ) ) ; else addProperty ( topNode , scopePropPath , propPattern , clause , options , valuePropsTrees , wcPatterns ) ; } // add wildcard patterns while ( wcPatterns && ( wcPatterns . length > 0 ) ) { const wcPatterns2 = new Array ( ) ; wcPatterns . forEach ( propPattern => { if ( ! excludedPaths . has ( propPattern ) ) addProperty ( topNode , scopePropPath , propPattern , clause , options , valuePropsTrees , wcPatterns2 ) ; } ) ; wcPatterns = wcPatterns2 ; } // add scope if requested if ( options && options . includeScopeProp && scopePropPath && ! topNode . includesProp ( scopePropPath ) ) { const scopeOptions = Object . create ( options ) ; scopeOptions . includeScopeProp = false ; scopeOptions . noCalculated = true ; scopeOptions . allowLeafObjects = true ; addProperty ( topNode , null , scopePropPath , clause , scopeOptions ) ; } // de-branch the tree and merge in the value trees const assertSingleBranch = ( branches , enable ) => { if ( enable && ( branches . length > 1 ) ) throw new Error ( 'Internal X2 error: unexpected multiple branches.' ) ; return branches ; } ; const valuePropsTreesArray = Array . from ( valuePropsTrees . entries ( ) ) ; return assertSingleBranch ( topNode . debranch ( ) . map ( branch => valuePropsTreesArray . reduce ( ( res , pair ) => { const valuePropPath = pair [ 0 ] ; const valuePropsTree = pair [ 1 ] ; if ( ! res . includesProp ( valuePropPath ) ) return res ; return res . combine ( valuePropsTree ) ; } , branch ) ) , scopePropPath ) ; }
Build properties tree from a list of property path patterns and debranch it.

@protected
@param {module:x2node-records~RecordTypesLibrary} recordTypes Record types
library.
@param {module:x2node-records~PropertyDescriptor} topPropDesc Descriptor of
the top property in the resulting tree. For example, when the tree is being
built for a query that fetches records of a given record type, this is the
descriptor of the "records" super-property.
@param {string} clause Clause for the tree. Every node in the resulting tree
will be marked as used in this clause.
@param {module:x2node-dbos~ValueExpressionContext} baseValueExprCtx
Context for any value expressions used by the properties in the tree. All
property nodes in the resulting tree will include this context's base path in
their <code>path</code> property.
@param {string} [scopePropPath] Optional scope property path, including the
base value expression context's base path. If provided, any attempt to add a
property to the tree that does not lie on the same collection axis with the
scope property will result in an error. Thus, if this argument is provided,
the resulting tree is guaranteed to have only a single branch. Note, that
collections <em>below</em> the scope property are not allowed either.
Therefore, trees built using the same scope property will combine into a tree
that will still have only a single branch.
@param {Iterable.<string>} propPatterns Patterns of properties to include in
the tree. The patterns are relative to (that is do not include) the base value
expression context's base path.
@param {Object} [options] Tree building logic options, if any.
@param {boolean} [options.noWildcards] If <code>true</code>, wildcard
patterns are not allowed.
@param {boolean} [options.noAggregates] If <code>true</code>, aggregate
properties are not allowed in the tree.
@param {boolean} [options.noCalculated] If <code>true</code>, neither
calculated value nor aggregate properties are allowed in the tree.
@param {boolean} [options.ignoreScopedOrders] If <code>true</code>, scoped
order specifications on any included collection properties are ignored.
@param {boolean} [options.noScopedFilters] If <code>true</code>, no collection
properties with scoped filters are allowed in the tree.
@returns {Array.<module:x2node-dbos~PropertyTreeNode>} The resulting
properties tree branches. If scope property was provided, there will be always
only one branch in the returned array.
@throws {module:x2node-common.X2SyntaxError} If the provided specifications or
participating property definitions are invalid.
Build properties tree from a list of property path patterns and debranch it .