![Create React App Officially Deprecated Amid React 19 Compatibility Issues](https://cdn.sanity.io/images/cgdhsj6q/production/04fa08cf844d798abc0e1a6391c129363cc7e2ab-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Create React App Officially Deprecated Amid React 19 Compatibility Issues
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
We had trouble finding a library for graph data structure which addresses our requirements. The principal need and motivator for now is model-based testing (MBT): a reactive system is modelled as a state-machine, which itself can be modelled as a multidigraph, or quiver. We could not find libraries which can handle such constructs. To generate input sequences for model testing, we need to examine the associated graph in a certain number of ways. This library aims at gathering such ways.
As such it is not and does not intend to be a all-purpose graph manipulation library. It just has what we need for model-based testing. Typically, the model coverage criteria used in MBT for transition-based models are :
We currently offer :
This was chosen for pragmatic reasons. From this included algorithm, it is possible to implement most of the above-mentioned coverage criteria.
/**
* @typedef {Object} Edge Edge must be an object (we use referential equality so this is to avoid surprises with
* equality of native types)
*/
/**
* @typedef {Array<Edge>} EdgePath
*/
/**
* @typedef {Object} Vertex Vertices must be an object (we use referential equality so this is to avoid surprises with
* equality of native types)
*/
/**
* @typedef {Object} EdgeADT
* @property {function(Edge) : Vertex} getEdgeTarget
* @property {function(Edge) : Vertex} getEdgeOrigin
* @property {function(Vertex, Vertex) : Edge} constructEdge
*/
/**
* @typedef {Object} Graph
* @property {function (Vertex) : Array<Edge>} outgoingEdges
* @property {function (Vertex) : Array<Edge>} incomingEdges
* @property {function (Vertex) : Array<Vertex>} getNeighbours
* @property {function (Vertex) : Array<Vertex>} vertices
* @property {function (Vertex) : Array<Vertex>} edges
* @property {function (Vertex) : Array<Vertex>} settings
* @property {function (Edge) : Vertex} getEdgeOrigin
* @property {function (Edge) : Vertex} getEdgeTarget
* @property {function(Vertex, Vertex) : Edge} constructEdge
* @property {function (Vertex) : ()} showVertex
* @property {function (Vertex) : ()} showEdge
* @property {function () : ()} clear free any resources that was used
*/
/**
* @typedef {Object} FindPathSettings
* @property {Number} [maxNumberOfTraversals=1] a number greater or equal to 0. Set to 1 by default
* @property {String} [strategy='BFS'] search strategy : depth-first or breadth-first (default)
*/
/**
* @typedef {() => Store<P>} StoreFactory Store constructor
* @constructor
*/
/**
* @typedef {Object} StoreInterface
* @property {Store<P> | StoreFactory} empty empty store or constructor for an empty store
* @property {function (Array<P>, Store<P>) : Store<P>} add adds a list of values into a store
* @property {function (Store<P>) : {popped, newStore: Store<P>}} takeAndRemoveOne empty store. removes one value
* from the store and returns that value and the new store without that value
* @property {function (Store<P>): Boolean} isEmpty predicate which returns true iff the store is empty
* @template P
*/
/**
* @typedef {Map} GraphTraversalState `graphTraversalState` is shared state between search, result accumulation and
* visiting functions. As such it must be used carefully. Ideally it is not necessary. If it is necessary then only
* one function should modify it while the others read from it. That eliminates the need to think about order of
* function application.
*/
/**
* @typedef {{value:*, isProduced:Boolean}} SearchOutput
*/
/**
* @typedef {Object} SearchSpecs
* @property {function (Edge, Graph, PathTraversalState, GraphTraversalState) : {graphTraversalState : GraphTraversalState, isGoalReached : Boolean, output: SearchOutput} } evaluateGoal predicate which assesses whether a given goal is reached, or if instead the search should continue. To assess the goal, the provided information is the edge being visited, and the current edge traversal state (roughly the sequence of edges visited so far). If the goal is reached, this means we have some results for the search, and those results are aggregated somewhere in the graph traversal state for posterior extraction through `showResults`.
* @property {*} initialGoalEvalState seed for the reducer associated to goal evaluation
* @property {function (GraphTraversalState) : Search<Result>} showResults returns the accumulated results which
* have been stored in the graph traversal state
*/
/**
* @typedef {*} PathTraversalState
*/
/**
* @typedef {{initialPathTraversalState:*, visitEdge : ReducerEdge}} VisitSpecs
*/
/**
* @typedef {function (Edge, Graph, PathTraversalState, GraphTraversalState) : {isTraversableEdge :Boolean, pathTraversalState:PathTraversalState}} ReducerEdge
* function which visit the edge, updates the state of the edge traversal, and evaluates if the visited edge
* should be included in the search (`isTraversableEdge` set to true) or not.
*/
/**
* @typedef {*} Result
*/
Both edges and vertices must be objects! The good behaviour of the library is not guaranteed for edges or vertices having native types.
A graph is constructed from its array of edges and its vertices. An edge itself must contain two vertices. A vertex can be anything.
A complete description should be :
source :: e -> V
, assigning to each edge its source node,target :: e -> V
, assigning to each edge its target node.This happens to coincide exactly with the signature of our graph constructor -- though instead of sets, we use arrays.
The array of vertices is mandatory, and must contain any and every vertex part of the graph. This means in particular that no edge can be based on vertices which do not figure in the passed vertex array. This is checked by contract, by means of referential equality.
Finds all paths between two vertices in a graph. Note that a path here is not an array of vertices but an array of edges. This is a requirement as we commonly deal in MBT with graphs with several guards between two states, with same-state transitions, and other circles.
If such paths exist, they are computed and returned in the form of array in which all elements are unique, i.e. there are no two same paths, with sameness defined by referential equality of the contained edges.
It is possible to configure the maximum number of occurrences of a given edge in a path. Sameness is defined by referential equality. The default value is set to 1 (no repetition of a given edge - this ensures loop-free paths). Settings that parameter to a value greater than 1 allows to have some control over the traversal of the graph cycles.
We did not bother much with a sophisticated algorithm. A collection of search algorithms can be found in the assets directory of this repository. We used an iterative version of a brute-force enumeration algorithm, adapted for the need of enumerating edges, accounting for loops, cycles, and multi-edges. The algorithm can be found in Enumeration algorithm, p14
The function findPathsBetweenTwoVertices
uses under the hood the search algorithm implemented by
searchGraphEdges
. searchGraphEdges
returns results from the graph search starting from a
given vertex , based on the configuration passed in TraversalSpecs
.
TraversalSpecs
contains three properties (search
, store
, visit
) respectively dictating what are
and how to build search results (for instance a result is a path between given origin and target
and is to be aggregated in an array), the traversal order (for instance breadth-first), and the
traversal criteria (for instance do not pass through the same edge twice).
The search
property contains the following properties : initialGoalEvalState
, evaluateGoal
,
showResults
, respectively specifying :
isGoalReached
), what/if to output as a result (output
), and the
update of the search state (graphTraversalState
).The visit
property contains the following properties : initialPathTraversalState
,
visitEdge
, respectively specifying :
isTraversableEdge
) or
alternatively the search should backtrack, and the update of the traversal
state (pathTraversalState
).The store
property contains the following properties :
empty
: empty storeadd
: adds elements to the storetakeAndRemoveOne
: remove an element from the store and returns a store with the same elements
except the removed elementisEmpty
: predicate which returns true iff the store is emptyFor instance, for the findPathsBetweenTwoVertices
function:
BFS
or DFS
searchvisitEdge
accumulates all traversable edges in an array (with initialPathTraversalState
initially an empty array), forming an edge path. A traversable edge being an edge such that when
added to the current edge path, does not feature more than a given number
(maxNumberOfTraversals
) of edge repetition.isGoalReached
returns true iff the final edge of the current edge path is the target vertex.
graphTraversalState
, initially an empty array (initialGoalEvalState
, accumulates results, i.e
. the paths we have found which fulfiil our search criteria). Finally showResults
simply
outputs the accumulated array.As such, the searchGraphEdges
is fairly generic, and can implement a large variety of
graph (edge) searches. Among the thing which can be done :
store
property, all
else being equalThe invariant part of the function, is that for any traversed edge, the outgoing edges from that edge will be enumerated as potential traversable edges. What is a traversable edge and how those edges are eventually accumulated into search results is the parameterizable part of the function.
The following contracts apply : type contracts, graph contracts, edge contracts, vertex contracts.
We could consider it an implicit contract that the search must terminate, i.e. that the search
parameters (in particular isGoalReached
and isTraversableEdge
) have to be configured in a way
that the store eventually returns to being empty. This is not enforced but important as a graph
may have loops in which case the enumeration of edge paths would be infinite.
The searchGraphEdgesGenerator
follows the same algorithm as searchGraphEdges
, except for the
fact that when a search result is found, that result is yielded to the function caller.
searchGraphEdgesGenerator
is indeed a generator, which when called returns an iterator. That
iterator, for each next
call will return a new search result, till the enumeration is finished
(emptied store). Note that the generator returns the list of all found results. As usual, the
return value of a generator cannot be retrieved in a for..of
loop. We provide the
getIteratorReturnValue
function to that purpose.
We included this version of the search because :
ixjs
,
the pull version of rxjs
)Same contracts as searchGraphEdges
, except that the implicit contract that the search must
terminate can be relaxed.
For the sake of our needs, we provided two parameter presets (a preset is a
configuration of isTraversableEdge
, and isGoalReached
):
ALL_n_TRANSITIONS
: will reject edge paths which features more than n
repetitions of any
given edge. A successful search is the one generating an edge path whose final edge has a given
target vertexALL_TRANSITIONS
: ALL_n_TRANSITIONS
with n = 1.This is specific to our state transducer library and our need to automatically generate test sequences.
In that context, note that ALL_TRANSITIONS
helps enumerating a set of paths (input tests)
which includes all transitions from a given vertex to a target vertex. That set of paths however
is not the minimal set of such paths. It is in fact the maximal set. As there is no unicity of
the minimum set, we chose to enumerate the maximal set and let the user pick from that set the
sequences he favors.
Tests can be run with npm run test
Examples can be found in the test directory
GraphTraversalState
can be used to implement early termination of the search. Typically
visit
would update some flag in the graph traversal state, and isTraversableEdge
would not
produce any further edges after consulting that flag.FAQs
Graph ADT library
We found that graph-adt demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.