dal-engine-core-js-lib-dev 0.0.4 → 0.0.5
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 +581 -197
- package/dist/index.esm.js +581 -197
- package/package.json +1 -1
- package/src/Base.js +10 -5
- package/src/BehavioralControlGraph/BehavioralControlGraph.js +76 -37
- package/src/BehavioralControlGraph/GraphNode.js +55 -25
- package/src/BehavioralControlGraph/Graphs.js +113 -11
- package/src/DALEngine.js +153 -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/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 +8 -0
- package/tests/Graphs.test.js +80 -0
- package/tests/Invariant.test.js +1 -0
package/src/DALEngine.js
CHANGED
|
@@ -1,35 +1,46 @@
|
|
|
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);
|
|
33
|
+
console.log("Initialized DAL Engine with graphs: ", this.graphs);
|
|
25
34
|
}
|
|
26
35
|
|
|
27
36
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @
|
|
37
|
+
* Sets the provided arguments to the engine.
|
|
38
|
+
*
|
|
39
|
+
* @throws {MissingAttributes} Thrown when required attributes are
|
|
40
|
+
* not present.
|
|
41
|
+
* @param {Object} args Arguments to load.
|
|
31
42
|
*/
|
|
32
|
-
|
|
43
|
+
_loadArgs (args) {
|
|
33
44
|
const expectedAttributes = ["name"];
|
|
34
45
|
if (typeof args !== "object" || args === null || Array.isArray(args)) {
|
|
35
46
|
// Not an object, so all attributes are missing.
|
|
@@ -44,97 +55,186 @@ export class DALEngine {
|
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
58
|
+
* Serializes the behavioral control graphs and returns the JSON text.
|
|
59
|
+
*
|
|
60
|
+
* @returns {String} Returns JSON string representing the control graphs.
|
|
49
61
|
*/
|
|
50
62
|
serialize () {
|
|
51
|
-
return JSON.stringify(this.
|
|
63
|
+
return JSON.stringify(this.graphs);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Loads the behavioral control graphs from JSON text and sets
|
|
68
|
+
* the active graph to the first graph in the collection of graphs.
|
|
69
|
+
*
|
|
70
|
+
* @param {String} serializedText JSON text representing the control
|
|
71
|
+
* graphs.
|
|
72
|
+
* @throws {SyntaxError|TypeError} Thrown when the JSON text is invalid.
|
|
73
|
+
*/
|
|
74
|
+
deserialize (serializedText) {
|
|
75
|
+
// TODO: Improve validation to throw specific error.
|
|
76
|
+
this.graphs = new Graphs();
|
|
77
|
+
this.graphs.loadFromJson(serializedText);
|
|
78
|
+
this.graph = this.graphs.getActiveGraph();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Creates a graph with the given name and sets it as the active graph.
|
|
83
|
+
*
|
|
84
|
+
* @param {String} name Name of the graph to create.
|
|
85
|
+
* @throws {GraphWithNameExistsError} Thrown when a graph with the
|
|
86
|
+
* provided name already exists.
|
|
87
|
+
*/
|
|
88
|
+
createGraph (name) {
|
|
89
|
+
this.graph = this.graphs.addGraph(name);
|
|
52
90
|
}
|
|
53
91
|
|
|
54
92
|
/**
|
|
55
|
-
*
|
|
56
|
-
*
|
|
93
|
+
* Sets the active graph to the graph with the given graphId.
|
|
94
|
+
*
|
|
95
|
+
* @param {String} graphId ID of the graph to set as active
|
|
96
|
+
* @throws {UnknownGraph} Thrown when the provided graphId does
|
|
97
|
+
* not exist in the collection of graphs.
|
|
57
98
|
*/
|
|
58
|
-
|
|
59
|
-
this.graph =
|
|
99
|
+
selectGraph (graphId) {
|
|
100
|
+
this.graph = this.graphs.setActiveGraph(graphId);
|
|
60
101
|
}
|
|
61
102
|
|
|
62
103
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* @
|
|
104
|
+
* Removes the graph with the given graphId
|
|
105
|
+
*
|
|
106
|
+
* @param {String} graphId Id of graph to remove.
|
|
107
|
+
* @throws {UnknownGraph} Thrown when the provided graphId does not
|
|
108
|
+
* exist in the collection of graphs.
|
|
109
|
+
*/
|
|
110
|
+
removeGraph (graphId) {
|
|
111
|
+
this.graphs.removeGraph(graphId);
|
|
112
|
+
this.graph = this.graphs.getActiveGraph();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Returns the names of all the graphs in the design.
|
|
117
|
+
*
|
|
118
|
+
* @returns {Array} Returns an array of graph names.
|
|
119
|
+
*/
|
|
120
|
+
getSelectableGraphs () {
|
|
121
|
+
return this.graphs.getGraphNames();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Creates a participant with the provided args and returns it.
|
|
126
|
+
*
|
|
127
|
+
* @param {Object} args Arguments to create the participant with.
|
|
128
|
+
* @returns {Participant} Returns the created participant.
|
|
129
|
+
* @throws {MissingAttributes} Thrown when required attributes are not
|
|
130
|
+
* present in the args. See Participant class for required attributes.
|
|
66
131
|
*/
|
|
67
132
|
createParticipant (args) {
|
|
68
133
|
return new Participant(args);
|
|
69
134
|
}
|
|
70
135
|
|
|
71
136
|
/**
|
|
72
|
-
* Creates a behavior.
|
|
73
|
-
*
|
|
74
|
-
* @
|
|
137
|
+
* Creates a behavior with the provided args and returns it.
|
|
138
|
+
*
|
|
139
|
+
* @param {Object} args Arguments to create the behavior with.
|
|
140
|
+
* @returns {Behavior} Returns the created behavior.
|
|
141
|
+
* @throws {MissingAttributes} Thrown when required attributes are not
|
|
142
|
+
* present in the args. See Behavior class for required attributes.
|
|
75
143
|
*/
|
|
76
144
|
createBehavior (args) {
|
|
77
145
|
return new Behavior(args);
|
|
78
146
|
}
|
|
79
147
|
|
|
80
148
|
/**
|
|
81
|
-
* Creates an invariant.
|
|
82
|
-
*
|
|
83
|
-
* @
|
|
149
|
+
* Creates an invariant with the provided args and returns it.
|
|
150
|
+
*
|
|
151
|
+
* @param {Object} args Arguments to create the invariant with.
|
|
152
|
+
* @returns {Invariant} Returns the created invariant.
|
|
153
|
+
* @throws {MissingAttributes} Raised when required attributes are not
|
|
154
|
+
* present in the args. See Invariant class for required attributes.
|
|
84
155
|
*/
|
|
85
156
|
createInvariant (args) {
|
|
86
157
|
return new Invariant(args);
|
|
87
158
|
}
|
|
88
159
|
|
|
89
|
-
|
|
90
160
|
/**
|
|
91
161
|
* Returns the node in the graph with the given behavior name.
|
|
92
|
-
*
|
|
93
|
-
* @
|
|
162
|
+
*
|
|
163
|
+
* @param {String} behaviorId ID of the behavior.
|
|
164
|
+
* @returns {GraphNode} Returns the node in the graph with the
|
|
165
|
+
* given behavior name.
|
|
166
|
+
* @throws {UnknownBehaviorError} Thrown when the provided behaviorId is not
|
|
167
|
+
* a valid behavior in the graph.
|
|
94
168
|
*/
|
|
95
169
|
getNode (behaviorId) {
|
|
96
|
-
return this.graph.
|
|
170
|
+
return this.graph.findNode(behaviorId);
|
|
97
171
|
}
|
|
98
172
|
|
|
99
173
|
/**
|
|
100
174
|
* Adds a node to the graph with the given behaviorId and goToBehaviors.
|
|
101
|
-
*
|
|
102
|
-
* @param {
|
|
103
|
-
* @param {
|
|
104
|
-
*
|
|
175
|
+
*
|
|
176
|
+
* @param {String} behaviorId ID of the behavior for the node.
|
|
177
|
+
* @param {Array} goToBehaviorIds IDs of the behaviors that this node
|
|
178
|
+
* transitions to.
|
|
179
|
+
* @param {Boolean} isAtomic Flag to indicate if this node contains an
|
|
180
|
+
* atomic behavior.
|
|
181
|
+
* @param {Boolean} isDesignFork Flag to indicate if this node
|
|
182
|
+
* is a fork in the design.
|
|
183
|
+
* @returns {GraphNode} Returns the created graph node.
|
|
184
|
+
* @throws {BehaviorAlreadyExistsError} Raised when a node with the provided
|
|
185
|
+
* behaviorId already exists in the graph.
|
|
105
186
|
*/
|
|
106
|
-
addNode (behaviorId,
|
|
107
|
-
return this.graph.
|
|
187
|
+
addNode (behaviorId, goToBehaviorIds, isAtomic, isDesignFork) {
|
|
188
|
+
return this.graph.addNode(
|
|
189
|
+
behaviorId,
|
|
190
|
+
goToBehaviorIds,
|
|
191
|
+
isAtomic,
|
|
192
|
+
isDesignFork
|
|
193
|
+
);
|
|
108
194
|
}
|
|
109
195
|
|
|
110
196
|
/**
|
|
111
197
|
* Deletes a node from the graph with the given behaviorId and
|
|
112
198
|
* removes it from the goToBehavior list of all other nodes.
|
|
113
|
-
*
|
|
199
|
+
*
|
|
200
|
+
* @param {String} behaviorId Behavior ID of the node to delete.
|
|
201
|
+
* @returns {GraphNode} Returns the deleted graph node.
|
|
202
|
+
* @throws {UnknownBehaviorError} Thrown when the provided behaviorId is not
|
|
203
|
+
* a valid behavior in the graph.
|
|
114
204
|
*/
|
|
115
205
|
removeNode (behaviorId) {
|
|
116
|
-
const node = this.graph.
|
|
206
|
+
const node = this.graph.findNode(behaviorId);
|
|
117
207
|
const nodeIndex = this.graph.nodes.indexOf(node);
|
|
118
|
-
this.graph.nodes.splice(nodeIndex, 1);
|
|
208
|
+
const removedNode = this.graph.nodes.splice(nodeIndex, 1);
|
|
119
209
|
for (const node of this.graph.nodes) {
|
|
120
210
|
node.removeGoToBehavior(behaviorId);
|
|
121
211
|
}
|
|
212
|
+
return removedNode[0];
|
|
122
213
|
}
|
|
123
214
|
|
|
124
215
|
/**
|
|
125
|
-
* Sets the current behavior in the graph.
|
|
126
|
-
*
|
|
216
|
+
* Sets the current behavior in the graph. Since the behavior is not
|
|
217
|
+
* being transitioned from another, it must be an atomic behavior.
|
|
218
|
+
*
|
|
219
|
+
* @param {String} behaviorId ID of the behavior to set as current.
|
|
220
|
+
* @throws {UnknownBehaviorError} Thrown when the provided behavior is not
|
|
221
|
+
* a valid behavior in the graph.
|
|
127
222
|
*/
|
|
128
223
|
setCurrentBehavior (behaviorId) {
|
|
129
|
-
this.graph.
|
|
224
|
+
this.graph.setCurrentBehavior(behaviorId);
|
|
130
225
|
}
|
|
131
226
|
|
|
132
227
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
228
|
+
* For the current node in the graph, transitions to the node with the given
|
|
229
|
+
* behaviorId if it is a valid transition.
|
|
230
|
+
*
|
|
135
231
|
* @param {String} nextBehaviorId ID of the next behavior.
|
|
232
|
+
* @throws {UnknownBehaviorError} Thrown when the provided behavior is not
|
|
233
|
+
* a valid behavior in the graph.
|
|
234
|
+
* @throws {InvalidTransitionError} Thrown when the provided behavior is not
|
|
235
|
+
* a valid transition from the current node.
|
|
136
236
|
*/
|
|
137
237
|
goToBehavior (nextBehaviorId) {
|
|
138
|
-
this.graph.
|
|
238
|
+
this.graph.goToBehavior(nextBehaviorId);
|
|
139
239
|
}
|
|
140
240
|
}
|
|
@@ -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,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.
|
|
@@ -1,16 +1,20 @@
|
|
|
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
|
import Invariant from "./Invariant";
|
|
5
6
|
|
|
6
|
-
/**
|
|
7
|
-
* Class representing a participant in the design.
|
|
8
|
-
*/
|
|
9
7
|
class Participant extends Base {
|
|
10
8
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* Class representing a participant in the design. The participants are
|
|
10
|
+
* entites in deisgn that participate in the behavior. They are mapped onto
|
|
11
|
+
* the implementation and their value is loaded from the execution. The
|
|
12
|
+
* participants define a valid world state for the behavior to happen in
|
|
13
|
+
* through invariants. When the value of the participant violates an
|
|
14
|
+
* invariant, the design has entered a semantically invalid state and is
|
|
15
|
+
* the root cause of downstream failure(s).
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} args The arguments to initialize the participant.
|
|
14
18
|
*/
|
|
15
19
|
constructor (args) {
|
|
16
20
|
super();
|
|
@@ -18,11 +22,7 @@ class Participant extends Base {
|
|
|
18
22
|
this.invariants = [];
|
|
19
23
|
this.abstractionId = null;
|
|
20
24
|
this.invariantViolated = false;
|
|
21
|
-
|
|
22
|
-
this._loadParticipantFromJSON(args);
|
|
23
|
-
} else {
|
|
24
|
-
this._loadArgs(args);
|
|
25
|
-
}
|
|
25
|
+
(isLoadedFromFile(args) ? this._loadFromFile(args) : this._loadArgs(args));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -46,9 +46,9 @@ class Participant extends Base {
|
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* Loads the participant from a JSON object.
|
|
49
|
-
* @param {Object} participantJSON
|
|
49
|
+
* @param {Object} participantJSON The JSON object read from file.
|
|
50
50
|
*/
|
|
51
|
-
|
|
51
|
+
_loadFromFile (participantJSON) {
|
|
52
52
|
for (const [key, value] of Object.entries(participantJSON)) {
|
|
53
53
|
if (key === "invariants") {
|
|
54
54
|
value.forEach(node => this.invariants.push(new Invariant(node)));
|
|
@@ -60,8 +60,8 @@ class Participant extends Base {
|
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Adds an invariant to the participant.
|
|
63
|
-
* @param {Invariant} invariant
|
|
64
|
-
* @returns
|
|
63
|
+
* @param {Invariant} invariant The invariant to add.
|
|
64
|
+
* @returns {Invariant} The invariant that was added.
|
|
65
65
|
*/
|
|
66
66
|
addInvariant (invariant) {
|
|
67
67
|
this.invariants.push(invariant);
|
|
@@ -69,16 +69,18 @@ class Participant extends Base {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
* Sets the value of
|
|
73
|
-
* @param {*} value
|
|
72
|
+
* Sets the value of this participant.
|
|
73
|
+
* @param {*} value The value to set for the participant.
|
|
74
74
|
*/
|
|
75
75
|
setValue (value) {
|
|
76
76
|
this.value = value;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
|
-
* Enforces the
|
|
81
|
-
*
|
|
80
|
+
* Enforces the participant's invariants. Raises a flag indicating if an
|
|
81
|
+
* invariant was violated and counts the number of invariant violations.
|
|
82
|
+
*
|
|
83
|
+
* @returns {Boolean} Returns flag indicating if any invariant was violated.
|
|
82
84
|
*/
|
|
83
85
|
enforceInvariants () {
|
|
84
86
|
this.invariantViolated = false
|
|
@@ -98,9 +100,15 @@ class Participant extends Base {
|
|
|
98
100
|
* This abstraction id will be used to assign a value to the
|
|
99
101
|
* participant from the execution using the logged abstraction id.
|
|
100
102
|
*
|
|
101
|
-
* @param {String} abstractionId
|
|
103
|
+
* @param {String} abstractionId The abstraction ID to map to the
|
|
104
|
+
* participant.
|
|
102
105
|
*/
|
|
103
106
|
mapAbstraction (abstractionId) {
|
|
107
|
+
/**
|
|
108
|
+
* TODO: Much like the behavior, I am settling on a clean way to map
|
|
109
|
+
* the participant onto the implementation without introducing new
|
|
110
|
+
* unncessary layers.
|
|
111
|
+
*/
|
|
104
112
|
this.abstractionId = abstractionId;
|
|
105
113
|
}
|
|
106
114
|
}
|