getJasmineRequireObj().TreeProcessor = function() { function TreeProcessor(attrs) { const tree = attrs.tree; const runnableIds = attrs.runnableIds; const queueRunnerFactory = attrs.queueRunnerFactory; const nodeStart = attrs.nodeStart || function() {}; const nodeComplete = attrs.nodeComplete || function() {}; const failSpecWithNoExpectations = !!attrs.failSpecWithNoExpectations; const orderChildren = attrs.orderChildren || function(node) { return node.children; }; const excludeNode = attrs.excludeNode || function(node) { return false; }; let stats = { valid: true }; let processed = false; const defaultMin = Infinity; const defaultMax = 1 - Infinity; this.processTree = function() { processNode(tree, true); processed = true; return stats; }; this.execute = async function() { if (!processed) { this.processTree(); } if (!stats.valid) { throw 'invalid order'; } const childFns = wrapChildren(tree, 0); await new Promise(function(resolve) { queueRunnerFactory({ queueableFns: childFns, userContext: tree.sharedUserContext(), onException: function() { tree.handleException.apply(tree, arguments); }, onComplete: resolve, onMultipleDone: tree.onMultipleDone ? tree.onMultipleDone.bind(tree) : null }); }); }; function runnableIndex(id) { for (let i = 0; i < runnableIds.length; i++) { if (runnableIds[i] === id) { return i; } } } function processNode(node, parentExcluded) { const executableIndex = runnableIndex(node.id); if (executableIndex !== undefined) { parentExcluded = false; } if (!node.children) { const excluded = parentExcluded || excludeNode(node); stats[node.id] = { excluded: excluded, willExecute: !excluded && !node.markedPending, segments: [ { index: 0, owner: node, nodes: [node], min: startingMin(executableIndex), max: startingMax(executableIndex) } ] }; } else { let hasExecutableChild = false; const orderedChildren = orderChildren(node); for (let i = 0; i < orderedChildren.length; i++) { const child = orderedChildren[i]; processNode(child, parentExcluded); if (!stats.valid) { return; } const childStats = stats[child.id]; hasExecutableChild = hasExecutableChild || childStats.willExecute; } stats[node.id] = { excluded: parentExcluded, willExecute: hasExecutableChild }; segmentChildren(node, orderedChildren, stats[node.id], executableIndex); if (!node.canBeReentered() && stats[node.id].segments.length > 1) { stats = { valid: false }; } } } function startingMin(executableIndex) { return executableIndex === undefined ? defaultMin : executableIndex; } function startingMax(executableIndex) { return executableIndex === undefined ? defaultMax : executableIndex; } function segmentChildren( node, orderedChildren, nodeStats, executableIndex ) { let currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) }, result = [currentSegment], lastMax = defaultMax, orderedChildSegments = orderChildSegments(orderedChildren); function isSegmentBoundary(minIndex) { return ( lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1 ); } for (let i = 0; i < orderedChildSegments.length; i++) { const childSegment = orderedChildSegments[i], maxIndex = childSegment.max, minIndex = childSegment.min; if (isSegmentBoundary(minIndex)) { currentSegment = { index: result.length, owner: node, nodes: [], min: defaultMin, max: defaultMax }; result.push(currentSegment); } currentSegment.nodes.push(childSegment); currentSegment.min = Math.min(currentSegment.min, minIndex); currentSegment.max = Math.max(currentSegment.max, maxIndex); lastMax = maxIndex; } nodeStats.segments = result; } function orderChildSegments(children) { const specifiedOrder = [], unspecifiedOrder = []; for (let i = 0; i < children.length; i++) { const child = children[i], segments = stats[child.id].segments; for (let j = 0; j < segments.length; j++) { const seg = segments[j]; if (seg.min === defaultMin) { unspecifiedOrder.push(seg); } else { specifiedOrder.push(seg); } } } specifiedOrder.sort(function(a, b) { return a.min - b.min; }); return specifiedOrder.concat(unspecifiedOrder); } function executeNode(node, segmentNumber) { if (node.children) { return { fn: function(done) { const onStart = { fn: function(next) { nodeStart(node, next); } }; queueRunnerFactory({ onComplete: function() { const args = Array.prototype.slice.call(arguments, [0]); node.cleanupBeforeAfter(); nodeComplete(node, node.getResult(), function() { done.apply(undefined, args); }); }, queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)), userContext: node.sharedUserContext(), onException: function() { node.handleException.apply(node, arguments); }, onMultipleDone: node.onMultipleDone ? node.onMultipleDone.bind(node) : null }); } }; } else { return { fn: function(done) { node.execute( queueRunnerFactory, done, stats[node.id].excluded, failSpecWithNoExpectations ); } }; } } function wrapChildren(node, segmentNumber) { const result = [], segmentChildren = stats[node.id].segments[segmentNumber].nodes; for (let i = 0; i < segmentChildren.length; i++) { result.push( executeNode(segmentChildren[i].owner, segmentChildren[i].index) ); } if (!stats[node.id].willExecute) { return result; } return node.beforeAllFns.concat(result).concat(node.afterAllFns); } } return TreeProcessor; };