dal-engine-core-js-lib-dev 0.0.2 → 0.0.4

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/src/DALEngine.js CHANGED
@@ -20,6 +20,7 @@ import Participant from "./Members/Participant";
20
20
  export class DALEngine {
21
21
  constructor (args) {
22
22
  this.graph = new BehavioralControlGraph();
23
+ this.atomicGraphs = [];
23
24
  this.loadArgs(args);
24
25
  }
25
26
 
@@ -55,8 +56,7 @@ export class DALEngine {
55
56
  * @param {String} jsonText
56
57
  */
57
58
  deserialize (jsonText) {
58
- this.graph = new BehavioralControlGraph();
59
- this.graph.loadGraphFromJSON(JSON.parse(jsonText));
59
+ this.graph = new BehavioralControlGraph(JSON.parse(jsonText));
60
60
  }
61
61
 
62
62
  /**
@@ -93,33 +93,48 @@ export class DALEngine {
93
93
  * @returns {GraphNode}
94
94
  */
95
95
  getNode (behaviorId) {
96
- return this.graph.findNode(behaviorId);
96
+ return this.graph._findNode(behaviorId);
97
97
  }
98
98
 
99
99
  /**
100
100
  * Adds a node to the graph with the given behaviorId and goToBehaviors.
101
101
  * @param {String} behaviorId
102
102
  * @param {Array} goToBehaviorsIds
103
+ * @param {Boolean} isAtomic
103
104
  * @returns {GraphNode}
104
105
  */
105
- addNode (behaviorId, goToBehaviorsIds) {
106
- const behavior = this.createBehavior({name: behaviorId});
107
- return this.graph.addNode(behavior, goToBehaviorsIds);
106
+ addNode (behaviorId, goToBehaviorsIds, isAtomic) {
107
+ return this.graph._addNode(behaviorId, goToBehaviorsIds, isAtomic);
108
108
  }
109
109
 
110
110
  /**
111
- * Adds a goToBehavior to the node with the given behaviorId.
111
+ * Deletes a node from the graph with the given behaviorId and
112
+ * removes it from the goToBehavior list of all other nodes.
112
113
  * @param {String} behaviorId
113
- * @param {String|Array} goToBehaviorIds
114
- * @returns {GraphNode}
115
114
  */
116
- addGoToBehavior (behaviorId, goToBehaviorIds) {
117
- const node = this.graph.findNode(behaviorId);
118
- if (Array.isArray(goToBehaviorIds)) {
119
- node.goToBehaviorsIds.push(...goToBehaviorIds);
120
- } else {
121
- node.goToBehaviorsIds.push(goToBehaviorIds);
115
+ removeNode (behaviorId) {
116
+ const node = this.graph._findNode(behaviorId);
117
+ const nodeIndex = this.graph.nodes.indexOf(node);
118
+ this.graph.nodes.splice(nodeIndex, 1);
119
+ for (const node of this.graph.nodes) {
120
+ node.removeGoToBehavior(behaviorId);
122
121
  }
123
- return node;
122
+ }
123
+
124
+ /**
125
+ * Sets the current behavior in the graph.
126
+ * @param {String} behaviorId
127
+ */
128
+ setCurrentBehavior (behaviorId) {
129
+ this.graph._setCurrentBehavior(behaviorId);
130
+ }
131
+
132
+ /**
133
+ * Transitions the graph to the given behavior if it
134
+ * is a valid transition from the current behavior.
135
+ * @param {String} nextBehaviorId ID of the next behavior.
136
+ */
137
+ goToBehavior (nextBehaviorId) {
138
+ this.graph._goToBehavior(nextBehaviorId);
124
139
  }
125
140
  }
@@ -18,9 +18,9 @@ class Behavior extends Base {
18
18
  this.abstractionIds = [];
19
19
  this.invalidWorldState = false;
20
20
  if (typeof args === "object" && Object.hasOwn(args, "uid")) {
21
- this.loadBehaviorFromJSON(args);
21
+ this._loadBehaviorFromJSON(args);
22
22
  } else {
23
- this.loadArgs(args);
23
+ this._loadArgs(args);
24
24
  }
25
25
  }
26
26
 
@@ -29,7 +29,7 @@ class Behavior extends Base {
29
29
  * @throws {MissingAttributes} Thrown when required attr is not present.
30
30
  * @param {Object} args
31
31
  */
32
- loadArgs (args) {
32
+ _loadArgs (args) {
33
33
  const expectedAttributes = ["name"];
34
34
  if (typeof args !== "object" || args === null || Array.isArray(args)) {
35
35
  // Not an object, so all attributes are missing.
@@ -47,7 +47,7 @@ class Behavior extends Base {
47
47
  * Loads the behavior from a JSON object.
48
48
  * @param {Object} behaviorJSON
49
49
  */
50
- loadBehaviorFromJSON (behaviorJSON) {
50
+ _loadBehaviorFromJSON (behaviorJSON) {
51
51
  for (const [key, value] of Object.entries(behaviorJSON)) {
52
52
  if (key === "participants") {
53
53
  value.forEach(node => this.participants.push(new Participant(node)));
@@ -62,7 +62,7 @@ class Behavior extends Base {
62
62
  * @param {Participant} participant
63
63
  * @returns
64
64
  */
65
- addParticpant (participant) {
65
+ addParticipant (participant) {
66
66
  this.participants.push(participant);
67
67
  return participant;
68
68
  }
@@ -18,9 +18,9 @@ class Invariant extends Base {
18
18
  this.invariantType = null;
19
19
  this.traceId = null;
20
20
  if (typeof args === "object" && Object.hasOwn(args, "uid")) {
21
- this.loadInvariantFromJSON(args);
21
+ this._loadInvariantFromJSON(args);
22
22
  } else {
23
- this.loadArgs(args);
23
+ this._loadArgs(args);
24
24
  }
25
25
  }
26
26
 
@@ -29,7 +29,7 @@ class Invariant extends Base {
29
29
  * @throws {MissingAttributes} Thrown when required attr is not present.
30
30
  * @param {Object} args
31
31
  */
32
- loadArgs (args) {
32
+ _loadArgs (args) {
33
33
  const expectedAttributes = ["name", "rule"];
34
34
  if (typeof args !== "object" || args === null || Array.isArray(args)) {
35
35
  // Not an object, so all attributes are missing.
@@ -47,7 +47,7 @@ class Invariant extends Base {
47
47
  * Loads the participant from a JSON object.
48
48
  * @param {Object} invariantJSON
49
49
  */
50
- loadInvariantFromJSON (invariantJSON) {
50
+ _loadInvariantFromJSON (invariantJSON) {
51
51
  for (const [key, value] of Object.entries(invariantJSON)) {
52
52
  this[key] = value;
53
53
  };
@@ -14,14 +14,14 @@ class Participant extends Base {
14
14
  */
15
15
  constructor (args) {
16
16
  super();
17
- this.type = ENGINE_TYPES.INVARIANT;
17
+ this.type = ENGINE_TYPES.PARTICIPANT;
18
18
  this.invariants = [];
19
19
  this.abstractionId = null;
20
20
  this.invariantViolated = false;
21
21
  if (typeof args === "object" && Object.hasOwn(args, "uid")) {
22
- this.loadParticipantFromJSON(args);
22
+ this._loadParticipantFromJSON(args);
23
23
  } else {
24
- this.loadArgs(args);
24
+ this._loadArgs(args);
25
25
  }
26
26
  }
27
27
 
@@ -30,7 +30,7 @@ class Participant extends Base {
30
30
  * @throws {MissingAttributes} Thrown when required attr is not present.
31
31
  * @param {Object} args
32
32
  */
33
- loadArgs (args) {
33
+ _loadArgs (args) {
34
34
  const expectedAttributes = ["name"];
35
35
  if (typeof args !== "object" || args === null || Array.isArray(args)) {
36
36
  // Not an object, so all attributes are missing.
@@ -48,7 +48,7 @@ class Participant extends Base {
48
48
  * Loads the participant from a JSON object.
49
49
  * @param {Object} participantJSON
50
50
  */
51
- loadParticipantFromJSON (participantJSON) {
51
+ _loadParticipantFromJSON (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)));
@@ -28,12 +28,12 @@ describe("DALEngine", () => {
28
28
  it("adds node to graph", () => {
29
29
  const d = new DALEngine({name: "Library Manager"});
30
30
  const goToBehaviorIds = ["AddBookToBasket"];
31
- const node = d.addNode("AcceptBookFromUser", goToBehaviorIds)
31
+ const node = d.addNode("AcceptBookFromUser", goToBehaviorIds);
32
32
 
33
33
  const nodeType = node.type;
34
34
  expect(nodeType).toBe(ENGINE_TYPES.GRAPH_NODE);
35
- expect(node.behavior.name).toStrictEqual("AcceptBookFromUser");
36
- expect(node.goToBehaviorsIds).toStrictEqual(goToBehaviorIds);
35
+ expect(node.getBehavior().name).toStrictEqual("AcceptBookFromUser");
36
+ expect(node.getGoToBehaviors()).toStrictEqual(goToBehaviorIds);
37
37
  });
38
38
 
39
39
  it("find node that was added using behavior name", () => {
@@ -46,6 +46,21 @@ describe("DALEngine", () => {
46
46
  expect(foundNode).toStrictEqual(node);
47
47
  });
48
48
 
49
+ it("adds node to graph and removes it", () => {
50
+ const d = new DALEngine({name: "Library Manager"});
51
+ d.addNode("AcceptBookFromUser", []);
52
+ d.addNode("AddBookToBasket", []);
53
+
54
+ d.getNode("AcceptBookFromUser").addGoToBehavior("AddBookToBasket");
55
+
56
+ const node = d.getNode("AcceptBookFromUser");
57
+
58
+ const nodeType = node.type;
59
+ expect(nodeType).toBe(ENGINE_TYPES.GRAPH_NODE);
60
+ expect(node.getBehavior().name).toStrictEqual("AcceptBookFromUser");
61
+ expect(node.getGoToBehaviors()).toStrictEqual(["AddBookToBasket"]);
62
+ });
63
+
49
64
  it("find node and check if observed behavior is valid transition", () => {
50
65
  const d = new DALEngine({name: "Library Manager"});
51
66
  const node1 = d.addNode("AcceptBookFromUser", []);
@@ -57,31 +72,31 @@ describe("DALEngine", () => {
57
72
 
58
73
  // Misspell behavior name to trigger unknown behavior error
59
74
  expect(() => {
60
- d.graph.setCurrentBehavior("AcceptBookromUser");
75
+ d.setCurrentBehavior("AcceptBookromUser");
61
76
  }).toThrow(UnknownBehaviorError);
62
77
 
63
- d.graph.setCurrentBehavior("AcceptBookFromUser");
78
+ d.setCurrentBehavior("AcceptBookFromUser");
64
79
  expect(d.graph.currentNode).toBe(node1);
65
80
 
66
- d.graph.goToBehavior("AddBookToBasket")
81
+ d.goToBehavior("AddBookToBasket")
67
82
  expect(d.graph.currentNode).toBe(node2);
68
83
 
69
84
  // Reset current behavior so transition is valid
70
- d.graph.setCurrentBehavior("AcceptBookFromUser");
71
- d.graph.goToBehavior("AddBookToBasket")
85
+ d.setCurrentBehavior("AcceptBookFromUser");
86
+ d.goToBehavior("AddBookToBasket")
72
87
  expect(d.graph.currentNode).toBe(node2);
73
88
 
74
89
  // Raises error because current behavior is "AnotherBehavior"
75
90
  // and it does not transition to itself.
76
91
  expect(() => {
77
- d.graph.goToBehavior("AddBookToBasket")
92
+ d.goToBehavior("AddBookToBasket")
78
93
  }).toThrow(InvalidTransitionError);
79
94
 
80
95
  // Reset the current behavior and then go to a behavior
81
96
  // which is misspelled and expect an invalid transition error
82
97
  expect(() => {
83
- d.graph.setCurrentBehavior("AcceptBookFromUser");
84
- d.graph.goToBehavior("AddBookToasket")
98
+ d.setCurrentBehavior("AcceptBookFromUser");
99
+ d.goToBehavior("AddBookToasket")
85
100
  }).toThrow(InvalidTransitionError);
86
101
  });
87
102
 
@@ -121,14 +136,14 @@ describe("DALEngine", () => {
121
136
  book.addInvariant(invariant);
122
137
 
123
138
 
124
- const node1 = d.addNode("AcceptBookFromUser", []);
139
+ d.addNode("AcceptBookFromUser", []);
125
140
  d.addNode("AddBookToBasket", []);
126
141
  d.addNode("AnotherBehavior", []);
127
142
 
128
- node1.addGoToBehavior("AddBookToBasket");
129
- node1.addGoToBehavior("AnotherBehavior");
143
+ d.getNode("AcceptBookFromUser").addGoToBehavior("AddBookToBasket");
144
+ d.getNode("AcceptBookFromUser").addGoToBehavior("AnotherBehavior");
130
145
 
131
- node1.behavior.addParticpant(book);
146
+ d.getNode("AcceptBookFromUser").getBehavior().addParticipant(book);
132
147
 
133
148
  const filePath = resolve(__dirname, "./temp/inspectSerializeTemp.json")
134
149
  await writeFile(filePath, d.serialize())
@@ -73,26 +73,26 @@ describe("invariantTests", () => {
73
73
 
74
74
  // Create behavior and participant
75
75
  const node1 = d.addNode("AcceptBookFromUser", []);
76
- node1.behavior.addParticpant(book);
76
+ node1.getBehavior().addParticipant(book);
77
77
 
78
78
  // Add value that respects invariant and expect valid world state
79
- node1.behavior.setParticipantValue("book", {
79
+ node1.getBehavior().setParticipantValue("book", {
80
80
  "uid": 1,
81
81
  "value": {
82
82
  "name": "Harry Potter and Chamber of Secrets",
83
83
  },
84
84
  })
85
- expect(node1.behavior.invalidWorldState).toBe(false);
85
+ expect(node1.getBehavior().invalidWorldState).toBe(false);
86
86
 
87
87
 
88
88
  // Add value that violates invariant and expect invalid world state
89
- node1.behavior.setParticipantValue("book", {
89
+ node1.getBehavior().setParticipantValue("book", {
90
90
  "uid": 1,
91
91
  "value": {
92
92
  "name": "",
93
93
  },
94
94
  })
95
- expect(node1.behavior.invalidWorldState).toBe(true);
95
+ expect(node1.getBehavior().invalidWorldState).toBe(true);
96
96
 
97
97
  // Write to file for inspection
98
98
  const filePath = resolve(__dirname, "./temp/invariantBehaviorTemp.json")
@@ -21,7 +21,10 @@ describe("SimpleDesignTest", () => {
21
21
  d.addNode("CreateSlotOnBookShelf", ["AddBookToShelf"]);
22
22
  d.addNode("AddBookToShelf", ["GetBookFromBasket"]);
23
23
 
24
- const filePath = resolve(__dirname, "./simple_design_temp.json")
24
+
25
+ d.removeNode("GetBookFromBasket");
26
+
27
+ const filePath = resolve(__dirname, "./temp/simple_design_temp.json")
25
28
  await writeFile(filePath, d.serialize())
26
29
 
27
30
  // Output can be viewed using https://mermaid.live/
@@ -1 +0,0 @@
1
- {"uid":"0f4433c4-abd7-43da-96e3-6809863c93ab","type":5,"nodes":[{"uid":"1b0751a9-c46e-4fa6-ae7f-cf6204fdd83b","type":6,"goToBehaviorsIds":["AcceptBookFromUser"],"behavior":{"uid":"e336a950-f89c-43a6-b3c4-09df32f64831","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AcceptChoiceToAddBookToBasket"}},{"uid":"deb11624-0fae-4d1b-9d22-d421dea1d712","type":6,"goToBehaviorsIds":["AddBookToBasket"],"behavior":{"uid":"65b253bb-c4f2-4dee-8f36-648f73b3300c","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AcceptBookFromUser"}},{"uid":"f914f2c9-86e3-4c54-a926-b6c9c425cf9f","type":6,"goToBehaviorsIds":[],"behavior":{"uid":"76b6962c-24b1-4999-9719-5ac2e4f1c022","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AddBookToBasket"}},{"uid":"84912fd4-c193-4b7d-ad62-cdc6b254d529","type":6,"goToBehaviorsIds":["GenerateAuditReport"],"behavior":{"uid":"76f3d5a5-2e64-4bea-8beb-70d0d38e0645","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AcceptChoiceToAuditLibrary"}},{"uid":"4056410c-37c5-4ffa-8766-2ecd7a079617","type":6,"goToBehaviorsIds":["HandAuditToUser"],"behavior":{"uid":"f6a6e7d4-0151-4881-8d57-fb327620fd4a","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"GenerateAuditReport"}},{"uid":"e6de6529-7d64-40f4-8787-c0e1c1c324eb","type":6,"goToBehaviorsIds":[],"behavior":{"uid":"8a3efec4-1068-4ee5-b66d-715bcc7b6d79","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"HandAuditToUser"}},{"uid":"91b71f6c-e384-4c31-9d39-4eae95e61872","type":6,"goToBehaviorsIds":["GetBookFromBasket"],"behavior":{"uid":"9caee137-24b9-4314-b5a7-e4a7f6e93256","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AcceptChoiceToPlaceBooksOnShelf"}},{"uid":"4ea36149-15cf-4e6d-8770-cfd6bdc9645d","type":6,"goToBehaviorsIds":["GetFirstLetterOfBookName"],"behavior":{"uid":"1477b094-eb0a-4c2c-88b2-35ba99155f1e","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"GetBookFromBasket"}},{"uid":"bd6116de-8cd9-41b2-a256-fab5d979d80e","type":6,"goToBehaviorsIds":["CreateSlotOnBookShelf","AddBookToShelf"],"behavior":{"uid":"36b0483d-d831-4478-a34e-c091db38370d","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"GetFirstLetterOfBookName"}},{"uid":"54948771-65b7-40cb-8331-85f5b7d6cbf1","type":6,"goToBehaviorsIds":["AddBookToShelf"],"behavior":{"uid":"1fcd8aa4-6f25-4406-a0bc-ba43912ec572","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"CreateSlotOnBookShelf"}},{"uid":"ff292a3c-e556-44de-9a47-9510ef0910e4","type":6,"goToBehaviorsIds":["GetBookFromBasket"],"behavior":{"uid":"b736147d-faf3-4718-86c2-a2e8ffa8fb51","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AddBookToShelf"}}]}