08-27-周三_17-09-29

This commit is contained in:
2025-08-27 17:10:05 +08:00
commit 86df397d8f
12735 changed files with 1145479 additions and 0 deletions

19
node_modules/dagre-layout/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2018 Tyler Long
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

53
node_modules/dagre-layout/README.md generated vendored Normal file
View File

@@ -0,0 +1,53 @@
# dagre-layout - Graph layout for JavaScript
[![Build Status](https://secure.travis-ci.org/tylingsoft/dagre-layout.png?branch=master)](http://travis-ci.org/tylingsoft/dagre-layout)
[![Coverage Status](https://coveralls.io/repos/github/tylingsoft/dagre-layout/badge.svg?branch=master)](https://coveralls.io/github/tylingsoft/dagre-layout?branch=master)
This project is an out-of-box replacement for [dagre](https://github.com/dagrejs/dagre).
This project isn't built from scratch. It's based on the original [dagre](https://github.com/dagrejs/dagre) project.
Dagre is a JavaScript library that makes it easy to lay out directed graphs on the client-side.
For more details, including examples and configuration options, please see our [wiki](https://github.com/dagrejs/dagre/wiki).
## Changes compared to dagrejs/dagre
- Upgrade all the dependencies (loadash 3 => 4)
- Yarn instead of NPM
- Get rid of PhantomJS
- ES6 instead of ES5
- Use webpack instead of browserify
- Use JavaScript Standard Style instead of JSHint
- Use Jest for testing
- Add test coverage report
- Remove Bower support
- Use 0 instead of `Number.NEGATIVE_INFINITY`
- Git ignore auto-generated code
## Setup
```
yarn install
```
## Build
```
yarn build
```
## Test
```
yarn test
```
## License
dagre-layout is licensed under the terms of the MIT License. See the LICENSE file for details.

2
node_modules/dagre-layout/dist/dagre-layout.core.js generated vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

10
node_modules/dagre-layout/dist/dagre-layout.js generated vendored Normal file

File diff suppressed because one or more lines are too long

1
node_modules/dagre-layout/dist/dagre-layout.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

5
node_modules/dagre-layout/index.js generated vendored Normal file
View File

@@ -0,0 +1,5 @@
import layout from './lib/layout'
export default {
layout
}

66
node_modules/dagre-layout/lib/acyclic.js generated vendored Normal file
View File

@@ -0,0 +1,66 @@
import _ from 'lodash'
import greedyFAS from './greedy-fas'
function run (g) {
const fas = (g.graph().acyclicer === 'greedy'
? greedyFAS(g, weightFn(g))
: dfsFAS(g))
_.forEach(fas, function (e) {
const label = g.edge(e)
g.removeEdge(e)
label.forwardName = e.name
label.reversed = true
g.setEdge(e.w, e.v, label, _.uniqueId('rev'))
})
function weightFn (g) {
return function (e) {
return g.edge(e).weight
}
}
}
function dfsFAS (g) {
const fas = []
const stack = {}
const visited = {}
function dfs (v) {
if (_.has(visited, v)) {
return
}
visited[v] = true
stack[v] = true
_.forEach(g.outEdges(v), function (e) {
if (_.has(stack, e.w)) {
fas.push(e)
} else {
dfs(e.w)
}
})
delete stack[v]
}
_.forEach(g.nodes(), dfs)
return fas
}
function undo (g) {
_.forEach(g.edges(), function (e) {
const label = g.edge(e)
if (label.reversed) {
g.removeEdge(e)
const forwardName = label.forwardName
delete label.reversed
delete label.forwardName
g.setEdge(e.w, e.v, label, forwardName)
}
})
}
export default {
run,
undo
}

39
node_modules/dagre-layout/lib/add-border-segments.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
import _ from 'lodash'
import util from './util'
function addBorderSegments (g) {
function dfs (v) {
const children = g.children(v)
const node = g.node(v)
if (children.length) {
_.forEach(children, dfs)
}
if (_.has(node, 'minRank')) {
node.borderLeft = []
node.borderRight = []
for (let rank = node.minRank, maxRank = node.maxRank + 1;
rank < maxRank;
++rank) {
addBorderNode(g, 'borderLeft', '_bl', v, node, rank)
addBorderNode(g, 'borderRight', '_br', v, node, rank)
}
}
}
_.forEach(g.children(), dfs)
}
function addBorderNode (g, prop, prefix, sg, sgNode, rank) {
const label = { width: 0, height: 0, rank: rank, borderType: prop }
const prev = sgNode[prop][rank - 1]
const curr = util.addDummyNode(g, 'border', label, prefix)
sgNode[prop][rank] = curr
g.setParent(curr, sg)
if (prev) {
g.setEdge(prev, curr, { weight: 1 })
}
}
export default addBorderSegments

70
node_modules/dagre-layout/lib/coordinate-system.js generated vendored Normal file
View File

@@ -0,0 +1,70 @@
import _ from 'lodash'
function adjust (g) {
const rankDir = g.graph().rankdir.toLowerCase()
if (rankDir === 'lr' || rankDir === 'rl') {
swapWidthHeight(g)
}
}
function undo (g) {
const rankDir = g.graph().rankdir.toLowerCase()
if (rankDir === 'bt' || rankDir === 'rl') {
reverseY(g)
}
if (rankDir === 'lr' || rankDir === 'rl') {
swapXY(g)
swapWidthHeight(g)
}
}
function swapWidthHeight (g) {
_.forEach(g.nodes(), function (v) { swapWidthHeightOne(g.node(v)) })
_.forEach(g.edges(), function (e) { swapWidthHeightOne(g.edge(e)) })
}
function swapWidthHeightOne (attrs) {
const w = attrs.width
attrs.width = attrs.height
attrs.height = w
}
function reverseY (g) {
_.forEach(g.nodes(), function (v) { reverseYOne(g.node(v)) })
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
_.forEach(edge.points, reverseYOne)
if (_.has(edge, 'y')) {
reverseYOne(edge)
}
})
}
function reverseYOne (attrs) {
attrs.y = -attrs.y
}
function swapXY (g) {
_.forEach(g.nodes(), function (v) { swapXYOne(g.node(v)) })
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
_.forEach(edge.points, swapXYOne)
if (_.has(edge, 'x')) {
swapXYOne(edge)
}
})
}
function swapXYOne (attrs) {
const x = attrs.x
attrs.x = attrs.y
attrs.y = x
}
export default {
adjust,
undo
}

56
node_modules/dagre-layout/lib/data/list.js generated vendored Normal file
View File

@@ -0,0 +1,56 @@
/*
* Simple doubly linked list implementation derived from Cormen, et al.,
* "Introduction to Algorithms".
*/
function List () {
const sentinel = {}
sentinel._next = sentinel._prev = sentinel
this._sentinel = sentinel
}
List.prototype.dequeue = function () {
const sentinel = this._sentinel
const entry = sentinel._prev
if (entry !== sentinel) {
unlink(entry)
return entry
}
}
List.prototype.enqueue = function (entry) {
const sentinel = this._sentinel
if (entry._prev && entry._next) {
unlink(entry)
}
entry._next = sentinel._next
sentinel._next._prev = entry
sentinel._next = entry
entry._prev = sentinel
}
List.prototype.toString = function () {
const strs = []
const sentinel = this._sentinel
let curr = sentinel._prev
while (curr !== sentinel) {
strs.push(JSON.stringify(curr, filterOutLinks))
curr = curr._prev
}
return '[' + strs.join(', ') + ']'
}
function unlink (entry) {
entry._prev._next = entry._next
entry._next._prev = entry._prev
delete entry._next
delete entry._prev
}
function filterOutLinks (k, v) {
if (k !== '_next' && k !== '_prev') {
return v
}
}
export default List

35
node_modules/dagre-layout/lib/debug.js generated vendored Normal file
View File

@@ -0,0 +1,35 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
import util from './util'
/* istanbul ignore next */
function debugOrdering (g) {
const layerMatrix = util.buildLayerMatrix(g)
const h = new Graph({ compound: true, multigraph: true }).setGraph({})
_.forEach(g.nodes(), function (v) {
h.setNode(v, { label: v })
h.setParent(v, 'layer' + g.node(v).rank)
})
_.forEach(g.edges(), function (e) {
h.setEdge(e.v, e.w, {}, e.name)
})
_.forEach(layerMatrix, function (layer, i) {
const layerV = 'layer' + i
h.setNode(layerV, { rank: 'same' })
_.reduce(layer, function (u, v) {
h.setEdge(u, v, { style: 'invis' })
return v
})
})
return h
}
export default {
debugOrdering
}

120
node_modules/dagre-layout/lib/greedy-fas.js generated vendored Normal file
View File

@@ -0,0 +1,120 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
import List from './data/list'
/*
* A greedy heuristic for finding a feedback arc set for a graph. A feedback
* arc set is a set of edges that can be removed to make a graph acyclic.
* The algorithm comes from: P. Eades, X. Lin, and W. F. Smyth, "A fast and
* effective heuristic for the feedback arc set problem." This implementation
* adjusts that from the paper to allow for weighted edges.
*/
const DEFAULT_WEIGHT_FN = _.constant(1)
function greedyFAS (g, weightFn) {
if (g.nodeCount() <= 1) {
return []
}
const state = buildState(g, weightFn || DEFAULT_WEIGHT_FN)
const results = doGreedyFAS(state.graph, state.buckets, state.zeroIdx)
// Expand multi-edges
return _.flatten(_.map(results, function (e) {
return g.outEdges(e.v, e.w)
}), true)
}
function doGreedyFAS (g, buckets, zeroIdx) {
let results = []
const sources = buckets[buckets.length - 1]
const sinks = buckets[0]
let entry
while (g.nodeCount()) {
while ((entry = sinks.dequeue())) { removeNode(g, buckets, zeroIdx, entry) }
while ((entry = sources.dequeue())) { removeNode(g, buckets, zeroIdx, entry) }
if (g.nodeCount()) {
for (let i = buckets.length - 2; i > 0; --i) {
entry = buckets[i].dequeue()
if (entry) {
results = results.concat(removeNode(g, buckets, zeroIdx, entry, true))
break
}
}
}
}
return results
}
function removeNode (g, buckets, zeroIdx, entry, collectPredecessors) {
const results = collectPredecessors ? [] : undefined
_.forEach(g.inEdges(entry.v), function (edge) {
const weight = g.edge(edge)
const uEntry = g.node(edge.v)
if (collectPredecessors) {
results.push({ v: edge.v, w: edge.w })
}
uEntry.out -= weight
assignBucket(buckets, zeroIdx, uEntry)
})
_.forEach(g.outEdges(entry.v), function (edge) {
const weight = g.edge(edge)
const w = edge.w
const wEntry = g.node(w)
wEntry['in'] -= weight
assignBucket(buckets, zeroIdx, wEntry)
})
g.removeNode(entry.v)
return results
}
function buildState (g, weightFn) {
const fasGraph = new Graph()
let maxIn = 0
let maxOut = 0
_.forEach(g.nodes(), function (v) {
fasGraph.setNode(v, { v: v, 'in': 0, out: 0 })
})
// Aggregate weights on nodes, but also sum the weights across multi-edges
// into a single edge for the fasGraph.
_.forEach(g.edges(), function (e) {
const prevWeight = fasGraph.edge(e.v, e.w) || 0
const weight = weightFn(e)
const edgeWeight = prevWeight + weight
fasGraph.setEdge(e.v, e.w, edgeWeight)
maxOut = Math.max(maxOut, fasGraph.node(e.v).out += weight)
maxIn = Math.max(maxIn, fasGraph.node(e.w)['in'] += weight)
})
const buckets = _.range(maxOut + maxIn + 3).map(function () { return new List() })
const zeroIdx = maxIn + 1
_.forEach(fasGraph.nodes(), function (v) {
assignBucket(buckets, zeroIdx, fasGraph.node(v))
})
return { graph: fasGraph, buckets: buckets, zeroIdx: zeroIdx }
}
function assignBucket (buckets, zeroIdx, entry) {
if (!entry.out) {
buckets[0].enqueue(entry)
} else if (!entry['in']) {
buckets[buckets.length - 1].enqueue(entry)
} else {
buckets[entry.out - entry['in'] + zeroIdx].enqueue(entry)
}
}
export default greedyFAS

394
node_modules/dagre-layout/lib/layout.js generated vendored Normal file
View File

@@ -0,0 +1,394 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
import acyclic from './acyclic'
import normalize from './normalize'
import rank from './rank'
import util, { normalizeRanks, removeEmptyRanks } from './util'
import parentDummyChains from './parent-dummy-chains'
import nestingGraph from './nesting-graph'
import addBorderSegments from './add-border-segments'
import coordinateSystem from './coordinate-system'
import order from './order'
import position from './position'
function layout (g, opts) {
const time = opts && opts.debugTiming ? util.time : util.notime
time('layout', function () {
const layoutGraph = time(' buildLayoutGraph',
function () { return buildLayoutGraph(g) })
time(' runLayout', function () { runLayout(layoutGraph, time) })
time(' updateInputGraph', function () { updateInputGraph(g, layoutGraph) })
})
}
function runLayout (g, time) {
time(' makeSpaceForEdgeLabels', function () { makeSpaceForEdgeLabels(g) })
time(' removeSelfEdges', function () { removeSelfEdges(g) })
time(' acyclic', function () { acyclic.run(g) })
time(' nestingGraph.run', function () { nestingGraph.run(g) })
time(' rank', function () { rank(util.asNonCompoundGraph(g)) })
time(' injectEdgeLabelProxies', function () { injectEdgeLabelProxies(g) })
time(' removeEmptyRanks', function () { removeEmptyRanks(g) })
time(' nestingGraph.cleanup', function () { nestingGraph.cleanup(g) })
time(' normalizeRanks', function () { normalizeRanks(g) })
time(' assignRankMinMax', function () { assignRankMinMax(g) })
time(' removeEdgeLabelProxies', function () { removeEdgeLabelProxies(g) })
time(' normalize.run', function () { normalize.run(g) })
time(' parentDummyChains', function () { parentDummyChains(g) })
time(' addBorderSegments', function () { addBorderSegments(g) })
time(' order', function () { order(g) })
time(' insertSelfEdges', function () { insertSelfEdges(g) })
time(' adjustCoordinateSystem', function () { coordinateSystem.adjust(g) })
time(' position', function () { position(g) })
time(' positionSelfEdges', function () { positionSelfEdges(g) })
time(' removeBorderNodes', function () { removeBorderNodes(g) })
time(' normalize.undo', function () { normalize.undo(g) })
time(' fixupEdgeLabelCoords', function () { fixupEdgeLabelCoords(g) })
time(' undoCoordinateSystem', function () { coordinateSystem.undo(g) })
time(' translateGraph', function () { translateGraph(g) })
time(' assignNodeIntersects', function () { assignNodeIntersects(g) })
time(' reversePoints', function () { reversePointsForReversedEdges(g) })
time(' acyclic.undo', function () { acyclic.undo(g) })
}
/*
* Copies final layout information from the layout graph back to the input
* graph. This process only copies whitelisted attributes from the layout graph
* to the input graph, so it serves as a good place to determine what
* attributes can influence layout.
*/
function updateInputGraph (inputGraph, layoutGraph) {
_.forEach(inputGraph.nodes(), function (v) {
const inputLabel = inputGraph.node(v)
const layoutLabel = layoutGraph.node(v)
if (inputLabel) {
inputLabel.x = layoutLabel.x
inputLabel.y = layoutLabel.y
if (layoutGraph.children(v).length) {
inputLabel.width = layoutLabel.width
inputLabel.height = layoutLabel.height
}
}
})
_.forEach(inputGraph.edges(), function (e) {
const inputLabel = inputGraph.edge(e)
const layoutLabel = layoutGraph.edge(e)
inputLabel.points = layoutLabel.points
if (_.has(layoutLabel, 'x')) {
inputLabel.x = layoutLabel.x
inputLabel.y = layoutLabel.y
}
})
inputGraph.graph().width = layoutGraph.graph().width
inputGraph.graph().height = layoutGraph.graph().height
}
const graphNumAttrs = ['nodesep', 'edgesep', 'ranksep', 'marginx', 'marginy']
const graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: 'tb' }
const graphAttrs = ['acyclicer', 'ranker', 'rankdir', 'align']
const nodeNumAttrs = ['width', 'height']
const nodeDefaults = { width: 0, height: 0 }
const edgeNumAttrs = ['minlen', 'weight', 'width', 'height', 'labeloffset']
const edgeDefaults = {
minlen: 1,
weight: 1,
width: 0,
height: 0,
labeloffset: 10,
labelpos: 'r'
}
const edgeAttrs = ['labelpos']
/*
* Constructs a new graph from the input graph, which can be used for layout.
* This process copies only whitelisted attributes from the input graph to the
* layout graph. Thus this function serves as a good place to determine what
* attributes can influence layout.
*/
function buildLayoutGraph (inputGraph) {
const g = new Graph({ multigraph: true, compound: true })
const graph = canonicalize(inputGraph.graph())
g.setGraph(_.merge({},
graphDefaults,
selectNumberAttrs(graph, graphNumAttrs),
_.pick(graph, graphAttrs)))
_.forEach(inputGraph.nodes(), function (v) {
const node = canonicalize(inputGraph.node(v))
g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults))
g.setParent(v, inputGraph.parent(v))
})
_.forEach(inputGraph.edges(), function (e) {
const edge = canonicalize(inputGraph.edge(e))
g.setEdge(e, _.merge({},
edgeDefaults,
selectNumberAttrs(edge, edgeNumAttrs),
_.pick(edge, edgeAttrs)))
})
return g
}
/*
* This idea comes from the Gansner paper: to account for edge labels in our
* layout we split each rank in half by doubling minlen and halving ranksep.
* Then we can place labels at these mid-points between nodes.
*
* We also add some minimal padding to the width to push the label for the edge
* away from the edge itself a bit.
*/
function makeSpaceForEdgeLabels (g) {
const graph = g.graph()
graph.ranksep /= 2
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
edge.minlen *= 2
if (edge.labelpos.toLowerCase() !== 'c') {
if (graph.rankdir === 'TB' || graph.rankdir === 'BT') {
edge.width += edge.labeloffset
} else {
edge.height += edge.labeloffset
}
}
})
}
/*
* Creates temporary dummy nodes that capture the rank in which each edge's
* label is going to, if it has one of non-zero width and height. We do this
* so that we can safely remove empty ranks while preserving balance for the
* label's position.
*/
function injectEdgeLabelProxies (g) {
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
if (edge.width && edge.height) {
const v = g.node(e.v)
const w = g.node(e.w)
const label = { rank: (w.rank - v.rank) / 2 + v.rank, e: e }
util.addDummyNode(g, 'edge-proxy', label, '_ep')
}
})
}
function assignRankMinMax (g) {
let maxRank = 0
_.forEach(g.nodes(), function (v) {
const node = g.node(v)
if (node.borderTop) {
node.minRank = g.node(node.borderTop).rank
node.maxRank = g.node(node.borderBottom).rank
maxRank = Math.max(maxRank, node.maxRank)
}
})
g.graph().maxRank = maxRank
}
function removeEdgeLabelProxies (g) {
_.forEach(g.nodes(), function (v) {
const node = g.node(v)
if (node.dummy === 'edge-proxy') {
g.edge(node.e).labelRank = node.rank
g.removeNode(v)
}
})
}
function translateGraph (g) {
let minX = Number.POSITIVE_INFINITY
let maxX = 0
let minY = Number.POSITIVE_INFINITY
let maxY = 0
const graphLabel = g.graph()
const marginX = graphLabel.marginx || 0
const marginY = graphLabel.marginy || 0
function getExtremes (attrs) {
const x = attrs.x
const y = attrs.y
const w = attrs.width
const h = attrs.height
minX = Math.min(minX, x - w / 2)
maxX = Math.max(maxX, x + w / 2)
minY = Math.min(minY, y - h / 2)
maxY = Math.max(maxY, y + h / 2)
}
_.forEach(g.nodes(), function (v) { getExtremes(g.node(v)) })
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
if (_.has(edge, 'x')) {
getExtremes(edge)
}
})
minX -= marginX
minY -= marginY
_.forEach(g.nodes(), function (v) {
const node = g.node(v)
node.x -= minX
node.y -= minY
})
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
_.forEach(edge.points, function (p) {
p.x -= minX
p.y -= minY
})
if (_.has(edge, 'x')) { edge.x -= minX }
if (_.has(edge, 'y')) { edge.y -= minY }
})
graphLabel.width = maxX - minX + marginX
graphLabel.height = maxY - minY + marginY
}
function assignNodeIntersects (g) {
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
const nodeV = g.node(e.v)
const nodeW = g.node(e.w)
let p1 = null
let p2 = null
if (!edge.points) {
edge.points = []
p1 = nodeW
p2 = nodeV
} else {
p1 = edge.points[0]
p2 = edge.points[edge.points.length - 1]
}
edge.points.unshift(util.intersectRect(nodeV, p1))
edge.points.push(util.intersectRect(nodeW, p2))
})
}
function fixupEdgeLabelCoords (g) {
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
if (_.has(edge, 'x')) {
if (edge.labelpos === 'l' || edge.labelpos === 'r') {
edge.width -= edge.labeloffset
}
switch (edge.labelpos) {
case 'l': edge.x -= edge.width / 2 + edge.labeloffset; break
case 'r': edge.x += edge.width / 2 + edge.labeloffset; break
}
}
})
}
function reversePointsForReversedEdges (g) {
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
if (edge.reversed) {
edge.points.reverse()
}
})
}
function removeBorderNodes (g) {
_.forEach(g.nodes(), function (v) {
if (g.children(v).length) {
const node = g.node(v)
const t = g.node(node.borderTop)
const b = g.node(node.borderBottom)
const l = g.node(_.last(node.borderLeft))
const r = g.node(_.last(node.borderRight))
node.width = Math.abs(r.x - l.x)
node.height = Math.abs(b.y - t.y)
node.x = l.x + node.width / 2
node.y = t.y + node.height / 2
}
})
_.forEach(g.nodes(), function (v) {
if (g.node(v).dummy === 'border') {
g.removeNode(v)
}
})
}
function removeSelfEdges (g) {
_.forEach(g.edges(), function (e) {
if (e.v === e.w) {
const node = g.node(e.v)
if (!node.selfEdges) {
node.selfEdges = []
}
node.selfEdges.push({ e: e, label: g.edge(e) })
g.removeEdge(e)
}
})
}
function insertSelfEdges (g) {
const layers = util.buildLayerMatrix(g)
_.forEach(layers, function (layer) {
let orderShift = 0
_.forEach(layer, function (v, i) {
const node = g.node(v)
node.order = i + orderShift
_.forEach(node.selfEdges, function (selfEdge) {
util.addDummyNode(g, 'selfedge', {
width: selfEdge.label.width,
height: selfEdge.label.height,
rank: node.rank,
order: i + (++orderShift),
e: selfEdge.e,
label: selfEdge.label
}, '_se')
})
delete node.selfEdges
})
})
}
function positionSelfEdges (g) {
_.forEach(g.nodes(), function (v) {
const node = g.node(v)
if (node.dummy === 'selfedge') {
const selfNode = g.node(node.e.v)
const x = selfNode.x + selfNode.width / 2
const y = selfNode.y
const dx = node.x - x
const dy = selfNode.height / 2
g.setEdge(node.e, node.label)
g.removeNode(v)
node.label.points = [
{ x: x + 2 * dx / 3, y: y - dy },
{ x: x + 5 * dx / 6, y: y - dy },
{ x: x + dx, y: y },
{ x: x + 5 * dx / 6, y: y + dy },
{ x: x + 2 * dx / 3, y: y + dy }
]
node.label.x = node.x
node.label.y = node.y
}
})
}
function selectNumberAttrs (obj, attrs) {
return _.mapValues(_.pick(obj, attrs), Number)
}
function canonicalize (attrs) {
const newAttrs = {}
_.forEach(attrs, function (v, k) {
newAttrs[k.toLowerCase()] = v
})
return newAttrs
}
export default layout

133
node_modules/dagre-layout/lib/nesting-graph.js generated vendored Normal file
View File

@@ -0,0 +1,133 @@
import _ from 'lodash'
import util from './util'
/*
* A nesting graph creates dummy nodes for the tops and bottoms of subgraphs,
* adds appropriate edges to ensure that all cluster nodes are placed between
* these boundries, and ensures that the graph is connected.
*
* In addition we ensure, through the use of the minlen property, that nodes
* and subgraph border nodes to not end up on the same rank.
*
* Preconditions:
*
* 1. Input graph is a DAG
* 2. Nodes in the input graph has a minlen attribute
*
* Postconditions:
*
* 1. Input graph is connected.
* 2. Dummy nodes are added for the tops and bottoms of subgraphs.
* 3. The minlen attribute for nodes is adjusted to ensure nodes do not
* get placed on the same rank as subgraph border nodes.
*
* The nesting graph idea comes from Sander, "Layout of Compound Directed
* Graphs."
*/
function run (g) {
const root = util.addDummyNode(g, 'root', {}, '_root')
const depths = treeDepths(g)
const height = _.max(_.values(depths)) - 1
const nodeSep = 2 * height + 1
g.graph().nestingRoot = root
// Multiply minlen by nodeSep to align nodes on non-border ranks.
_.forEach(g.edges(), function (e) { g.edge(e).minlen *= nodeSep })
// Calculate a weight that is sufficient to keep subgraphs vertically compact
const weight = sumWeights(g) + 1
// Create border nodes and link them up
_.forEach(g.children(), function (child) {
dfs(g, root, nodeSep, weight, height, depths, child)
})
// Save the multiplier for node layers for later removal of empty border
// layers.
g.graph().nodeRankFactor = nodeSep
}
function dfs (g, root, nodeSep, weight, height, depths, v) {
const children = g.children(v)
if (!children.length) {
if (v !== root) {
g.setEdge(root, v, { weight: 0, minlen: nodeSep })
}
return
}
const top = util.addBorderNode(g, '_bt')
const bottom = util.addBorderNode(g, '_bb')
const label = g.node(v)
g.setParent(top, v)
label.borderTop = top
g.setParent(bottom, v)
label.borderBottom = bottom
_.forEach(children, function (child) {
dfs(g, root, nodeSep, weight, height, depths, child)
const childNode = g.node(child)
const childTop = childNode.borderTop ? childNode.borderTop : child
const childBottom = childNode.borderBottom ? childNode.borderBottom : child
const thisWeight = childNode.borderTop ? weight : 2 * weight
const minlen = childTop !== childBottom ? 1 : height - depths[v] + 1
g.setEdge(top, childTop, {
weight: thisWeight,
minlen: minlen,
nestingEdge: true
})
g.setEdge(childBottom, bottom, {
weight: thisWeight,
minlen: minlen,
nestingEdge: true
})
})
if (!g.parent(v)) {
g.setEdge(root, top, { weight: 0, minlen: height + depths[v] })
}
}
function treeDepths (g) {
const depths = {}
function dfs (v, depth) {
const children = g.children(v)
if (children && children.length) {
_.forEach(children, function (child) {
dfs(child, depth + 1)
})
}
depths[v] = depth
}
_.forEach(g.children(), function (v) { dfs(v, 1) })
return depths
}
function sumWeights (g) {
return _.reduce(g.edges(), function (acc, e) {
return acc + g.edge(e).weight
}, 0)
}
function cleanup (g) {
const graphLabel = g.graph()
g.removeNode(graphLabel.nestingRoot)
delete graphLabel.nestingRoot
_.forEach(g.edges(), function (e) {
const edge = g.edge(e)
if (edge.nestingEdge) {
g.removeEdge(e)
}
})
}
export default {
run,
cleanup
}

93
node_modules/dagre-layout/lib/normalize.js generated vendored Normal file
View File

@@ -0,0 +1,93 @@
import _ from 'lodash'
import util from './util'
/*
* Breaks any long edges in the graph into short segments that span 1 layer
* each. This operation is undoable with the denormalize function.
*
* Pre-conditions:
*
* 1. The input graph is a DAG.
* 2. Each node in the graph has a "rank" property.
*
* Post-condition:
*
* 1. All edges in the graph have a length of 1.
* 2. Dummy nodes are added where edges have been split into segments.
* 3. The graph is augmented with a "dummyChains" attribute which contains
* the first dummy in each chain of dummy nodes produced.
*/
function run (g) {
g.graph().dummyChains = []
_.forEach(g.edges(), function (edge) { normalizeEdge(g, edge) })
}
function normalizeEdge (g, e) {
let v = e.v
let vRank = g.node(v).rank
const w = e.w
const wRank = g.node(w).rank
const name = e.name
const edgeLabel = g.edge(e)
const labelRank = edgeLabel.labelRank
if (wRank === vRank + 1) return
g.removeEdge(e)
let dummy
let attrs
let i
for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) {
edgeLabel.points = []
attrs = {
width: 0,
height: 0,
edgeLabel: edgeLabel,
edgeObj: e,
rank: vRank
}
dummy = util.addDummyNode(g, 'edge', attrs, '_d')
if (vRank === labelRank) {
attrs.width = edgeLabel.width
attrs.height = edgeLabel.height
attrs.dummy = 'edge-label'
attrs.labelpos = edgeLabel.labelpos
}
g.setEdge(v, dummy, { weight: edgeLabel.weight }, name)
if (i === 0) {
g.graph().dummyChains.push(dummy)
}
v = dummy
}
g.setEdge(v, w, { weight: edgeLabel.weight }, name)
}
function undo (g) {
_.forEach(g.graph().dummyChains, function (v) {
let node = g.node(v)
const origLabel = node.edgeLabel
let w = null
g.setEdge(node.edgeObj, origLabel)
while (node.dummy) {
w = g.successors(v)[0]
g.removeNode(v)
origLabel.points.push({ x: node.x, y: node.y })
if (node.dummy === 'edge-label') {
origLabel.x = node.x
origLabel.y = node.y
origLabel.width = node.width
origLabel.height = node.height
}
v = w
node = g.node(v)
}
})
}
export default {
run,
undo
}

View File

@@ -0,0 +1,53 @@
import _ from 'lodash'
function addSubgraphConstraints (g, cg, vs) {
const prev = {}
let rootPrev
_.forEach(vs, function (v) {
let child = g.parent(v)
let parent
let prevChild
while (child) {
parent = g.parent(child)
if (parent) {
prevChild = prev[parent]
prev[parent] = child
} else {
prevChild = rootPrev
rootPrev = child
}
if (prevChild && prevChild !== child) {
cg.setEdge(prevChild, child)
return
}
child = parent
}
})
/*
function dfs(v) {
const children = v ? g.children(v) : g.children();
if (children.length) {
const min = Number.POSITIVE_INFINITY,
subgraphs = [];
_.forEach(children, function(child) {
const childMin = dfs(child);
if (g.children(child).length) {
subgraphs.push({ v: child, order: childMin });
}
min = Math.min(min, childMin);
});
_.reduce(_.sortBy(subgraphs, "order"), function(prev, curr) {
cg.setEdge(prev.v, curr.v);
return curr;
});
return min;
}
return g.node(v).order;
}
dfs(undefined);
*/
}
export default addSubgraphConstraints

27
node_modules/dagre-layout/lib/order/barycenter.js generated vendored Normal file
View File

@@ -0,0 +1,27 @@
import _ from 'lodash'
function barycenter (g, movable) {
return _.map(movable, function (v) {
const inV = g.inEdges(v)
if (!inV.length) {
return { v: v }
} else {
const result = _.reduce(inV, function (acc, e) {
const edge = g.edge(e)
const nodeU = g.node(e.v)
return {
sum: acc.sum + (edge.weight * nodeU.order),
weight: acc.weight + edge.weight
}
}, { sum: 0, weight: 0 })
return {
v: v,
barycenter: result.sum / result.weight,
weight: result.weight
}
}
})
}
export default barycenter

View File

@@ -0,0 +1,73 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
/*
* Constructs a graph that can be used to sort a layer of nodes. The graph will
* contain all base and subgraph nodes from the request layer in their original
* hierarchy and any edges that are incident on these nodes and are of the type
* requested by the "relationship" parameter.
*
* Nodes from the requested rank that do not have parents are assigned a root
* node in the output graph, which is set in the root graph attribute. This
* makes it easy to walk the hierarchy of movable nodes during ordering.
*
* Pre-conditions:
*
* 1. Input graph is a DAG
* 2. Base nodes in the input graph have a rank attribute
* 3. Subgraph nodes in the input graph has minRank and maxRank attributes
* 4. Edges have an assigned weight
*
* Post-conditions:
*
* 1. Output graph has all nodes in the movable rank with preserved
* hierarchy.
* 2. Root nodes in the movable layer are made children of the node
* indicated by the root attribute of the graph.
* 3. Non-movable nodes incident on movable nodes, selected by the
* relationship parameter, are included in the graph (without hierarchy).
* 4. Edges incident on movable nodes, selected by the relationship
* parameter, are added to the output graph.
* 5. The weights for copied edges are aggregated as need, since the output
* graph is not a multi-graph.
*/
function buildLayerGraph (g, rank, relationship) {
const root = createRootNode(g)
const result = new Graph({ compound: true }).setGraph({ root: root })
.setDefaultNodeLabel(function (v) { return g.node(v) })
_.forEach(g.nodes(), function (v) {
const node = g.node(v)
const parent = g.parent(v)
if (node.rank === rank || (node.minRank <= rank && rank <= node.maxRank)) {
result.setNode(v)
result.setParent(v, parent || root)
// This assumes we have only short edges!
_.forEach(g[relationship](v), function (e) {
const u = e.v === v ? e.w : e.v
const edge = result.edge(u, v)
const weight = !_.isUndefined(edge) ? edge.weight : 0
result.setEdge(u, v, { weight: g.edge(e).weight + weight })
})
if (_.has(node, 'minRank')) {
result.setNode(v, {
borderLeft: node.borderLeft[rank],
borderRight: node.borderRight[rank]
})
}
}
})
return result
}
function createRootNode (g) {
let v
while (g.hasNode((v = _.uniqueId('_root'))));
return v
}
export default buildLayerGraph

70
node_modules/dagre-layout/lib/order/cross-count.js generated vendored Normal file
View File

@@ -0,0 +1,70 @@
import _ from 'lodash'
/*
* A function that takes a layering (an array of layers, each with an array of
* ordererd nodes) and a graph and returns a weighted crossing count.
*
* Pre-conditions:
*
* 1. Input graph must be simple (not a multigraph), directed, and include
* only simple edges.
* 2. Edges in the input graph must have assigned weights.
*
* Post-conditions:
*
* 1. The graph and layering matrix are left unchanged.
*
* This algorithm is derived from Barth, et al., "Bilayer Cross Counting."
*/
function crossCount (g, layering) {
let cc = 0
for (let i = 1; i < layering.length; ++i) {
cc += twoLayerCrossCount(g, layering[i - 1], layering[i])
}
return cc
}
function twoLayerCrossCount (g, northLayer, southLayer) {
// Sort all of the edges between the north and south layers by their position
// in the north layer and then the south. Map these edges to the position of
// their head in the south layer.
const southPos = _.zipObject(southLayer,
_.map(southLayer, function (v, i) { return i }))
const southEntries = _.flatten(_.map(northLayer, function (v) {
return _.chain(g.outEdges(v))
.map(function (e) {
return { pos: southPos[e.w], weight: g.edge(e).weight }
})
.sortBy('pos')
.value()
}), true)
// Build the accumulator tree
let firstIndex = 1
while (firstIndex < southLayer.length) {
firstIndex <<= 1
}
const treeSize = 2 * firstIndex - 1
firstIndex -= 1
const tree = _.map(new Array(treeSize), function () { return 0 })
// Calculate the weighted crossings
let cc = 0
_.forEach(southEntries.forEach(function (entry) {
let index = entry.pos + firstIndex
tree[index] += entry.weight
let weightSum = 0
while (index > 0) {
if (index % 2) {
weightSum += tree[index + 1]
}
index = (index - 1) >> 1
tree[index] += entry.weight
}
cc += entry.weight * weightSum
}))
return cc
}
export default crossCount

78
node_modules/dagre-layout/lib/order/index.js generated vendored Normal file
View File

@@ -0,0 +1,78 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
import initOrder from './init-order'
import crossCount from './cross-count'
import sortSubgraph from './sort-subgraph'
import buildLayerGraph from './build-layer-graph'
import addSubgraphConstraints from './add-subgraph-constraints'
import util from '../util'
/*
* Applies heuristics to minimize edge crossings in the graph and sets the best
* order solution as an order attribute on each node.
*
* Pre-conditions:
*
* 1. Graph must be DAG
* 2. Graph nodes must be objects with a "rank" attribute
* 3. Graph edges must have the "weight" attribute
*
* Post-conditions:
*
* 1. Graph nodes will have an "order" attribute based on the results of the
* algorithm.
*/
function order (g) {
const maxRank = util.maxRank(g)
const downLayerGraphs = buildLayerGraphs(g, _.range(1, maxRank + 1), 'inEdges')
const upLayerGraphs = buildLayerGraphs(g, _.range(maxRank - 1, -1, -1), 'outEdges')
let layering = initOrder(g)
assignOrder(g, layering)
let bestCC = Number.POSITIVE_INFINITY
let best
for (let i = 0, lastBest = 0; lastBest < 4; ++i, ++lastBest) {
sweepLayerGraphs(i % 2 ? downLayerGraphs : upLayerGraphs, i % 4 >= 2)
layering = util.buildLayerMatrix(g)
const cc = crossCount(g, layering)
if (cc < bestCC) {
lastBest = 0
best = _.cloneDeep(layering)
bestCC = cc
}
}
assignOrder(g, best)
}
function buildLayerGraphs (g, ranks, relationship) {
return _.map(ranks, function (rank) {
return buildLayerGraph(g, rank, relationship)
})
}
function sweepLayerGraphs (layerGraphs, biasRight) {
const cg = new Graph()
_.forEach(layerGraphs, function (lg) {
const root = lg.graph().root
const sorted = sortSubgraph(lg, root, cg, biasRight)
_.forEach(sorted.vs, function (v, i) {
lg.node(v).order = i
})
addSubgraphConstraints(lg, cg, sorted.vs)
})
}
function assignOrder (g, layering) {
_.forEach(layering, function (layer) {
_.forEach(layer, function (v, i) {
g.node(v).order = i
})
})
}
export default order

36
node_modules/dagre-layout/lib/order/init-order.js generated vendored Normal file
View File

@@ -0,0 +1,36 @@
import _ from 'lodash'
/*
* Assigns an initial order value for each node by performing a DFS search
* starting from nodes in the first rank. Nodes are assigned an order in their
* rank as they are first visited.
*
* This approach comes from Gansner, et al., "A Technique for Drawing Directed
* Graphs."
*
* Returns a layering matrix with an array per layer and each layer sorted by
* the order of its nodes.
*/
function initOrder (g) {
const visited = {}
const simpleNodes = _.filter(g.nodes(), function (v) {
return !g.children(v).length
})
const maxRank = _.max(_.map(simpleNodes, function (v) { return g.node(v).rank }))
const layers = _.map(_.range(maxRank + 1), function () { return [] })
function dfs (v) {
if (_.has(visited, v)) return
visited[v] = true
const node = g.node(v)
layers[node.rank].push(v)
_.forEach(g.successors(v), dfs)
}
const orderedVs = _.sortBy(simpleNodes, function (v) { return g.node(v).rank })
_.forEach(orderedVs, dfs)
return layers
}
export default initOrder

View File

@@ -0,0 +1,121 @@
import _ from 'lodash'
/*
* Given a list of entries of the form {v, barycenter, weight} and a
* constraint graph this function will resolve any conflicts between the
* constraint graph and the barycenters for the entries. If the barycenters for
* an entry would violate a constraint in the constraint graph then we coalesce
* the nodes in the conflict into a new node that respects the contraint and
* aggregates barycenter and weight information.
*
* This implementation is based on the description in Forster, "A Fast and
* Simple Hueristic for Constrained Two-Level Crossing Reduction," thought it
* differs in some specific details.
*
* Pre-conditions:
*
* 1. Each entry has the form {v, barycenter, weight}, or if the node has
* no barycenter, then {v}.
*
* Returns:
*
* A new list of entries of the form {vs, i, barycenter, weight}. The list
* `vs` may either be a singleton or it may be an aggregation of nodes
* ordered such that they do not violate constraints from the constraint
* graph. The property `i` is the lowest original index of any of the
* elements in `vs`.
*/
function resolveConflicts (entries, cg) {
const mappedEntries = {}
_.forEach(entries, function (entry, i) {
const tmp = mappedEntries[entry.v] = {
indegree: 0,
'in': [],
out: [],
vs: [entry.v],
i: i
}
if (!_.isUndefined(entry.barycenter)) {
tmp.barycenter = entry.barycenter
tmp.weight = entry.weight
}
})
_.forEach(cg.edges(), function (e) {
const entryV = mappedEntries[e.v]
const entryW = mappedEntries[e.w]
if (!_.isUndefined(entryV) && !_.isUndefined(entryW)) {
entryW.indegree++
entryV.out.push(mappedEntries[e.w])
}
})
const sourceSet = _.filter(mappedEntries, function (entry) {
return !entry.indegree
})
return doResolveConflicts(sourceSet)
}
function doResolveConflicts (sourceSet) {
const entries = []
function handleIn (vEntry) {
return function (uEntry) {
if (uEntry.merged) {
return
}
if (_.isUndefined(uEntry.barycenter) ||
_.isUndefined(vEntry.barycenter) ||
uEntry.barycenter >= vEntry.barycenter) {
mergeEntries(vEntry, uEntry)
}
}
}
function handleOut (vEntry) {
return function (wEntry) {
wEntry['in'].push(vEntry)
if (--wEntry.indegree === 0) {
sourceSet.push(wEntry)
}
}
}
while (sourceSet.length) {
const entry = sourceSet.pop()
entries.push(entry)
_.forEach(entry['in'].reverse(), handleIn(entry))
_.forEach(entry.out, handleOut(entry))
}
return _.chain(entries)
.filter(function (entry) { return !entry.merged })
.map(function (entry) {
return _.pick(entry, ['vs', 'i', 'barycenter', 'weight'])
})
.value()
}
function mergeEntries (target, source) {
let sum = 0
let weight = 0
if (target.weight) {
sum += target.barycenter * target.weight
weight += target.weight
}
if (source.weight) {
sum += source.barycenter * source.weight
weight += source.weight
}
target.vs = source.vs.concat(target.vs)
target.barycenter = sum / weight
target.weight = weight
target.i = Math.min(source.i, target.i)
source.merged = true
}
export default resolveConflicts

77
node_modules/dagre-layout/lib/order/sort-subgraph.js generated vendored Normal file
View File

@@ -0,0 +1,77 @@
import _ from 'lodash'
import barycenter from './barycenter'
import resolveConflicts from './resolve-conflicts'
import sort from './sort'
function sortSubgraph (g, v, cg, biasRight) {
let movable = g.children(v)
const node = g.node(v)
const bl = node ? node.borderLeft : undefined
const br = node ? node.borderRight : undefined
const subgraphs = {}
if (bl) {
movable = _.filter(movable, function (w) {
return w !== bl && w !== br
})
}
const barycenters = barycenter(g, movable)
_.forEach(barycenters, function (entry) {
if (g.children(entry.v).length) {
const subgraphResult = sortSubgraph(g, entry.v, cg, biasRight)
subgraphs[entry.v] = subgraphResult
if (_.has(subgraphResult, 'barycenter')) {
mergeBarycenters(entry, subgraphResult)
}
}
})
const entries = resolveConflicts(barycenters, cg)
expandSubgraphs(entries, subgraphs)
const result = sort(entries, biasRight)
if (bl) {
result.vs = _.flatten([bl, result.vs, br], true)
if (g.predecessors(bl).length) {
const blPred = g.node(g.predecessors(bl)[0])
const brPred = g.node(g.predecessors(br)[0])
if (!_.has(result, 'barycenter')) {
result.barycenter = 0
result.weight = 0
}
result.barycenter = (result.barycenter * result.weight +
blPred.order + brPred.order) / (result.weight + 2)
result.weight += 2
}
}
return result
}
function expandSubgraphs (entries, subgraphs) {
_.forEach(entries, function (entry) {
entry.vs = _.flatten(entry.vs.map(function (v) {
if (subgraphs[v]) {
return subgraphs[v].vs
}
return v
}), true)
})
}
function mergeBarycenters (target, other) {
if (!_.isUndefined(target.barycenter)) {
target.barycenter = (target.barycenter * target.weight +
other.barycenter * other.weight) /
(target.weight + other.weight)
target.weight += other.weight
} else {
target.barycenter = other.barycenter
target.weight = other.weight
}
}
export default sortSubgraph

58
node_modules/dagre-layout/lib/order/sort.js generated vendored Normal file
View File

@@ -0,0 +1,58 @@
import _ from 'lodash'
import util from '../util'
function sort (entries, biasRight) {
const parts = util.partition(entries, function (entry) {
return _.has(entry, 'barycenter')
})
const sortable = parts.lhs
const unsortable = _.sortBy(parts.rhs, function (entry) { return -entry.i })
const vs = []
let sum = 0
let weight = 0
let vsIndex = 0
sortable.sort(compareWithBias(!!biasRight))
vsIndex = consumeUnsortable(vs, unsortable, vsIndex)
_.forEach(sortable, function (entry) {
vsIndex += entry.vs.length
vs.push(entry.vs)
sum += entry.barycenter * entry.weight
weight += entry.weight
vsIndex = consumeUnsortable(vs, unsortable, vsIndex)
})
const result = { vs: _.flatten(vs, true) }
if (weight) {
result.barycenter = sum / weight
result.weight = weight
}
return result
}
function consumeUnsortable (vs, unsortable, index) {
let last
while (unsortable.length && (last = _.last(unsortable)).i <= index) {
unsortable.pop()
vs.push(last.vs)
index++
}
return index
}
function compareWithBias (bias) {
return function (entryV, entryW) {
if (entryV.barycenter < entryW.barycenter) {
return -1
} else if (entryV.barycenter > entryW.barycenter) {
return 1
}
return !bias ? entryV.i - entryW.i : entryW.i - entryV.i
}
}
export default sort

86
node_modules/dagre-layout/lib/parent-dummy-chains.js generated vendored Normal file
View File

@@ -0,0 +1,86 @@
import _ from 'lodash'
function parentDummyChains (g) {
const postorderNums = postorder(g)
_.forEach(g.graph().dummyChains, function (v) {
let node = g.node(v)
const edgeObj = node.edgeObj
const pathData = findPath(g, postorderNums, edgeObj.v, edgeObj.w)
const path = pathData.path
const lca = pathData.lca
let pathIdx = 0
let pathV = path[pathIdx]
let ascending = true
while (v !== edgeObj.w) {
node = g.node(v)
if (ascending) {
while ((pathV = path[pathIdx]) !== lca &&
g.node(pathV).maxRank < node.rank) {
pathIdx++
}
if (pathV === lca) {
ascending = false
}
}
if (!ascending) {
while (pathIdx < path.length - 1 &&
g.node(pathV = path[pathIdx + 1]).minRank <= node.rank) {
pathIdx++
}
pathV = path[pathIdx]
}
g.setParent(v, pathV)
v = g.successors(v)[0]
}
})
}
// Find a path from v to w through the lowest common ancestor (LCA). Return the
// full path and the LCA.
function findPath (g, postorderNums, v, w) {
const vPath = []
const wPath = []
const low = Math.min(postorderNums[v].low, postorderNums[w].low)
const lim = Math.max(postorderNums[v].lim, postorderNums[w].lim)
let parent
let lca
// Traverse up from v to find the LCA
parent = v
do {
parent = g.parent(parent)
vPath.push(parent)
} while (parent &&
(postorderNums[parent].low > low || lim > postorderNums[parent].lim))
lca = parent
// Traverse from w to LCA
parent = w
while ((parent = g.parent(parent)) !== lca) {
wPath.push(parent)
}
return { path: vPath.concat(wPath.reverse()), lca: lca }
}
function postorder (g) {
const result = {}
let lim = 0
function dfs (v) {
const low = lim
_.forEach(g.children(v), dfs)
result[v] = { low: low, lim: lim++ }
}
_.forEach(g.children(), dfs)
return result
}
export default parentDummyChains

392
node_modules/dagre-layout/lib/position/bk.js generated vendored Normal file
View File

@@ -0,0 +1,392 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
import util from '../util'
/*
* This module provides coordinate assignment based on Brandes and Köpf, "Fast
* and Simple Horizontal Coordinate Assignment."
*/
/*
* Marks all edges in the graph with a type-1 conflict with the "type1Conflict"
* property. A type-1 conflict is one where a non-inner segment crosses an
* inner segment. An inner segment is an edge with both incident nodes marked
* with the "dummy" property.
*
* This algorithm scans layer by layer, starting with the second, for type-1
* conflicts between the current layer and the previous layer. For each layer
* it scans the nodes from left to right until it reaches one that is incident
* on an inner segment. It then scans predecessors to determine if they have
* edges that cross that inner segment. At the end a final scan is done for all
* nodes on the current rank to see if they cross the last visited inner
* segment.
*
* This algorithm (safely) assumes that a dummy node will only be incident on a
* single node in the layers being scanned.
*/
function findType1Conflicts (g, layering) {
const conflicts = {}
function visitLayer (prevLayer, layer) {
// last visited node in the previous layer that is incident on an inner
// segment.
let k0 = 0
// Tracks the last node in this layer scanned for crossings with a type-1
// segment.
let scanPos = 0
const prevLayerLength = prevLayer.length
const lastNode = _.last(layer)
_.forEach(layer, function (v, i) {
const w = findOtherInnerSegmentNode(g, v)
const k1 = w ? g.node(w).order : prevLayerLength
if (w || v === lastNode) {
_.forEach(layer.slice(scanPos, i + 1), function (scanNode) {
_.forEach(g.predecessors(scanNode), function (u) {
const uLabel = g.node(u)
const uPos = uLabel.order
if ((uPos < k0 || k1 < uPos) &&
!(uLabel.dummy && g.node(scanNode).dummy)) {
addConflict(conflicts, u, scanNode)
}
})
})
scanPos = i + 1
k0 = k1
}
})
return layer
}
_.reduce(layering, visitLayer)
return conflicts
}
function findType2Conflicts (g, layering) {
const conflicts = {}
function scan (south, southPos, southEnd, prevNorthBorder, nextNorthBorder) {
let v
_.forEach(_.range(southPos, southEnd), function (i) {
v = south[i]
if (g.node(v).dummy) {
_.forEach(g.predecessors(v), function (u) {
const uNode = g.node(u)
if (uNode.dummy &&
(uNode.order < prevNorthBorder || uNode.order > nextNorthBorder)) {
addConflict(conflicts, u, v)
}
})
}
})
}
function visitLayer (north, south) {
let prevNorthPos = -1
let nextNorthPos
let southPos = 0
_.forEach(south, function (v, southLookahead) {
if (g.node(v).dummy === 'border') {
const predecessors = g.predecessors(v)
if (predecessors.length) {
nextNorthPos = g.node(predecessors[0]).order
scan(south, southPos, southLookahead, prevNorthPos, nextNorthPos)
southPos = southLookahead
prevNorthPos = nextNorthPos
}
}
scan(south, southPos, south.length, nextNorthPos, north.length)
})
return south
}
_.reduce(layering, visitLayer)
return conflicts
}
function findOtherInnerSegmentNode (g, v) {
if (g.node(v).dummy) {
return _.find(g.predecessors(v), function (u) {
return g.node(u).dummy
})
}
}
function addConflict (conflicts, v, w) {
if (v > w) {
const tmp = v
v = w
w = tmp
}
let conflictsV = conflicts[v]
if (!conflictsV) {
conflicts[v] = conflictsV = {}
}
conflictsV[w] = true
}
function hasConflict (conflicts, v, w) {
if (v > w) {
const tmp = v
v = w
w = tmp
}
return _.has(conflicts[v], w)
}
/*
* Try to align nodes into vertical "blocks" where possible. This algorithm
* attempts to align a node with one of its median neighbors. If the edge
* connecting a neighbor is a type-1 conflict then we ignore that possibility.
* If a previous node has already formed a block with a node after the node
* we're trying to form a block with, we also ignore that possibility - our
* blocks would be split in that scenario.
*/
function verticalAlignment (g, layering, conflicts, neighborFn) {
const root = {}
const align = {}
const pos = {}
// We cache the position here based on the layering because the graph and
// layering may be out of sync. The layering matrix is manipulated to
// generate different extreme alignments.
_.forEach(layering, function (layer) {
_.forEach(layer, function (v, order) {
root[v] = v
align[v] = v
pos[v] = order
})
})
_.forEach(layering, function (layer) {
let prevIdx = -1
_.forEach(layer, function (v) {
let ws = neighborFn(v)
if (ws.length) {
ws = _.sortBy(ws, function (w) { return pos[w] })
const mp = (ws.length - 1) / 2
for (let i = Math.floor(mp), il = Math.ceil(mp); i <= il; ++i) {
const w = ws[i]
if (align[v] === v && prevIdx < pos[w] && !hasConflict(conflicts, v, w)) {
align[w] = v
align[v] = root[v] = root[w]
prevIdx = pos[w]
}
}
}
})
})
return { root: root, align: align }
}
function horizontalCompaction (g, layering, root, align, reverseSep) {
// This portion of the algorithm differs from BK due to a number of problems.
// Instead of their algorithm we construct a new block graph and do two
// sweeps. The first sweep places blocks with the smallest possible
// coordinates. The second sweep removes unused space by moving blocks to the
// greatest coordinates without violating separation.
const xs = {}
const blockG = buildBlockGraph(g, layering, root, reverseSep)
// First pass, assign smallest coordinates via DFS
const visited = {}
function pass1 (v) {
if (!_.has(visited, v)) {
visited[v] = true
xs[v] = _.reduce(blockG.inEdges(v), function (max, e) {
pass1(e.v)
return Math.max(max, xs[e.v] + blockG.edge(e))
}, 0)
}
}
_.forEach(blockG.nodes(), pass1)
const borderType = reverseSep ? 'borderLeft' : 'borderRight'
function pass2 (v) {
if (visited[v] !== 2) {
visited[v]++
const node = g.node(v)
const min = _.reduce(blockG.outEdges(v), function (min, e) {
pass2(e.w)
return Math.min(min, xs[e.w] - blockG.edge(e))
}, Number.POSITIVE_INFINITY)
if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
xs[v] = Math.max(xs[v], min)
}
}
}
_.forEach(blockG.nodes(), pass2)
// Assign x coordinates to all nodes
_.forEach(align, function (v) {
xs[v] = xs[root[v]]
})
return xs
}
function buildBlockGraph (g, layering, root, reverseSep) {
const blockGraph = new Graph()
const graphLabel = g.graph()
const sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep)
_.forEach(layering, function (layer) {
let u
_.forEach(layer, function (v) {
const vRoot = root[v]
blockGraph.setNode(vRoot)
if (u) {
const uRoot = root[u]
const prevMax = blockGraph.edge(uRoot, vRoot)
blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0))
}
u = v
})
})
return blockGraph
}
/*
* Returns the alignment that has the smallest width of the given alignments.
*/
function findSmallestWidthAlignment (g, xss) {
return _.minBy(_.values(xss), function (xs) {
const min = (_.minBy(_.toPairs(xs), (pair) => pair[1] - width(g, pair[0]) / 2) || ['k', 0])[1]
const max = (_.maxBy(_.toPairs(xs), (pair) => pair[1] + width(g, pair[0]) / 2) || ['k', 0])[1]
return max - min
})
}
/*
* Align the coordinates of each of the layout alignments such that
* left-biased alignments have their minimum coordinate at the same point as
* the minimum coordinate of the smallest width alignment and right-biased
* alignments have their maximum coordinate at the same point as the maximum
* coordinate of the smallest width alignment.
*/
function alignCoordinates (xss, alignTo) {
const alignToVals = _.values(alignTo)
const alignToMin = _.min(alignToVals)
const alignToMax = _.max(alignToVals)
_.forEach(['u', 'd'], function (vert) {
_.forEach(['l', 'r'], function (horiz) {
const alignment = vert + horiz
const xs = xss[alignment]
if (xs === alignTo) {
return
}
const xsVals = _.values(xs)
const delta = horiz === 'l' ? alignToMin - _.min(xsVals) : alignToMax - _.max(xsVals)
if (delta) {
xss[alignment] = _.mapValues(xs, function (x) { return x + delta })
}
})
})
}
function balance (xss, align) {
return _.mapValues(xss.ul, function (ignore, v) {
if (align) {
return xss[align.toLowerCase()][v]
} else {
const xs = _.sortBy(_.map(xss, v))
return (xs[1] + xs[2]) / 2
}
})
}
export function positionX (g) {
const layering = util.buildLayerMatrix(g)
const conflicts = _.merge(findType1Conflicts(g, layering), findType2Conflicts(g, layering))
const xss = {}
let adjustedLayering
_.forEach(['u', 'd'], function (vert) {
adjustedLayering = vert === 'u' ? layering : _.values(layering).reverse()
_.forEach(['l', 'r'], function (horiz) {
if (horiz === 'r') {
adjustedLayering = _.map(adjustedLayering, function (inner) {
return _.values(inner).reverse()
})
}
const neighborFn = _.bind(vert === 'u' ? g.predecessors : g.successors, g)
const align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn)
let xs = horizontalCompaction(g, adjustedLayering,
align.root, align.align,
horiz === 'r')
if (horiz === 'r') {
xs = _.mapValues(xs, function (x) { return -x })
}
xss[vert + horiz] = xs
})
})
const smallestWidth = findSmallestWidthAlignment(g, xss)
alignCoordinates(xss, smallestWidth)
return balance(xss, g.graph().align)
}
function sep (nodeSep, edgeSep, reverseSep) {
return function (g, v, w) {
const vLabel = g.node(v)
const wLabel = g.node(w)
let sum = 0
let delta
sum += vLabel.width / 2
if (_.has(vLabel, 'labelpos')) {
switch (vLabel.labelpos.toLowerCase()) {
case 'l': delta = -vLabel.width / 2; break
case 'r': delta = vLabel.width / 2; break
}
}
if (delta) {
sum += reverseSep ? delta : -delta
}
delta = 0
sum += (vLabel.dummy ? edgeSep : nodeSep) / 2
sum += (wLabel.dummy ? edgeSep : nodeSep) / 2
sum += wLabel.width / 2
if (_.has(wLabel, 'labelpos')) {
switch (wLabel.labelpos.toLowerCase()) {
case 'l': delta = wLabel.width / 2; break
case 'r': delta = -wLabel.width / 2; break
}
}
if (delta) {
sum += reverseSep ? delta : -delta
}
delta = 0
return sum
}
}
function width (g, v) {
return g.node(v).width
}
export default {
positionX: positionX,
findType1Conflicts: findType1Conflicts,
findType2Conflicts: findType2Conflicts,
addConflict: addConflict,
hasConflict: hasConflict,
verticalAlignment: verticalAlignment,
horizontalCompaction: horizontalCompaction,
alignCoordinates: alignCoordinates,
findSmallestWidthAlignment: findSmallestWidthAlignment,
balance: balance
}

28
node_modules/dagre-layout/lib/position/index.js generated vendored Normal file
View File

@@ -0,0 +1,28 @@
import _ from 'lodash'
import util from '../util'
import { positionX } from './bk'
function position (g) {
g = util.asNonCompoundGraph(g)
positionY(g)
_.forEach(positionX(g), function (x, v) {
g.node(v).x = x
})
}
function positionY (g) {
const layering = util.buildLayerMatrix(g)
const rankSep = g.graph().ranksep
let prevY = 0
_.forEach(layering, function (layer) {
const maxHeight = _.max(_.map(layer, function (v) { return g.node(v).height }))
_.forEach(layer, function (v) {
g.node(v).y = prevY + maxHeight / 2
})
prevY += maxHeight + rankSep
})
}
export default position

89
node_modules/dagre-layout/lib/rank/feasible-tree.js generated vendored Normal file
View File

@@ -0,0 +1,89 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
import { slack } from './util'
/*
* Constructs a spanning tree with tight edges and adjusted the input node's
* ranks to achieve this. A tight edge is one that is has a length that matches
* its "minlen" attribute.
*
* The basic structure for this function is derived from Gansner, et al., "A
* Technique for Drawing Directed Graphs."
*
* Pre-conditions:
*
* 1. Graph must be a DAG.
* 2. Graph must be connected.
* 3. Graph must have at least one node.
* 5. Graph nodes must have been previously assigned a "rank" property that
* respects the "minlen" property of incident edges.
* 6. Graph edges must have a "minlen" property.
*
* Post-conditions:
*
* - Graph nodes will have their rank adjusted to ensure that all edges are
* tight.
*
* Returns a tree (undirected graph) that is constructed using only "tight"
* edges.
*/
function feasibleTree (g) {
const t = new Graph({ directed: false })
// Choose arbitrary node from which to start our tree
const start = g.nodes()[0]
const size = g.nodeCount()
t.setNode(start, {})
let edge
let delta
while (tightTree(t, g) < size) {
edge = findMinSlackEdge(t, g)
delta = t.hasNode(edge.v) ? slack(g, edge) : -slack(g, edge)
shiftRanks(t, g, delta)
}
return t
}
/*
* Finds a maximal tree of tight edges and returns the number of nodes in the
* tree.
*/
function tightTree (t, g) {
function dfs (v) {
_.forEach(g.nodeEdges(v), function (e) {
const edgeV = e.v
const w = (v === edgeV) ? e.w : edgeV
if (!t.hasNode(w) && !slack(g, e)) {
t.setNode(w, {})
t.setEdge(v, w, {})
dfs(w)
}
})
}
_.forEach(t.nodes(), dfs)
return t.nodeCount()
}
/*
* Finds the edge with the smallest slack that is incident on tree and returns
* it.
*/
function findMinSlackEdge (t, g) {
return _.minBy(g.edges(), function (e) {
if (t.hasNode(e.v) !== t.hasNode(e.w)) {
return slack(g, e)
}
})
}
function shiftRanks (t, g, delta) {
_.forEach(t.nodes(), function (v) {
g.node(v).rank += delta
})
}
export default feasibleTree

45
node_modules/dagre-layout/lib/rank/index.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
import { longestPath } from './util'
import feasibleTree from './feasible-tree'
import networkSimplex from './network-simplex'
/*
* Assigns a rank to each node in the input graph that respects the "minlen"
* constraint specified on edges between nodes.
*
* This basic structure is derived from Gansner, et al., "A Technique for
* Drawing Directed Graphs."
*
* Pre-conditions:
*
* 1. Graph must be a connected DAG
* 2. Graph nodes must be objects
* 3. Graph edges must have "weight" and "minlen" attributes
*
* Post-conditions:
*
* 1. Graph nodes will have a "rank" attribute based on the results of the
* algorithm. Ranks can start at any index (including negative), we'll
* fix them up later.
*/
function rank (g) {
switch (g.graph().ranker) {
case 'network-simplex': networkSimplexRanker(g); break
case 'tight-tree': tightTreeRanker(g); break
case 'longest-path': longestPathRanker(g); break
default: networkSimplexRanker(g)
}
}
// A fast and simple ranker, but results are far from optimal.
const longestPathRanker = longestPath
function tightTreeRanker (g) {
longestPath(g)
feasibleTree(g)
}
function networkSimplexRanker (g) {
networkSimplex(g)
}
export default rank

234
node_modules/dagre-layout/lib/rank/network-simplex.js generated vendored Normal file
View File

@@ -0,0 +1,234 @@
import _ from 'lodash'
import { alg } from 'graphlibrary'
import feasibleTree from './feasible-tree'
import { slack, longestPath as initRank } from './util'
import { simplify } from '../util'
const { preorder, postorder } = alg
// Expose some internals for testing purposes
networkSimplex.initLowLimValues = initLowLimValues
networkSimplex.initCutValues = initCutValues
networkSimplex.calcCutValue = calcCutValue
networkSimplex.leaveEdge = leaveEdge
networkSimplex.enterEdge = enterEdge
networkSimplex.exchangeEdges = exchangeEdges
/*
* The network simplex algorithm assigns ranks to each node in the input graph
* and iteratively improves the ranking to reduce the length of edges.
*
* Preconditions:
*
* 1. The input graph must be a DAG.
* 2. All nodes in the graph must have an object value.
* 3. All edges in the graph must have "minlen" and "weight" attributes.
*
* Postconditions:
*
* 1. All nodes in the graph will have an assigned "rank" attribute that has
* been optimized by the network simplex algorithm. Ranks start at 0.
*
*
* A rough sketch of the algorithm is as follows:
*
* 1. Assign initial ranks to each node. We use the longest path algorithm,
* which assigns ranks to the lowest position possible. In general this
* leads to very wide bottom ranks and unnecessarily long edges.
* 2. Construct a feasible tight tree. A tight tree is one such that all
* edges in the tree have no slack (difference between length of edge
* and minlen for the edge). This by itself greatly improves the assigned
* rankings by shorting edges.
* 3. Iteratively find edges that have negative cut values. Generally a
* negative cut value indicates that the edge could be removed and a new
* tree edge could be added to produce a more compact graph.
*
* Much of the algorithms here are derived from Gansner, et al., "A Technique
* for Drawing Directed Graphs." The structure of the file roughly follows the
* structure of the overall algorithm.
*/
function networkSimplex (g) {
g = simplify(g)
initRank(g)
const t = feasibleTree(g)
initLowLimValues(t)
initCutValues(t, g)
let e
let f
while ((e = leaveEdge(t))) {
f = enterEdge(t, g, e)
exchangeEdges(t, g, e, f)
}
}
/*
* Initializes cut values for all edges in the tree.
*/
function initCutValues (t, g) {
let vs = postorder(t, t.nodes())
vs = vs.slice(0, vs.length - 1)
_.forEach(vs, function (v) {
assignCutValue(t, g, v)
})
}
function assignCutValue (t, g, child) {
const childLab = t.node(child)
const parent = childLab.parent
t.edge(child, parent).cutvalue = calcCutValue(t, g, child)
}
/*
* Given the tight tree, its graph, and a child in the graph calculate and
* return the cut value for the edge between the child and its parent.
*/
function calcCutValue (t, g, child) {
const childLab = t.node(child)
const parent = childLab.parent
// True if the child is on the tail end of the edge in the directed graph
let childIsTail = true
// The graph's view of the tree edge we're inspecting
let graphEdge = g.edge(child, parent)
// The accumulated cut value for the edge between this node and its parent
let cutValue = 0
if (!graphEdge) {
childIsTail = false
graphEdge = g.edge(parent, child)
}
cutValue = graphEdge.weight
_.forEach(g.nodeEdges(child), function (e) {
const isOutEdge = e.v === child
const other = isOutEdge ? e.w : e.v
if (other !== parent) {
const pointsToHead = isOutEdge === childIsTail
const otherWeight = g.edge(e).weight
cutValue += pointsToHead ? otherWeight : -otherWeight
if (isTreeEdge(t, child, other)) {
const otherCutValue = t.edge(child, other).cutvalue
cutValue += pointsToHead ? -otherCutValue : otherCutValue
}
}
})
return cutValue
}
function initLowLimValues (tree, root) {
if (arguments.length < 2) {
root = tree.nodes()[0]
}
dfsAssignLowLim(tree, {}, 1, root)
}
function dfsAssignLowLim (tree, visited, nextLim, v, parent) {
const low = nextLim
const label = tree.node(v)
visited[v] = true
_.forEach(tree.neighbors(v), function (w) {
if (!_.has(visited, w)) {
nextLim = dfsAssignLowLim(tree, visited, nextLim, w, v)
}
})
label.low = low
label.lim = nextLim++
if (parent) {
label.parent = parent
} else {
// TODO should be able to remove this when we incrementally update low lim
delete label.parent
}
return nextLim
}
function leaveEdge (tree) {
return _.find(tree.edges(), function (e) {
return tree.edge(e).cutvalue < 0
})
}
function enterEdge (t, g, edge) {
let v = edge.v
let w = edge.w
// For the rest of this function we assume that v is the tail and w is the
// head, so if we don't have this edge in the graph we should flip it to
// match the correct orientation.
if (!g.hasEdge(v, w)) {
v = edge.w
w = edge.v
}
const vLabel = t.node(v)
const wLabel = t.node(w)
let tailLabel = vLabel
let flip = false
// If the root is in the tail of the edge then we need to flip the logic that
// checks for the head and tail nodes in the candidates function below.
if (vLabel.lim > wLabel.lim) {
tailLabel = wLabel
flip = true
}
const candidates = _.filter(g.edges(), function (edge) {
return flip === isDescendant(t, t.node(edge.v), tailLabel) &&
flip !== isDescendant(t, t.node(edge.w), tailLabel)
})
return _.minBy(candidates, function (edge) { return slack(g, edge) })
}
function exchangeEdges (t, g, e, f) {
const v = e.v
const w = e.w
t.removeEdge(v, w)
t.setEdge(f.v, f.w, {})
initLowLimValues(t)
initCutValues(t, g)
updateRanks(t, g)
}
function updateRanks (t, g) {
const root = _.find(t.nodes(), function (v) { return !g.node(v).parent })
let vs = preorder(t, root)
vs = vs.slice(1)
_.forEach(vs, function (v) {
const parent = t.node(v).parent
let edge = g.edge(v, parent)
let flipped = false
if (!edge) {
edge = g.edge(parent, v)
flipped = true
}
g.node(v).rank = g.node(parent).rank + (flipped ? edge.minlen : -edge.minlen)
})
}
/*
* Returns true if the edge is in the tree.
*/
function isTreeEdge (tree, u, v) {
return tree.hasEdge(u, v)
}
/*
* Returns true if the specified node is descendant of the root node per the
* assigned low and lim attributes in the tree.
*/
function isDescendant (tree, vLabel, rootLabel) {
return rootLabel.low <= vLabel.lim && vLabel.lim <= rootLabel.lim
}
export default networkSimplex

55
node_modules/dagre-layout/lib/rank/util.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
import _ from 'lodash'
/*
* Initializes ranks for the input graph using the longest path algorithm. This
* algorithm scales well and is fast in practice, it yields rather poor
* solutions. Nodes are pushed to the lowest layer possible, leaving the bottom
* ranks wide and leaving edges longer than necessary. However, due to its
* speed, this algorithm is good for getting an initial ranking that can be fed
* into other algorithms.
*
* This algorithm does not normalize layers because it will be used by other
* algorithms in most cases. If using this algorithm directly, be sure to
* run normalize at the end.
*
* Pre-conditions:
*
* 1. Input graph is a DAG.
* 2. Input graph node labels can be assigned properties.
*
* Post-conditions:
*
* 1. Each node will be assign an (unnormalized) "rank" property.
*/
export function longestPath (g) {
const visited = {}
function dfs (v) {
const label = g.node(v)
if (_.has(visited, v)) {
return label.rank
}
visited[v] = true
const rank = _.min(_.map(g.outEdges(v), function (e) {
return dfs(e.w) - g.edge(e).minlen
})) || 0
return (label.rank = rank)
}
_.forEach(g.sources(), dfs)
}
/*
* Returns the amount of slack for the given edge. The slack is defined as the
* difference between the length of the edge and its minimum length.
*/
export function slack (g, e) {
return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen
}
export default {
longestPath: longestPath,
slack: slack
}

235
node_modules/dagre-layout/lib/util.js generated vendored Normal file
View File

@@ -0,0 +1,235 @@
import _ from 'lodash'
import { Graph } from 'graphlibrary'
/*
* Adds a dummy node to the graph and return v.
*/
export function addDummyNode (g, type, attrs, name) {
let v
do {
v = _.uniqueId(name)
} while (g.hasNode(v))
attrs.dummy = type
g.setNode(v, attrs)
return v
}
/*
* Returns a new graph with only simple edges. Handles aggregation of data
* associated with multi-edges.
*/
export function simplify (g) {
const simplified = new Graph().setGraph(g.graph())
_.forEach(g.nodes(), function (v) { simplified.setNode(v, g.node(v)) })
_.forEach(g.edges(), function (e) {
const simpleLabel = simplified.edge(e.v, e.w) || { weight: 0, minlen: 1 }
const label = g.edge(e)
simplified.setEdge(e.v, e.w, {
weight: simpleLabel.weight + label.weight,
minlen: Math.max(simpleLabel.minlen, label.minlen)
})
})
return simplified
}
export function asNonCompoundGraph (g) {
const simplified = new Graph({ multigraph: g.isMultigraph() }).setGraph(g.graph())
_.forEach(g.nodes(), function (v) {
if (!g.children(v).length) {
simplified.setNode(v, g.node(v))
}
})
_.forEach(g.edges(), function (e) {
simplified.setEdge(e, g.edge(e))
})
return simplified
}
export function successorWeights (g) {
const weightMap = _.map(g.nodes(), function (v) {
const sucs = {}
_.forEach(g.outEdges(v), function (e) {
sucs[e.w] = (sucs[e.w] || 0) + g.edge(e).weight
})
return sucs
})
return _.zipObject(g.nodes(), weightMap)
}
export function predecessorWeights (g) {
const weightMap = _.map(g.nodes(), function (v) {
const preds = {}
_.forEach(g.inEdges(v), function (e) {
preds[e.v] = (preds[e.v] || 0) + g.edge(e).weight
})
return preds
})
return _.zipObject(g.nodes(), weightMap)
}
/*
* Finds where a line starting at point ({x, y}) would intersect a rectangle
* ({x, y, width, height}) if it were pointing at the rectangle's center.
*/
export function intersectRect (rect, point) {
const x = rect.x
const y = rect.y
// Rectangle intersection algorithm from:
// http://math.stackexchange.com/questions/108113/find-edge-between-two-boxes
const dx = point.x - x
const dy = point.y - y
let w = rect.width / 2
let h = rect.height / 2
if (!dx && !dy) {
throw new Error('Not possible to find intersection inside of the rectangle')
}
let sx
let sy
if (Math.abs(dy) * w > Math.abs(dx) * h) {
// Intersection is top or bottom of rect.
if (dy < 0) {
h = -h
}
sx = h * dx / dy
sy = h
} else {
// Intersection is left or right of rect.
if (dx < 0) {
w = -w
}
sx = w
sy = w * dy / dx
}
return { x: x + sx, y: y + sy }
}
/*
* Given a DAG with each node assigned "rank" and "order" properties, this
* function will produce a matrix with the ids of each node.
*/
export function buildLayerMatrix (g) {
const layering = _.map(_.range(maxRank(g) + 1), function () { return [] })
_.forEach(g.nodes(), function (v) {
const node = g.node(v)
const rank = node.rank
if (!_.isUndefined(rank)) {
layering[rank][node.order] = v
}
})
return layering
}
/*
* Adjusts the ranks for all nodes in the graph such that all nodes v have
* rank(v) >= 0 and at least one node w has rank(w) = 0.
*/
export function normalizeRanks (g) {
const min = _.min(_.map(g.nodes(), function (v) { return g.node(v).rank }))
_.forEach(g.nodes(), function (v) {
const node = g.node(v)
if (_.has(node, 'rank')) {
node.rank -= min
}
})
}
export function removeEmptyRanks (g) {
// Ranks may not start at 0, so we need to offset them
const offset = _.min(_.map(g.nodes(), function (v) { return g.node(v).rank }))
const layers = []
_.forEach(g.nodes(), function (v) {
const rank = g.node(v).rank - offset
if (!layers[rank]) {
layers[rank] = []
}
layers[rank].push(v)
})
let delta = 0
const nodeRankFactor = g.graph().nodeRankFactor
_.forEach(layers, function (vs, i) {
if (_.isUndefined(vs) && i % nodeRankFactor !== 0) {
--delta
} else if (delta) {
_.forEach(vs, function (v) { g.node(v).rank += delta })
}
})
}
export function addBorderNode (g, prefix, rank, order) {
const node = {
width: 0,
height: 0
}
if (arguments.length >= 4) {
node.rank = rank
node.order = order
}
return addDummyNode(g, 'border', node, prefix)
}
export function maxRank (g) {
return _.max(_.map(g.nodes(), function (v) {
const rank = g.node(v).rank
if (!_.isUndefined(rank)) {
return rank
}
}))
}
/*
* Partition a collection into two groups: `lhs` and `rhs`. If the supplied
* function returns true for an entry it goes into `lhs`. Otherwise it goes
* into `rhs.
*/
export function partition (collection, fn) {
const result = { lhs: [], rhs: [] }
_.forEach(collection, function (value) {
if (fn(value)) {
result.lhs.push(value)
} else {
result.rhs.push(value)
}
})
return result
}
/*
* Returns a new function that wraps `fn` with a timer. The wrapper logs the
* time it takes to execute the function.
*/
export function time (name, fn) {
const start = _.now()
try {
return fn()
} finally {
console.log(name + ' time: ' + (_.now() - start) + 'ms')
}
}
export function notime (name, fn) {
return fn()
}
export default {
addDummyNode,
simplify,
asNonCompoundGraph,
successorWeights,
predecessorWeights,
intersectRect,
buildLayerMatrix,
normalizeRanks,
removeEmptyRanks,
addBorderNode,
maxRank,
partition,
time,
notime
}

47
node_modules/dagre-layout/node_modules/lodash/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,47 @@
Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
Based on Underscore.js, copyright Jeremy Ashkenas,
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/lodash/lodash
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
Copyright and related rights for sample code are waived via CC0. Sample
code is defined as all source code displayed within the prose of the
documentation.
CC0: http://creativecommons.org/publicdomain/zero/1.0/
====
Files located in the node_modules and vendor directories are externally
maintained libraries used by this software which have their own
licenses; we recommend you read them, as their terms may differ from the
terms above.

View File

@@ -0,0 +1,39 @@
# lodash v4.17.21
The [Lodash](https://lodash.com/) library exported as [Node.js](https://nodejs.org/) modules.
## Installation
Using npm:
```shell
$ npm i -g npm
$ npm i --save lodash
```
In Node.js:
```js
// Load the full build.
var _ = require('lodash');
// Load the core build.
var _ = require('lodash/core');
// Load the FP build for immutable auto-curried iteratee-first data-last methods.
var fp = require('lodash/fp');
// Load method categories.
var array = require('lodash/array');
var object = require('lodash/fp/object');
// Cherry-pick methods for smaller browserify/rollup/webpack bundles.
var at = require('lodash/at');
var curryN = require('lodash/fp/curryN');
```
See the [package source](https://github.com/lodash/lodash/tree/4.17.21-npm) for more details.
**Note:**<br>
Install [n_](https://www.npmjs.com/package/n_) for Lodash use in the Node.js < 6 REPL.
## Support
Tested in Chrome 74-75, Firefox 66-67, IE 11, Edge 18, Safari 11-12, & Node.js 8-12.<br>
Automated [browser](https://saucelabs.com/u/lodash) & [CI](https://travis-ci.org/lodash/lodash/) test runs are available.

View File

@@ -0,0 +1,7 @@
var getNative = require('./_getNative'),
root = require('./_root');
/* Built-in method references that are verified to be native. */
var DataView = getNative(root, 'DataView');
module.exports = DataView;

32
node_modules/dagre-layout/node_modules/lodash/_Hash.js generated vendored Normal file
View File

@@ -0,0 +1,32 @@
var hashClear = require('./_hashClear'),
hashDelete = require('./_hashDelete'),
hashGet = require('./_hashGet'),
hashHas = require('./_hashHas'),
hashSet = require('./_hashSet');
/**
* Creates a hash object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Hash(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
// Add methods to `Hash`.
Hash.prototype.clear = hashClear;
Hash.prototype['delete'] = hashDelete;
Hash.prototype.get = hashGet;
Hash.prototype.has = hashHas;
Hash.prototype.set = hashSet;
module.exports = Hash;

View File

@@ -0,0 +1,28 @@
var baseCreate = require('./_baseCreate'),
baseLodash = require('./_baseLodash');
/** Used as references for the maximum length and index of an array. */
var MAX_ARRAY_LENGTH = 4294967295;
/**
* Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
*
* @private
* @constructor
* @param {*} value The value to wrap.
*/
function LazyWrapper(value) {
this.__wrapped__ = value;
this.__actions__ = [];
this.__dir__ = 1;
this.__filtered__ = false;
this.__iteratees__ = [];
this.__takeCount__ = MAX_ARRAY_LENGTH;
this.__views__ = [];
}
// Ensure `LazyWrapper` is an instance of `baseLodash`.
LazyWrapper.prototype = baseCreate(baseLodash.prototype);
LazyWrapper.prototype.constructor = LazyWrapper;
module.exports = LazyWrapper;

View File

@@ -0,0 +1,32 @@
var listCacheClear = require('./_listCacheClear'),
listCacheDelete = require('./_listCacheDelete'),
listCacheGet = require('./_listCacheGet'),
listCacheHas = require('./_listCacheHas'),
listCacheSet = require('./_listCacheSet');
/**
* Creates an list cache object.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function ListCache(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
// Add methods to `ListCache`.
ListCache.prototype.clear = listCacheClear;
ListCache.prototype['delete'] = listCacheDelete;
ListCache.prototype.get = listCacheGet;
ListCache.prototype.has = listCacheHas;
ListCache.prototype.set = listCacheSet;
module.exports = ListCache;

View File

@@ -0,0 +1,22 @@
var baseCreate = require('./_baseCreate'),
baseLodash = require('./_baseLodash');
/**
* The base constructor for creating `lodash` wrapper objects.
*
* @private
* @param {*} value The value to wrap.
* @param {boolean} [chainAll] Enable explicit method chain sequences.
*/
function LodashWrapper(value, chainAll) {
this.__wrapped__ = value;
this.__actions__ = [];
this.__chain__ = !!chainAll;
this.__index__ = 0;
this.__values__ = undefined;
}
LodashWrapper.prototype = baseCreate(baseLodash.prototype);
LodashWrapper.prototype.constructor = LodashWrapper;
module.exports = LodashWrapper;

View File

@@ -0,0 +1,7 @@
var getNative = require('./_getNative'),
root = require('./_root');
/* Built-in method references that are verified to be native. */
var Map = getNative(root, 'Map');
module.exports = Map;

View File

@@ -0,0 +1,32 @@
var mapCacheClear = require('./_mapCacheClear'),
mapCacheDelete = require('./_mapCacheDelete'),
mapCacheGet = require('./_mapCacheGet'),
mapCacheHas = require('./_mapCacheHas'),
mapCacheSet = require('./_mapCacheSet');
/**
* Creates a map cache object to store key-value pairs.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function MapCache(entries) {
var index = -1,
length = entries == null ? 0 : entries.length;
this.clear();
while (++index < length) {
var entry = entries[index];
this.set(entry[0], entry[1]);
}
}
// Add methods to `MapCache`.
MapCache.prototype.clear = mapCacheClear;
MapCache.prototype['delete'] = mapCacheDelete;
MapCache.prototype.get = mapCacheGet;
MapCache.prototype.has = mapCacheHas;
MapCache.prototype.set = mapCacheSet;
module.exports = MapCache;

View File

@@ -0,0 +1,7 @@
var getNative = require('./_getNative'),
root = require('./_root');
/* Built-in method references that are verified to be native. */
var Promise = getNative(root, 'Promise');
module.exports = Promise;

View File

@@ -0,0 +1,7 @@
var getNative = require('./_getNative'),
root = require('./_root');
/* Built-in method references that are verified to be native. */
var Set = getNative(root, 'Set');
module.exports = Set;

View File

@@ -0,0 +1,27 @@
var MapCache = require('./_MapCache'),
setCacheAdd = require('./_setCacheAdd'),
setCacheHas = require('./_setCacheHas');
/**
*
* Creates an array cache object to store unique values.
*
* @private
* @constructor
* @param {Array} [values] The values to cache.
*/
function SetCache(values) {
var index = -1,
length = values == null ? 0 : values.length;
this.__data__ = new MapCache;
while (++index < length) {
this.add(values[index]);
}
}
// Add methods to `SetCache`.
SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
SetCache.prototype.has = setCacheHas;
module.exports = SetCache;

View File

@@ -0,0 +1,27 @@
var ListCache = require('./_ListCache'),
stackClear = require('./_stackClear'),
stackDelete = require('./_stackDelete'),
stackGet = require('./_stackGet'),
stackHas = require('./_stackHas'),
stackSet = require('./_stackSet');
/**
* Creates a stack cache object to store key-value pairs.
*
* @private
* @constructor
* @param {Array} [entries] The key-value pairs to cache.
*/
function Stack(entries) {
var data = this.__data__ = new ListCache(entries);
this.size = data.size;
}
// Add methods to `Stack`.
Stack.prototype.clear = stackClear;
Stack.prototype['delete'] = stackDelete;
Stack.prototype.get = stackGet;
Stack.prototype.has = stackHas;
Stack.prototype.set = stackSet;
module.exports = Stack;

View File

@@ -0,0 +1,6 @@
var root = require('./_root');
/** Built-in value references. */
var Symbol = root.Symbol;
module.exports = Symbol;

View File

@@ -0,0 +1,6 @@
var root = require('./_root');
/** Built-in value references. */
var Uint8Array = root.Uint8Array;
module.exports = Uint8Array;

View File

@@ -0,0 +1,7 @@
var getNative = require('./_getNative'),
root = require('./_root');
/* Built-in method references that are verified to be native. */
var WeakMap = getNative(root, 'WeakMap');
module.exports = WeakMap;

View File

@@ -0,0 +1,21 @@
/**
* A faster alternative to `Function#apply`, this function invokes `func`
* with the `this` binding of `thisArg` and the arguments of `args`.
*
* @private
* @param {Function} func The function to invoke.
* @param {*} thisArg The `this` binding of `func`.
* @param {Array} args The arguments to invoke `func` with.
* @returns {*} Returns the result of `func`.
*/
function apply(func, thisArg, args) {
switch (args.length) {
case 0: return func.call(thisArg);
case 1: return func.call(thisArg, args[0]);
case 2: return func.call(thisArg, args[0], args[1]);
case 3: return func.call(thisArg, args[0], args[1], args[2]);
}
return func.apply(thisArg, args);
}
module.exports = apply;

View File

@@ -0,0 +1,22 @@
/**
* A specialized version of `baseAggregator` for arrays.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} setter The function to set `accumulator` values.
* @param {Function} iteratee The iteratee to transform keys.
* @param {Object} accumulator The initial aggregated object.
* @returns {Function} Returns `accumulator`.
*/
function arrayAggregator(array, setter, iteratee, accumulator) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
var value = array[index];
setter(accumulator, value, iteratee(value), array);
}
return accumulator;
}
module.exports = arrayAggregator;

View File

@@ -0,0 +1,22 @@
/**
* A specialized version of `_.forEach` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns `array`.
*/
function arrayEach(array, iteratee) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
if (iteratee(array[index], index, array) === false) {
break;
}
}
return array;
}
module.exports = arrayEach;

View File

@@ -0,0 +1,21 @@
/**
* A specialized version of `_.forEachRight` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns `array`.
*/
function arrayEachRight(array, iteratee) {
var length = array == null ? 0 : array.length;
while (length--) {
if (iteratee(array[length], length, array) === false) {
break;
}
}
return array;
}
module.exports = arrayEachRight;

View File

@@ -0,0 +1,23 @@
/**
* A specialized version of `_.every` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {boolean} Returns `true` if all elements pass the predicate check,
* else `false`.
*/
function arrayEvery(array, predicate) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
if (!predicate(array[index], index, array)) {
return false;
}
}
return true;
}
module.exports = arrayEvery;

View File

@@ -0,0 +1,25 @@
/**
* A specialized version of `_.filter` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {Array} Returns the new filtered array.
*/
function arrayFilter(array, predicate) {
var index = -1,
length = array == null ? 0 : array.length,
resIndex = 0,
result = [];
while (++index < length) {
var value = array[index];
if (predicate(value, index, array)) {
result[resIndex++] = value;
}
}
return result;
}
module.exports = arrayFilter;

View File

@@ -0,0 +1,17 @@
var baseIndexOf = require('./_baseIndexOf');
/**
* A specialized version of `_.includes` for arrays without support for
* specifying an index to search from.
*
* @private
* @param {Array} [array] The array to inspect.
* @param {*} target The value to search for.
* @returns {boolean} Returns `true` if `target` is found, else `false`.
*/
function arrayIncludes(array, value) {
var length = array == null ? 0 : array.length;
return !!length && baseIndexOf(array, value, 0) > -1;
}
module.exports = arrayIncludes;

View File

@@ -0,0 +1,22 @@
/**
* This function is like `arrayIncludes` except that it accepts a comparator.
*
* @private
* @param {Array} [array] The array to inspect.
* @param {*} target The value to search for.
* @param {Function} comparator The comparator invoked per element.
* @returns {boolean} Returns `true` if `target` is found, else `false`.
*/
function arrayIncludesWith(array, value, comparator) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
if (comparator(value, array[index])) {
return true;
}
}
return false;
}
module.exports = arrayIncludesWith;

View File

@@ -0,0 +1,49 @@
var baseTimes = require('./_baseTimes'),
isArguments = require('./isArguments'),
isArray = require('./isArray'),
isBuffer = require('./isBuffer'),
isIndex = require('./_isIndex'),
isTypedArray = require('./isTypedArray');
/** Used for built-in method references. */
var objectProto = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Creates an array of the enumerable property names of the array-like `value`.
*
* @private
* @param {*} value The value to query.
* @param {boolean} inherited Specify returning inherited property names.
* @returns {Array} Returns the array of property names.
*/
function arrayLikeKeys(value, inherited) {
var isArr = isArray(value),
isArg = !isArr && isArguments(value),
isBuff = !isArr && !isArg && isBuffer(value),
isType = !isArr && !isArg && !isBuff && isTypedArray(value),
skipIndexes = isArr || isArg || isBuff || isType,
result = skipIndexes ? baseTimes(value.length, String) : [],
length = result.length;
for (var key in value) {
if ((inherited || hasOwnProperty.call(value, key)) &&
!(skipIndexes && (
// Safari 9 has enumerable `arguments.length` in strict mode.
key == 'length' ||
// Node.js 0.10 has enumerable non-index properties on buffers.
(isBuff && (key == 'offset' || key == 'parent')) ||
// PhantomJS 2 has enumerable non-index properties on typed arrays.
(isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
// Skip index properties.
isIndex(key, length)
))) {
result.push(key);
}
}
return result;
}
module.exports = arrayLikeKeys;

View File

@@ -0,0 +1,21 @@
/**
* A specialized version of `_.map` for arrays without support for iteratee
* shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array} Returns the new mapped array.
*/
function arrayMap(array, iteratee) {
var index = -1,
length = array == null ? 0 : array.length,
result = Array(length);
while (++index < length) {
result[index] = iteratee(array[index], index, array);
}
return result;
}
module.exports = arrayMap;

View File

@@ -0,0 +1,20 @@
/**
* Appends the elements of `values` to `array`.
*
* @private
* @param {Array} array The array to modify.
* @param {Array} values The values to append.
* @returns {Array} Returns `array`.
*/
function arrayPush(array, values) {
var index = -1,
length = values.length,
offset = array.length;
while (++index < length) {
array[offset + index] = values[index];
}
return array;
}
module.exports = arrayPush;

View File

@@ -0,0 +1,26 @@
/**
* A specialized version of `_.reduce` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @param {*} [accumulator] The initial value.
* @param {boolean} [initAccum] Specify using the first element of `array` as
* the initial value.
* @returns {*} Returns the accumulated value.
*/
function arrayReduce(array, iteratee, accumulator, initAccum) {
var index = -1,
length = array == null ? 0 : array.length;
if (initAccum && length) {
accumulator = array[++index];
}
while (++index < length) {
accumulator = iteratee(accumulator, array[index], index, array);
}
return accumulator;
}
module.exports = arrayReduce;

View File

@@ -0,0 +1,24 @@
/**
* A specialized version of `_.reduceRight` for arrays without support for
* iteratee shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @param {*} [accumulator] The initial value.
* @param {boolean} [initAccum] Specify using the last element of `array` as
* the initial value.
* @returns {*} Returns the accumulated value.
*/
function arrayReduceRight(array, iteratee, accumulator, initAccum) {
var length = array == null ? 0 : array.length;
if (initAccum && length) {
accumulator = array[--length];
}
while (length--) {
accumulator = iteratee(accumulator, array[length], length, array);
}
return accumulator;
}
module.exports = arrayReduceRight;

View File

@@ -0,0 +1,15 @@
var baseRandom = require('./_baseRandom');
/**
* A specialized version of `_.sample` for arrays.
*
* @private
* @param {Array} array The array to sample.
* @returns {*} Returns the random element.
*/
function arraySample(array) {
var length = array.length;
return length ? array[baseRandom(0, length - 1)] : undefined;
}
module.exports = arraySample;

View File

@@ -0,0 +1,17 @@
var baseClamp = require('./_baseClamp'),
copyArray = require('./_copyArray'),
shuffleSelf = require('./_shuffleSelf');
/**
* A specialized version of `_.sampleSize` for arrays.
*
* @private
* @param {Array} array The array to sample.
* @param {number} n The number of elements to sample.
* @returns {Array} Returns the random elements.
*/
function arraySampleSize(array, n) {
return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
}
module.exports = arraySampleSize;

View File

@@ -0,0 +1,15 @@
var copyArray = require('./_copyArray'),
shuffleSelf = require('./_shuffleSelf');
/**
* A specialized version of `_.shuffle` for arrays.
*
* @private
* @param {Array} array The array to shuffle.
* @returns {Array} Returns the new shuffled array.
*/
function arrayShuffle(array) {
return shuffleSelf(copyArray(array));
}
module.exports = arrayShuffle;

View File

@@ -0,0 +1,23 @@
/**
* A specialized version of `_.some` for arrays without support for iteratee
* shorthands.
*
* @private
* @param {Array} [array] The array to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {boolean} Returns `true` if any element passes the predicate check,
* else `false`.
*/
function arraySome(array, predicate) {
var index = -1,
length = array == null ? 0 : array.length;
while (++index < length) {
if (predicate(array[index], index, array)) {
return true;
}
}
return false;
}
module.exports = arraySome;

View File

@@ -0,0 +1,12 @@
var baseProperty = require('./_baseProperty');
/**
* Gets the size of an ASCII `string`.
*
* @private
* @param {string} string The string inspect.
* @returns {number} Returns the string size.
*/
var asciiSize = baseProperty('length');
module.exports = asciiSize;

View File

@@ -0,0 +1,12 @@
/**
* Converts an ASCII `string` to an array.
*
* @private
* @param {string} string The string to convert.
* @returns {Array} Returns the converted array.
*/
function asciiToArray(string) {
return string.split('');
}
module.exports = asciiToArray;

View File

@@ -0,0 +1,15 @@
/** Used to match words composed of alphanumeric characters. */
var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
/**
* Splits an ASCII `string` into an array of its words.
*
* @private
* @param {string} The string to inspect.
* @returns {Array} Returns the words of `string`.
*/
function asciiWords(string) {
return string.match(reAsciiWord) || [];
}
module.exports = asciiWords;

View File

@@ -0,0 +1,20 @@
var baseAssignValue = require('./_baseAssignValue'),
eq = require('./eq');
/**
* This function is like `assignValue` except that it doesn't assign
* `undefined` values.
*
* @private
* @param {Object} object The object to modify.
* @param {string} key The key of the property to assign.
* @param {*} value The value to assign.
*/
function assignMergeValue(object, key, value) {
if ((value !== undefined && !eq(object[key], value)) ||
(value === undefined && !(key in object))) {
baseAssignValue(object, key, value);
}
}
module.exports = assignMergeValue;

View File

@@ -0,0 +1,28 @@
var baseAssignValue = require('./_baseAssignValue'),
eq = require('./eq');
/** Used for built-in method references. */
var objectProto = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Assigns `value` to `key` of `object` if the existing value is not equivalent
* using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
* for equality comparisons.
*
* @private
* @param {Object} object The object to modify.
* @param {string} key The key of the property to assign.
* @param {*} value The value to assign.
*/
function assignValue(object, key, value) {
var objValue = object[key];
if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
(value === undefined && !(key in object))) {
baseAssignValue(object, key, value);
}
}
module.exports = assignValue;

View File

@@ -0,0 +1,21 @@
var eq = require('./eq');
/**
* Gets the index at which the `key` is found in `array` of key-value pairs.
*
* @private
* @param {Array} array The array to inspect.
* @param {*} key The key to search for.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function assocIndexOf(array, key) {
var length = array.length;
while (length--) {
if (eq(array[length][0], key)) {
return length;
}
}
return -1;
}
module.exports = assocIndexOf;

View File

@@ -0,0 +1,21 @@
var baseEach = require('./_baseEach');
/**
* Aggregates elements of `collection` on `accumulator` with keys transformed
* by `iteratee` and values set by `setter`.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} setter The function to set `accumulator` values.
* @param {Function} iteratee The iteratee to transform keys.
* @param {Object} accumulator The initial aggregated object.
* @returns {Function} Returns `accumulator`.
*/
function baseAggregator(collection, setter, iteratee, accumulator) {
baseEach(collection, function(value, key, collection) {
setter(accumulator, value, iteratee(value), collection);
});
return accumulator;
}
module.exports = baseAggregator;

View File

@@ -0,0 +1,17 @@
var copyObject = require('./_copyObject'),
keys = require('./keys');
/**
* The base implementation of `_.assign` without support for multiple sources
* or `customizer` functions.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @returns {Object} Returns `object`.
*/
function baseAssign(object, source) {
return object && copyObject(source, keys(source), object);
}
module.exports = baseAssign;

View File

@@ -0,0 +1,17 @@
var copyObject = require('./_copyObject'),
keysIn = require('./keysIn');
/**
* The base implementation of `_.assignIn` without support for multiple sources
* or `customizer` functions.
*
* @private
* @param {Object} object The destination object.
* @param {Object} source The source object.
* @returns {Object} Returns `object`.
*/
function baseAssignIn(object, source) {
return object && copyObject(source, keysIn(source), object);
}
module.exports = baseAssignIn;

View File

@@ -0,0 +1,25 @@
var defineProperty = require('./_defineProperty');
/**
* The base implementation of `assignValue` and `assignMergeValue` without
* value checks.
*
* @private
* @param {Object} object The object to modify.
* @param {string} key The key of the property to assign.
* @param {*} value The value to assign.
*/
function baseAssignValue(object, key, value) {
if (key == '__proto__' && defineProperty) {
defineProperty(object, key, {
'configurable': true,
'enumerable': true,
'value': value,
'writable': true
});
} else {
object[key] = value;
}
}
module.exports = baseAssignValue;

View File

@@ -0,0 +1,23 @@
var get = require('./get');
/**
* The base implementation of `_.at` without support for individual paths.
*
* @private
* @param {Object} object The object to iterate over.
* @param {string[]} paths The property paths to pick.
* @returns {Array} Returns the picked elements.
*/
function baseAt(object, paths) {
var index = -1,
length = paths.length,
result = Array(length),
skip = object == null;
while (++index < length) {
result[index] = skip ? undefined : get(object, paths[index]);
}
return result;
}
module.exports = baseAt;

View File

@@ -0,0 +1,22 @@
/**
* The base implementation of `_.clamp` which doesn't coerce arguments.
*
* @private
* @param {number} number The number to clamp.
* @param {number} [lower] The lower bound.
* @param {number} upper The upper bound.
* @returns {number} Returns the clamped number.
*/
function baseClamp(number, lower, upper) {
if (number === number) {
if (upper !== undefined) {
number = number <= upper ? number : upper;
}
if (lower !== undefined) {
number = number >= lower ? number : lower;
}
}
return number;
}
module.exports = baseClamp;

View File

@@ -0,0 +1,166 @@
var Stack = require('./_Stack'),
arrayEach = require('./_arrayEach'),
assignValue = require('./_assignValue'),
baseAssign = require('./_baseAssign'),
baseAssignIn = require('./_baseAssignIn'),
cloneBuffer = require('./_cloneBuffer'),
copyArray = require('./_copyArray'),
copySymbols = require('./_copySymbols'),
copySymbolsIn = require('./_copySymbolsIn'),
getAllKeys = require('./_getAllKeys'),
getAllKeysIn = require('./_getAllKeysIn'),
getTag = require('./_getTag'),
initCloneArray = require('./_initCloneArray'),
initCloneByTag = require('./_initCloneByTag'),
initCloneObject = require('./_initCloneObject'),
isArray = require('./isArray'),
isBuffer = require('./isBuffer'),
isMap = require('./isMap'),
isObject = require('./isObject'),
isSet = require('./isSet'),
keys = require('./keys'),
keysIn = require('./keysIn');
/** Used to compose bitmasks for cloning. */
var CLONE_DEEP_FLAG = 1,
CLONE_FLAT_FLAG = 2,
CLONE_SYMBOLS_FLAG = 4;
/** `Object#toString` result references. */
var argsTag = '[object Arguments]',
arrayTag = '[object Array]',
boolTag = '[object Boolean]',
dateTag = '[object Date]',
errorTag = '[object Error]',
funcTag = '[object Function]',
genTag = '[object GeneratorFunction]',
mapTag = '[object Map]',
numberTag = '[object Number]',
objectTag = '[object Object]',
regexpTag = '[object RegExp]',
setTag = '[object Set]',
stringTag = '[object String]',
symbolTag = '[object Symbol]',
weakMapTag = '[object WeakMap]';
var arrayBufferTag = '[object ArrayBuffer]',
dataViewTag = '[object DataView]',
float32Tag = '[object Float32Array]',
float64Tag = '[object Float64Array]',
int8Tag = '[object Int8Array]',
int16Tag = '[object Int16Array]',
int32Tag = '[object Int32Array]',
uint8Tag = '[object Uint8Array]',
uint8ClampedTag = '[object Uint8ClampedArray]',
uint16Tag = '[object Uint16Array]',
uint32Tag = '[object Uint32Array]';
/** Used to identify `toStringTag` values supported by `_.clone`. */
var cloneableTags = {};
cloneableTags[argsTag] = cloneableTags[arrayTag] =
cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
cloneableTags[boolTag] = cloneableTags[dateTag] =
cloneableTags[float32Tag] = cloneableTags[float64Tag] =
cloneableTags[int8Tag] = cloneableTags[int16Tag] =
cloneableTags[int32Tag] = cloneableTags[mapTag] =
cloneableTags[numberTag] = cloneableTags[objectTag] =
cloneableTags[regexpTag] = cloneableTags[setTag] =
cloneableTags[stringTag] = cloneableTags[symbolTag] =
cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
cloneableTags[errorTag] = cloneableTags[funcTag] =
cloneableTags[weakMapTag] = false;
/**
* The base implementation of `_.clone` and `_.cloneDeep` which tracks
* traversed objects.
*
* @private
* @param {*} value The value to clone.
* @param {boolean} bitmask The bitmask flags.
* 1 - Deep clone
* 2 - Flatten inherited properties
* 4 - Clone symbols
* @param {Function} [customizer] The function to customize cloning.
* @param {string} [key] The key of `value`.
* @param {Object} [object] The parent object of `value`.
* @param {Object} [stack] Tracks traversed objects and their clone counterparts.
* @returns {*} Returns the cloned value.
*/
function baseClone(value, bitmask, customizer, key, object, stack) {
var result,
isDeep = bitmask & CLONE_DEEP_FLAG,
isFlat = bitmask & CLONE_FLAT_FLAG,
isFull = bitmask & CLONE_SYMBOLS_FLAG;
if (customizer) {
result = object ? customizer(value, key, object, stack) : customizer(value);
}
if (result !== undefined) {
return result;
}
if (!isObject(value)) {
return value;
}
var isArr = isArray(value);
if (isArr) {
result = initCloneArray(value);
if (!isDeep) {
return copyArray(value, result);
}
} else {
var tag = getTag(value),
isFunc = tag == funcTag || tag == genTag;
if (isBuffer(value)) {
return cloneBuffer(value, isDeep);
}
if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
result = (isFlat || isFunc) ? {} : initCloneObject(value);
if (!isDeep) {
return isFlat
? copySymbolsIn(value, baseAssignIn(result, value))
: copySymbols(value, baseAssign(result, value));
}
} else {
if (!cloneableTags[tag]) {
return object ? value : {};
}
result = initCloneByTag(value, tag, isDeep);
}
}
// Check for circular references and return its corresponding clone.
stack || (stack = new Stack);
var stacked = stack.get(value);
if (stacked) {
return stacked;
}
stack.set(value, result);
if (isSet(value)) {
value.forEach(function(subValue) {
result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
});
} else if (isMap(value)) {
value.forEach(function(subValue, key) {
result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
});
}
var keysFunc = isFull
? (isFlat ? getAllKeysIn : getAllKeys)
: (isFlat ? keysIn : keys);
var props = isArr ? undefined : keysFunc(value);
arrayEach(props || value, function(subValue, key) {
if (props) {
key = subValue;
subValue = value[key];
}
// Recursively populate clone (susceptible to call stack limits).
assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
});
return result;
}
module.exports = baseClone;

View File

@@ -0,0 +1,18 @@
var baseConformsTo = require('./_baseConformsTo'),
keys = require('./keys');
/**
* The base implementation of `_.conforms` which doesn't clone `source`.
*
* @private
* @param {Object} source The object of property predicates to conform to.
* @returns {Function} Returns the new spec function.
*/
function baseConforms(source) {
var props = keys(source);
return function(object) {
return baseConformsTo(object, source, props);
};
}
module.exports = baseConforms;

View File

@@ -0,0 +1,27 @@
/**
* The base implementation of `_.conformsTo` which accepts `props` to check.
*
* @private
* @param {Object} object The object to inspect.
* @param {Object} source The object of property predicates to conform to.
* @returns {boolean} Returns `true` if `object` conforms, else `false`.
*/
function baseConformsTo(object, source, props) {
var length = props.length;
if (object == null) {
return !length;
}
object = Object(object);
while (length--) {
var key = props[length],
predicate = source[key],
value = object[key];
if ((value === undefined && !(key in object)) || !predicate(value)) {
return false;
}
}
return true;
}
module.exports = baseConformsTo;

View File

@@ -0,0 +1,30 @@
var isObject = require('./isObject');
/** Built-in value references. */
var objectCreate = Object.create;
/**
* The base implementation of `_.create` without support for assigning
* properties to the created object.
*
* @private
* @param {Object} proto The object to inherit from.
* @returns {Object} Returns the new object.
*/
var baseCreate = (function() {
function object() {}
return function(proto) {
if (!isObject(proto)) {
return {};
}
if (objectCreate) {
return objectCreate(proto);
}
object.prototype = proto;
var result = new object;
object.prototype = undefined;
return result;
};
}());
module.exports = baseCreate;

View File

@@ -0,0 +1,21 @@
/** Error message constants. */
var FUNC_ERROR_TEXT = 'Expected a function';
/**
* The base implementation of `_.delay` and `_.defer` which accepts `args`
* to provide to `func`.
*
* @private
* @param {Function} func The function to delay.
* @param {number} wait The number of milliseconds to delay invocation.
* @param {Array} args The arguments to provide to `func`.
* @returns {number|Object} Returns the timer id or timeout object.
*/
function baseDelay(func, wait, args) {
if (typeof func != 'function') {
throw new TypeError(FUNC_ERROR_TEXT);
}
return setTimeout(function() { func.apply(undefined, args); }, wait);
}
module.exports = baseDelay;

View File

@@ -0,0 +1,67 @@
var SetCache = require('./_SetCache'),
arrayIncludes = require('./_arrayIncludes'),
arrayIncludesWith = require('./_arrayIncludesWith'),
arrayMap = require('./_arrayMap'),
baseUnary = require('./_baseUnary'),
cacheHas = require('./_cacheHas');
/** Used as the size to enable large array optimizations. */
var LARGE_ARRAY_SIZE = 200;
/**
* The base implementation of methods like `_.difference` without support
* for excluding multiple arrays or iteratee shorthands.
*
* @private
* @param {Array} array The array to inspect.
* @param {Array} values The values to exclude.
* @param {Function} [iteratee] The iteratee invoked per element.
* @param {Function} [comparator] The comparator invoked per element.
* @returns {Array} Returns the new array of filtered values.
*/
function baseDifference(array, values, iteratee, comparator) {
var index = -1,
includes = arrayIncludes,
isCommon = true,
length = array.length,
result = [],
valuesLength = values.length;
if (!length) {
return result;
}
if (iteratee) {
values = arrayMap(values, baseUnary(iteratee));
}
if (comparator) {
includes = arrayIncludesWith;
isCommon = false;
}
else if (values.length >= LARGE_ARRAY_SIZE) {
includes = cacheHas;
isCommon = false;
values = new SetCache(values);
}
outer:
while (++index < length) {
var value = array[index],
computed = iteratee == null ? value : iteratee(value);
value = (comparator || value !== 0) ? value : 0;
if (isCommon && computed === computed) {
var valuesIndex = valuesLength;
while (valuesIndex--) {
if (values[valuesIndex] === computed) {
continue outer;
}
}
result.push(value);
}
else if (!includes(values, computed, comparator)) {
result.push(value);
}
}
return result;
}
module.exports = baseDifference;

View File

@@ -0,0 +1,14 @@
var baseForOwn = require('./_baseForOwn'),
createBaseEach = require('./_createBaseEach');
/**
* The base implementation of `_.forEach` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array|Object} Returns `collection`.
*/
var baseEach = createBaseEach(baseForOwn);
module.exports = baseEach;

View File

@@ -0,0 +1,14 @@
var baseForOwnRight = require('./_baseForOwnRight'),
createBaseEach = require('./_createBaseEach');
/**
* The base implementation of `_.forEachRight` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Array|Object} Returns `collection`.
*/
var baseEachRight = createBaseEach(baseForOwnRight, true);
module.exports = baseEachRight;

View File

@@ -0,0 +1,21 @@
var baseEach = require('./_baseEach');
/**
* The base implementation of `_.every` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {boolean} Returns `true` if all elements pass the predicate check,
* else `false`
*/
function baseEvery(collection, predicate) {
var result = true;
baseEach(collection, function(value, index, collection) {
result = !!predicate(value, index, collection);
return result;
});
return result;
}
module.exports = baseEvery;

View File

@@ -0,0 +1,32 @@
var isSymbol = require('./isSymbol');
/**
* The base implementation of methods like `_.max` and `_.min` which accepts a
* `comparator` to determine the extremum value.
*
* @private
* @param {Array} array The array to iterate over.
* @param {Function} iteratee The iteratee invoked per iteration.
* @param {Function} comparator The comparator used to compare values.
* @returns {*} Returns the extremum value.
*/
function baseExtremum(array, iteratee, comparator) {
var index = -1,
length = array.length;
while (++index < length) {
var value = array[index],
current = iteratee(value);
if (current != null && (computed === undefined
? (current === current && !isSymbol(current))
: comparator(current, computed)
)) {
var computed = current,
result = value;
}
}
return result;
}
module.exports = baseExtremum;

View File

@@ -0,0 +1,32 @@
var toInteger = require('./toInteger'),
toLength = require('./toLength');
/**
* The base implementation of `_.fill` without an iteratee call guard.
*
* @private
* @param {Array} array The array to fill.
* @param {*} value The value to fill `array` with.
* @param {number} [start=0] The start position.
* @param {number} [end=array.length] The end position.
* @returns {Array} Returns `array`.
*/
function baseFill(array, value, start, end) {
var length = array.length;
start = toInteger(start);
if (start < 0) {
start = -start > length ? 0 : (length + start);
}
end = (end === undefined || end > length) ? length : toInteger(end);
if (end < 0) {
end += length;
}
end = start > end ? 0 : toLength(end);
while (start < end) {
array[start++] = value;
}
return array;
}
module.exports = baseFill;

View File

@@ -0,0 +1,21 @@
var baseEach = require('./_baseEach');
/**
* The base implementation of `_.filter` without support for iteratee shorthands.
*
* @private
* @param {Array|Object} collection The collection to iterate over.
* @param {Function} predicate The function invoked per iteration.
* @returns {Array} Returns the new filtered array.
*/
function baseFilter(collection, predicate) {
var result = [];
baseEach(collection, function(value, index, collection) {
if (predicate(value, index, collection)) {
result.push(value);
}
});
return result;
}
module.exports = baseFilter;

View File

@@ -0,0 +1,24 @@
/**
* The base implementation of `_.findIndex` and `_.findLastIndex` without
* support for iteratee shorthands.
*
* @private
* @param {Array} array The array to inspect.
* @param {Function} predicate The function invoked per iteration.
* @param {number} fromIndex The index to search from.
* @param {boolean} [fromRight] Specify iterating from right to left.
* @returns {number} Returns the index of the matched value, else `-1`.
*/
function baseFindIndex(array, predicate, fromIndex, fromRight) {
var length = array.length,
index = fromIndex + (fromRight ? 1 : -1);
while ((fromRight ? index-- : ++index < length)) {
if (predicate(array[index], index, array)) {
return index;
}
}
return -1;
}
module.exports = baseFindIndex;

View File

@@ -0,0 +1,23 @@
/**
* The base implementation of methods like `_.findKey` and `_.findLastKey`,
* without support for iteratee shorthands, which iterates over `collection`
* using `eachFunc`.
*
* @private
* @param {Array|Object} collection The collection to inspect.
* @param {Function} predicate The function invoked per iteration.
* @param {Function} eachFunc The function to iterate over `collection`.
* @returns {*} Returns the found element or its key, else `undefined`.
*/
function baseFindKey(collection, predicate, eachFunc) {
var result;
eachFunc(collection, function(value, key, collection) {
if (predicate(value, key, collection)) {
result = key;
return false;
}
});
return result;
}
module.exports = baseFindKey;

View File

@@ -0,0 +1,38 @@
var arrayPush = require('./_arrayPush'),
isFlattenable = require('./_isFlattenable');
/**
* The base implementation of `_.flatten` with support for restricting flattening.
*
* @private
* @param {Array} array The array to flatten.
* @param {number} depth The maximum recursion depth.
* @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
* @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
* @param {Array} [result=[]] The initial result value.
* @returns {Array} Returns the new flattened array.
*/
function baseFlatten(array, depth, predicate, isStrict, result) {
var index = -1,
length = array.length;
predicate || (predicate = isFlattenable);
result || (result = []);
while (++index < length) {
var value = array[index];
if (depth > 0 && predicate(value)) {
if (depth > 1) {
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result);
} else {
arrayPush(result, value);
}
} else if (!isStrict) {
result[result.length] = value;
}
}
return result;
}
module.exports = baseFlatten;

View File

@@ -0,0 +1,16 @@
var createBaseFor = require('./_createBaseFor');
/**
* The base implementation of `baseForOwn` which iterates over `object`
* properties returned by `keysFunc` and invokes `iteratee` for each property.
* Iteratee functions may exit iteration early by explicitly returning `false`.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @param {Function} keysFunc The function to get the keys of `object`.
* @returns {Object} Returns `object`.
*/
var baseFor = createBaseFor();
module.exports = baseFor;

View File

@@ -0,0 +1,16 @@
var baseFor = require('./_baseFor'),
keys = require('./keys');
/**
* The base implementation of `_.forOwn` without support for iteratee shorthands.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Object} Returns `object`.
*/
function baseForOwn(object, iteratee) {
return object && baseFor(object, iteratee, keys);
}
module.exports = baseForOwn;

View File

@@ -0,0 +1,16 @@
var baseForRight = require('./_baseForRight'),
keys = require('./keys');
/**
* The base implementation of `_.forOwnRight` without support for iteratee shorthands.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @returns {Object} Returns `object`.
*/
function baseForOwnRight(object, iteratee) {
return object && baseForRight(object, iteratee, keys);
}
module.exports = baseForOwnRight;

View File

@@ -0,0 +1,15 @@
var createBaseFor = require('./_createBaseFor');
/**
* This function is like `baseFor` except that it iterates over properties
* in the opposite order.
*
* @private
* @param {Object} object The object to iterate over.
* @param {Function} iteratee The function invoked per iteration.
* @param {Function} keysFunc The function to get the keys of `object`.
* @returns {Object} Returns `object`.
*/
var baseForRight = createBaseFor(true);
module.exports = baseForRight;

View File

@@ -0,0 +1,19 @@
var arrayFilter = require('./_arrayFilter'),
isFunction = require('./isFunction');
/**
* The base implementation of `_.functions` which creates an array of
* `object` function property names filtered from `props`.
*
* @private
* @param {Object} object The object to inspect.
* @param {Array} props The property names to filter.
* @returns {Array} Returns the function names.
*/
function baseFunctions(object, props) {
return arrayFilter(props, function(key) {
return isFunction(object[key]);
});
}
module.exports = baseFunctions;

View File

@@ -0,0 +1,24 @@
var castPath = require('./_castPath'),
toKey = require('./_toKey');
/**
* The base implementation of `_.get` without support for default values.
*
* @private
* @param {Object} object The object to query.
* @param {Array|string} path The path of the property to get.
* @returns {*} Returns the resolved value.
*/
function baseGet(object, path) {
path = castPath(path, object);
var index = 0,
length = path.length;
while (object != null && index < length) {
object = object[toKey(path[index++])];
}
return (index && index == length) ? object : undefined;
}
module.exports = baseGet;

View File

@@ -0,0 +1,20 @@
var arrayPush = require('./_arrayPush'),
isArray = require('./isArray');
/**
* The base implementation of `getAllKeys` and `getAllKeysIn` which uses
* `keysFunc` and `symbolsFunc` to get the enumerable property names and
* symbols of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {Function} keysFunc The function to get the keys of `object`.
* @param {Function} symbolsFunc The function to get the symbols of `object`.
* @returns {Array} Returns the array of property names and symbols.
*/
function baseGetAllKeys(object, keysFunc, symbolsFunc) {
var result = keysFunc(object);
return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
}
module.exports = baseGetAllKeys;

Some files were not shown because too many files have changed in this diff Show More