dal-engine-core-js-lib-dev 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +595 -197
- package/dist/index.esm.js +595 -197
- package/package.json +1 -1
- package/src/Base.js +10 -5
- package/src/BehavioralControlGraph/BehavioralControlGraph.js +76 -37
- package/src/BehavioralControlGraph/GraphNode.js +61 -25
- package/src/BehavioralControlGraph/Graphs.js +113 -11
- package/src/DALEngine.js +154 -53
- package/src/Errors/BehaviorAlreadyExistsError.js +10 -0
- package/src/Errors/GraphWithNameExistsError.js +10 -0
- package/src/Errors/ParticipantAlreadyExistsError.js +10 -0
- package/src/Errors/TransitionAlreadyExistsError.js +11 -0
- package/src/Errors/UnknownGraph.js +10 -0
- package/src/Errors/UnknownParticipantError.js +9 -0
- package/src/Members/Behavior.js +44 -22
- package/src/Members/Invariant.js +37 -22
- package/src/Members/Participant.js +28 -20
- package/src/TYPES.js +2 -3
- package/src/helpers/isLoadedFromFile.js +15 -0
- package/tests/DALEngine.test.js +19 -0
- package/tests/Graphs.test.js +80 -0
- package/tests/Invariant.test.js +1 -0
package/src/DALEngine.js
CHANGED
|
@@ -1,35 +1,45 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Graphs from "./BehavioralControlGraph/Graphs";
|
|
2
2
|
import MissingAttributes from "./Errors/MissingAttributes";
|
|
3
3
|
import Behavior from "./Members/Behavior";
|
|
4
4
|
import Invariant from "./Members/Invariant";
|
|
5
5
|
import Participant from "./Members/Participant";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* configure the engine through the DAL specification.
|
|
8
|
+
* This engine can be used to define and execute designs defined in a
|
|
9
|
+
* Design Abstraction Language (DAL).
|
|
11
10
|
*
|
|
12
|
-
*
|
|
13
|
-
* the
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
11
|
+
* This class is the main interface for users to interact with the
|
|
12
|
+
* engine. It exposes functions to configure the engine and to execute
|
|
13
|
+
* the design. It also exposes functions to serialize and deserialize
|
|
14
|
+
* the engine to and from JSON text.
|
|
15
|
+
*
|
|
16
|
+
* A design can consist of multiple atomic behavioral control graphs and
|
|
17
|
+
* this class allows users to create, select, and delete graphs. It also
|
|
18
|
+
* allows users to add nodes to the graph and to transition between
|
|
19
|
+
* behaviors in the graph. It also allows users to create participants,
|
|
20
|
+
* behaviors, and invariants and assign them to nodes in the graph.
|
|
21
|
+
*
|
|
22
|
+
* The selected graph is determined by the atomic behavior that is observed.
|
|
23
|
+
* The design is executed by transitioning between behaviors in the graph.
|
|
24
|
+
* The values of the participants are set from the observed values and the
|
|
25
|
+
* invariants are checked at each transition to recognize if the design has
|
|
26
|
+
* entered a semantically invalid state.
|
|
19
27
|
*/
|
|
20
28
|
export class DALEngine {
|
|
21
29
|
constructor (args) {
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
30
|
+
this.graphs = new Graphs();
|
|
31
|
+
this.graph = this.graphs.getActiveGraph();
|
|
32
|
+
this._loadArgs(args);
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @
|
|
36
|
+
* Sets the provided arguments to the engine.
|
|
37
|
+
*
|
|
38
|
+
* @throws {MissingAttributes} Thrown when required attributes are
|
|
39
|
+
* not present.
|
|
40
|
+
* @param {Object} args Arguments to load.
|
|
31
41
|
*/
|
|
32
|
-
|
|
42
|
+
_loadArgs (args) {
|
|
33
43
|
const expectedAttributes = ["name"];
|
|
34
44
|
if (typeof args !== "object" || args === null || Array.isArray(args)) {
|
|
35
45
|
// Not an object, so all attributes are missing.
|
|
@@ -44,97 +54,188 @@ export class DALEngine {
|
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
57
|
+
* Serializes the behavioral control graphs and returns the JSON text.
|
|
58
|
+
*
|
|
59
|
+
* @returns {String} Returns JSON string representing the control graphs.
|
|
49
60
|
*/
|
|
50
61
|
serialize () {
|
|
51
|
-
return JSON.stringify(this.
|
|
62
|
+
return JSON.stringify(this.graphs);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Loads the behavioral control graphs from JSON text and sets
|
|
67
|
+
* the active graph to the first graph in the collection of graphs.
|
|
68
|
+
*
|
|
69
|
+
* @param {String} serializedText JSON text representing the control
|
|
70
|
+
* graphs.
|
|
71
|
+
* @throws {SyntaxError|TypeError} Thrown when the JSON text is invalid.
|
|
72
|
+
*/
|
|
73
|
+
deserialize (serializedText) {
|
|
74
|
+
// TODO: Improve validation to throw specific error.
|
|
75
|
+
this.graphs = new Graphs();
|
|
76
|
+
this.graphs.loadFromJson(serializedText);
|
|
77
|
+
this.graph = this.graphs.getActiveGraph();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Creates a graph with the given name and sets it as the active graph.
|
|
82
|
+
*
|
|
83
|
+
* @param {String} name Name of the graph to create.
|
|
84
|
+
* @throws {GraphWithNameExistsError} Thrown when a graph with the
|
|
85
|
+
* provided name already exists.
|
|
86
|
+
*/
|
|
87
|
+
createGraph (name) {
|
|
88
|
+
this.graph = this.graphs.addGraph(name);
|
|
52
89
|
}
|
|
53
90
|
|
|
54
91
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
92
|
+
* Sets the active graph to the graph with the given graphId.
|
|
93
|
+
*
|
|
94
|
+
* @param {String} graphId ID of the graph to set as active
|
|
95
|
+
* @throws {UnknownGraph} Thrown when the provided graphId does
|
|
96
|
+
* not exist in the collection of graphs.
|
|
57
97
|
*/
|
|
58
|
-
|
|
59
|
-
this.graph =
|
|
98
|
+
selectGraph (graphId) {
|
|
99
|
+
this.graph = this.graphs.setActiveGraph(graphId);
|
|
60
100
|
}
|
|
61
101
|
|
|
62
102
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* @
|
|
103
|
+
* Removes the graph with the given graphId
|
|
104
|
+
*
|
|
105
|
+
* @param {String} graphId Id of graph to remove.
|
|
106
|
+
* @throws {UnknownGraph} Thrown when the provided graphId does not
|
|
107
|
+
* exist in the collection of graphs.
|
|
108
|
+
*/
|
|
109
|
+
removeGraph (graphId) {
|
|
110
|
+
this.graphs.removeGraph(graphId);
|
|
111
|
+
this.graph = this.graphs.getActiveGraph();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Returns the names of all the graphs in the design.
|
|
116
|
+
*
|
|
117
|
+
* @returns {Array} Returns an array of graph names.
|
|
118
|
+
*/
|
|
119
|
+
getSelectableGraphs () {
|
|
120
|
+
return this.graphs.getGraphNames();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Creates a participant with the provided args and returns it.
|
|
125
|
+
*
|
|
126
|
+
* @param {Object} args Arguments to create the participant with.
|
|
127
|
+
* @returns {Participant} Returns the created participant.
|
|
128
|
+
* @throws {MissingAttributes} Thrown when required attributes are not
|
|
129
|
+
* present in the args. See Participant class for required attributes.
|
|
66
130
|
*/
|
|
67
131
|
createParticipant (args) {
|
|
68
132
|
return new Participant(args);
|
|
69
133
|
}
|
|
70
134
|
|
|
71
135
|
/**
|
|
72
|
-
* Creates a behavior.
|
|
73
|
-
*
|
|
74
|
-
* @
|
|
136
|
+
* Creates a behavior with the provided args and returns it.
|
|
137
|
+
*
|
|
138
|
+
* @param {Object} args Arguments to create the behavior with.
|
|
139
|
+
* @returns {Behavior} Returns the created behavior.
|
|
140
|
+
* @throws {MissingAttributes} Thrown when required attributes are not
|
|
141
|
+
* present in the args. See Behavior class for required attributes.
|
|
75
142
|
*/
|
|
76
143
|
createBehavior (args) {
|
|
77
144
|
return new Behavior(args);
|
|
78
145
|
}
|
|
79
146
|
|
|
80
147
|
/**
|
|
81
|
-
* Creates an invariant.
|
|
82
|
-
*
|
|
83
|
-
* @
|
|
148
|
+
* Creates an invariant with the provided args and returns it.
|
|
149
|
+
*
|
|
150
|
+
* @param {Object} args Arguments to create the invariant with.
|
|
151
|
+
* @returns {Invariant} Returns the created invariant.
|
|
152
|
+
* @throws {MissingAttributes} Raised when required attributes are not
|
|
153
|
+
* present in the args. See Invariant class for required attributes.
|
|
84
154
|
*/
|
|
85
155
|
createInvariant (args) {
|
|
86
156
|
return new Invariant(args);
|
|
87
157
|
}
|
|
88
158
|
|
|
89
|
-
|
|
90
159
|
/**
|
|
91
160
|
* Returns the node in the graph with the given behavior name.
|
|
92
|
-
*
|
|
93
|
-
* @
|
|
161
|
+
*
|
|
162
|
+
* @param {String} behaviorId ID of the behavior.
|
|
163
|
+
* @returns {GraphNode} Returns the node in the graph with the
|
|
164
|
+
* given behavior name.
|
|
165
|
+
* @throws {UnknownBehaviorError} Thrown when the provided behaviorId is not
|
|
166
|
+
* a valid behavior in the graph.
|
|
94
167
|
*/
|
|
95
168
|
getNode (behaviorId) {
|
|
96
|
-
return this.graph.
|
|
169
|
+
return this.graph.findNode(behaviorId);
|
|
97
170
|
}
|
|
98
171
|
|
|
99
172
|
/**
|
|
100
173
|
* Adds a node to the graph with the given behaviorId and goToBehaviors.
|
|
101
|
-
*
|
|
102
|
-
* @param {
|
|
103
|
-
* @param {
|
|
104
|
-
*
|
|
174
|
+
*
|
|
175
|
+
* @param {String} behaviorId ID of the behavior for the node.
|
|
176
|
+
* @param {Array} goToBehaviorIds IDs of the behaviors that this node
|
|
177
|
+
* transitions to.
|
|
178
|
+
* @param {Boolean} isAtomic Flag to indicate if this node contains an
|
|
179
|
+
* atomic behavior.
|
|
180
|
+
* @param {Boolean} isDesignFork Flag to indicate if this node
|
|
181
|
+
* is a fork in the design.
|
|
182
|
+
* @returns {GraphNode} Returns the created graph node.
|
|
183
|
+
* @throws {BehaviorAlreadyExistsError} Raised when a node with the provided
|
|
184
|
+
* behaviorId already exists in the graph.
|
|
105
185
|
*/
|
|
106
|
-
addNode (behaviorId,
|
|
107
|
-
return this.graph.
|
|
186
|
+
addNode (behaviorId, goToBehaviorIds, isAtomic, isDesignFork) {
|
|
187
|
+
return this.graph.addNode(
|
|
188
|
+
behaviorId,
|
|
189
|
+
goToBehaviorIds,
|
|
190
|
+
isAtomic,
|
|
191
|
+
isDesignFork
|
|
192
|
+
);
|
|
108
193
|
}
|
|
109
194
|
|
|
110
195
|
/**
|
|
111
196
|
* Deletes a node from the graph with the given behaviorId and
|
|
112
197
|
* removes it from the goToBehavior list of all other nodes.
|
|
113
|
-
*
|
|
198
|
+
*
|
|
199
|
+
* @param {String} behaviorId Behavior ID of the node to delete.
|
|
200
|
+
* @returns {GraphNode} Returns the deleted graph node.
|
|
201
|
+
* @throws {UnknownBehaviorError} Thrown when the provided behaviorId is not
|
|
202
|
+
* a valid behavior in the graph.
|
|
114
203
|
*/
|
|
115
204
|
removeNode (behaviorId) {
|
|
116
|
-
|
|
205
|
+
// TODO: Move this to graph class, this class shouldn't
|
|
206
|
+
// modifiy the graph structure directly.
|
|
207
|
+
const node = this.graph.findNode(behaviorId);
|
|
117
208
|
const nodeIndex = this.graph.nodes.indexOf(node);
|
|
118
|
-
this.graph.nodes.splice(nodeIndex, 1);
|
|
209
|
+
const removedNode = this.graph.nodes.splice(nodeIndex, 1);
|
|
119
210
|
for (const node of this.graph.nodes) {
|
|
120
211
|
node.removeGoToBehavior(behaviorId);
|
|
121
212
|
}
|
|
213
|
+
return removedNode[0];
|
|
122
214
|
}
|
|
123
215
|
|
|
124
216
|
/**
|
|
125
|
-
* Sets the current behavior in the graph.
|
|
126
|
-
*
|
|
217
|
+
* Sets the current behavior in the graph. Since the behavior is not
|
|
218
|
+
* being transitioned from another, it must be an atomic behavior.
|
|
219
|
+
*
|
|
220
|
+
* @param {String} behaviorId ID of the behavior to set as current.
|
|
221
|
+
* @throws {UnknownBehaviorError} Thrown when the provided behavior is not
|
|
222
|
+
* a valid behavior in the graph.
|
|
127
223
|
*/
|
|
128
224
|
setCurrentBehavior (behaviorId) {
|
|
129
|
-
this.graph.
|
|
225
|
+
this.graph.setCurrentBehavior(behaviorId);
|
|
130
226
|
}
|
|
131
227
|
|
|
132
228
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
229
|
+
* For the current node in the graph, transitions to the node with the given
|
|
230
|
+
* behaviorId if it is a valid transition.
|
|
231
|
+
*
|
|
135
232
|
* @param {String} nextBehaviorId ID of the next behavior.
|
|
233
|
+
* @throws {UnknownBehaviorError} Thrown when the provided behavior is not
|
|
234
|
+
* a valid behavior in the graph.
|
|
235
|
+
* @throws {InvalidTransitionError} Thrown when the provided behavior is not
|
|
236
|
+
* a valid transition from the current node.
|
|
136
237
|
*/
|
|
137
238
|
goToBehavior (nextBehaviorId) {
|
|
138
|
-
this.graph.
|
|
239
|
+
this.graph.goToBehavior(nextBehaviorId);
|
|
139
240
|
}
|
|
140
241
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import DALEngineError from "./DALEngineError";
|
|
2
|
+
|
|
3
|
+
class BehaviorAlreadyExistsError extends DALEngineError {
|
|
4
|
+
constructor (name) {
|
|
5
|
+
let msg = `Node with Behavior name "${name}" already exists in the graph.`;
|
|
6
|
+
super(msg);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default BehaviorAlreadyExistsError;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import DALEngineError from "./DALEngineError";
|
|
2
|
+
|
|
3
|
+
class ParticipantAlreadyExistsError extends DALEngineError {
|
|
4
|
+
constructor (name) {
|
|
5
|
+
let msg = `Participant with name "${name}" already exists in the behavior.`;
|
|
6
|
+
super(msg);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default ParticipantAlreadyExistsError;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import DALEngineError from "./DALEngineError";
|
|
2
|
+
|
|
3
|
+
class TransitionAlreadyExistsError extends DALEngineError {
|
|
4
|
+
constructor (behaviorName, transitionName) {
|
|
5
|
+
let msg = `Node with behavior named "${behaviorName}" already has a transition\
|
|
6
|
+
to behavior "${transitionName}".`;
|
|
7
|
+
super(msg);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default TransitionAlreadyExistsError;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import DALEngineError from "./DALEngineError";
|
|
2
|
+
|
|
3
|
+
class UnknownParticipantError extends DALEngineError {
|
|
4
|
+
constructor (participantName) {
|
|
5
|
+
super(`The participant named "${participantName}" was not found in the behavior.`);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default UnknownParticipantError;
|
package/src/Members/Behavior.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import Base from "../Base";
|
|
2
2
|
import MissingAttributes from "../Errors/MissingAttributes";
|
|
3
|
+
import ParticipantAlreadyExistsError from "../Errors/ParticipantAlreadyExistsError";
|
|
4
|
+
import UnknownParticipantError from "../Errors/UnknownParticipantError";
|
|
5
|
+
import isLoadedFromFile from "../helpers/isLoadedFromFile";
|
|
3
6
|
import ENGINE_TYPES from "../TYPES";
|
|
4
7
|
import Participant from "./Participant";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
+
|
|
9
|
+
|
|
8
10
|
class Behavior extends Base {
|
|
9
11
|
/**
|
|
10
12
|
* Initialize the Behavior.
|
|
13
|
+
*
|
|
11
14
|
* @param {String} name
|
|
12
15
|
* @param args
|
|
13
16
|
*/
|
|
@@ -17,15 +20,12 @@ class Behavior extends Base {
|
|
|
17
20
|
this.participants = [];
|
|
18
21
|
this.abstractionIds = [];
|
|
19
22
|
this.invalidWorldState = false;
|
|
20
|
-
|
|
21
|
-
this._loadBehaviorFromJSON(args);
|
|
22
|
-
} else {
|
|
23
|
-
this._loadArgs(args);
|
|
24
|
-
}
|
|
23
|
+
(isLoadedFromFile(args) ? this._loadFromFile(args) : this._loadArgs(args));
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
/**
|
|
28
27
|
* Loads the provided arguments.
|
|
28
|
+
*
|
|
29
29
|
* @throws {MissingAttributes} Thrown when required attr is not present.
|
|
30
30
|
* @param {Object} args
|
|
31
31
|
*/
|
|
@@ -44,10 +44,12 @@ class Behavior extends Base {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* Loads the behavior from a JSON object.
|
|
48
|
-
*
|
|
47
|
+
* Loads the behavior from a JSON object that was read from file.
|
|
48
|
+
*
|
|
49
|
+
* @param {Object} behaviorJSON The JSON object representing the behavior
|
|
50
|
+
* read from file.
|
|
49
51
|
*/
|
|
50
|
-
|
|
52
|
+
_loadFromFile (behaviorJSON) {
|
|
51
53
|
for (const [key, value] of Object.entries(behaviorJSON)) {
|
|
52
54
|
if (key === "participants") {
|
|
53
55
|
value.forEach(node => this.participants.push(new Participant(node)));
|
|
@@ -59,33 +61,53 @@ class Behavior extends Base {
|
|
|
59
61
|
|
|
60
62
|
/**
|
|
61
63
|
* Adds a participant to the behavior.
|
|
62
|
-
*
|
|
63
|
-
* @
|
|
64
|
+
*
|
|
65
|
+
* @param {Participant} participant The participant to add.
|
|
66
|
+
* @returns {Participant} The added participant.
|
|
67
|
+
* @throws {ParticipantAlreadyExistsError} Thrown when a participant with
|
|
68
|
+
* the same name already exists in the behavior.
|
|
64
69
|
*/
|
|
65
70
|
addParticipant (participant) {
|
|
71
|
+
if (this.participants.some(p => p.name === participant.name)) {
|
|
72
|
+
throw new ParticipantAlreadyExistsError(participant.name);
|
|
73
|
+
}
|
|
66
74
|
this.participants.push(participant);
|
|
67
75
|
return participant;
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
79
|
+
* Sets the value of a participant and checks for invariant violations.
|
|
80
|
+
* If any invariant is violated, the world state for this behavior is
|
|
81
|
+
* marked as invalid.
|
|
82
|
+
*
|
|
83
|
+
* @param {String} name Name of the participant whose value is being set.
|
|
84
|
+
* @param {*} value Value to set for the participant.
|
|
85
|
+
* @throws {UnknownParticipantError} Thrown when a participant with the
|
|
86
|
+
* provided name does not exist in the behavior.
|
|
74
87
|
*/
|
|
75
|
-
setParticipantValue (
|
|
76
|
-
const participant = this.participants.find(obj => obj.name ===
|
|
88
|
+
setParticipantValue (name, value) {
|
|
89
|
+
const participant = this.participants.find(obj => obj.name === name);
|
|
90
|
+
if (!participant) {
|
|
91
|
+
throw new UnknownParticipantError(name);
|
|
92
|
+
}
|
|
77
93
|
participant.value = value;
|
|
78
|
-
|
|
79
|
-
if (violation) {
|
|
94
|
+
if (participant.enforceInvariants()) {
|
|
80
95
|
this.invalidWorldState = true;
|
|
81
96
|
}
|
|
82
97
|
}
|
|
83
98
|
|
|
84
99
|
/**
|
|
85
|
-
* Maps the abstraction id from
|
|
86
|
-
*
|
|
100
|
+
* Maps the abstraction id from implementation to the behavior.
|
|
101
|
+
*
|
|
102
|
+
* @param {String} abstractionId ID of mapped abstraction.
|
|
87
103
|
*/
|
|
88
104
|
addMapping (abstractionId) {
|
|
105
|
+
/**
|
|
106
|
+
* TODO: After some more thinking, it seems to me that the
|
|
107
|
+
* uniqe identifier should be a file name and line number.
|
|
108
|
+
* It doesn't make sense to create a new abstraction id,
|
|
109
|
+
* however, I will resolve this soon and remove this TODO.
|
|
110
|
+
*/
|
|
89
111
|
this.abstractionIds.push(abstractionId);
|
|
90
112
|
}
|
|
91
113
|
}
|
package/src/Members/Invariant.js
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
import Base from "../Base";
|
|
2
2
|
import MissingAttributes from "../Errors/MissingAttributes";
|
|
3
|
+
import isLoadedFromFile from "../helpers/isLoadedFromFile";
|
|
3
4
|
import ENGINE_TYPES from "../TYPES";
|
|
4
5
|
|
|
5
|
-
/**
|
|
6
|
-
* Class representing a Invariant in the design.
|
|
7
|
-
*/
|
|
8
6
|
class Invariant extends Base {
|
|
9
7
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* Class representing a Invariant in the design. Invariants are rules that
|
|
9
|
+
* define a valid world state for participants in behaviors. The invariants
|
|
10
|
+
* are used to check if the design has entered a semantically invalid state
|
|
11
|
+
* during execution.
|
|
12
|
+
*
|
|
13
|
+
* The expected attributes in args are:
|
|
14
|
+
* - name: Name of the invariant.
|
|
15
|
+
* - rule: The rule that defines the how to enforce the invariant. This
|
|
16
|
+
* will be formally defined in a collection of invariant rules that can
|
|
17
|
+
* be chosen from when creating an invariant.
|
|
18
|
+
*
|
|
19
|
+
* Currently, the only supported invariant rule is the string min length
|
|
20
|
+
* rule, which can be specified as follows:
|
|
21
|
+
* {
|
|
22
|
+
* "name": "MinLengthConstraint",
|
|
23
|
+
* "rule": {
|
|
24
|
+
* "type": "minLength",
|
|
25
|
+
* "keys": ["value", "name"],
|
|
26
|
+
* "value": 1,
|
|
27
|
+
* },
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* @param {Object} args The arguments to initialize the invariant with.
|
|
13
31
|
*/
|
|
14
32
|
constructor (args) {
|
|
15
33
|
super();
|
|
@@ -17,17 +35,13 @@ class Invariant extends Base {
|
|
|
17
35
|
this.invariantViolated = false;
|
|
18
36
|
this.invariantType = null;
|
|
19
37
|
this.traceId = null;
|
|
20
|
-
|
|
21
|
-
this._loadInvariantFromJSON(args);
|
|
22
|
-
} else {
|
|
23
|
-
this._loadArgs(args);
|
|
24
|
-
}
|
|
38
|
+
(isLoadedFromFile(args) ? this._loadFromFile(args) : this._loadArgs(args));
|
|
25
39
|
}
|
|
26
40
|
|
|
27
41
|
/**
|
|
28
|
-
* Loads the provided arguments.
|
|
42
|
+
* Loads the invariant from the provided arguments.
|
|
29
43
|
* @throws {MissingAttributes} Thrown when required attr is not present.
|
|
30
|
-
* @param {Object} args
|
|
44
|
+
* @param {Object} args The arguments to initialize the invariant with.
|
|
31
45
|
*/
|
|
32
46
|
_loadArgs (args) {
|
|
33
47
|
const expectedAttributes = ["name", "rule"];
|
|
@@ -44,10 +58,10 @@ class Invariant extends Base {
|
|
|
44
58
|
}
|
|
45
59
|
|
|
46
60
|
/**
|
|
47
|
-
* Loads the
|
|
48
|
-
* @param {Object} invariantJSON
|
|
61
|
+
* Loads the invariant from file.
|
|
62
|
+
* @param {Object} invariantJSON The JSON object to load the invariant from.
|
|
49
63
|
*/
|
|
50
|
-
|
|
64
|
+
_loadFromFile (invariantJSON) {
|
|
51
65
|
for (const [key, value] of Object.entries(invariantJSON)) {
|
|
52
66
|
this[key] = value;
|
|
53
67
|
};
|
|
@@ -57,9 +71,10 @@ class Invariant extends Base {
|
|
|
57
71
|
}
|
|
58
72
|
|
|
59
73
|
/**
|
|
60
|
-
* Evaluate the invariant
|
|
61
|
-
*
|
|
62
|
-
* @
|
|
74
|
+
* Evaluate the invariant by applying the invariant rule to the provided
|
|
75
|
+
* value. Returns a flag indicating whether the invariant was violated.
|
|
76
|
+
* @param {*} value The value to evaluate the invariant on.
|
|
77
|
+
* @returns {Boolean} Returns flag indicating if invariant was violated.
|
|
63
78
|
*/
|
|
64
79
|
evaluate (value) {
|
|
65
80
|
this.invariantViolated = false;
|
|
@@ -70,8 +85,8 @@ class Invariant extends Base {
|
|
|
70
85
|
}
|
|
71
86
|
|
|
72
87
|
/**
|
|
73
|
-
* Enforce the string min length invariant
|
|
74
|
-
* @param value
|
|
88
|
+
* Enforce the string min length invariant.
|
|
89
|
+
* @param {*} value The value to enforce the invariant on.
|
|
75
90
|
*/
|
|
76
91
|
enforceMinLength (value) {
|
|
77
92
|
if ("keys" in this.rule) {
|
|
@@ -108,7 +123,7 @@ class Invariant extends Base {
|
|
|
108
123
|
* automated testing.
|
|
109
124
|
*
|
|
110
125
|
* Substrate invariants correspond to a trace that represents
|
|
111
|
-
* an environment
|
|
126
|
+
* an environment which reveals a limitation of the substrate,
|
|
112
127
|
* thus motivating the invariant. It is also the environment
|
|
113
128
|
* in which an implementation can prove that it respects this
|
|
114
129
|
* invariant.
|