Skip to content

Commit

Permalink
v5.11.1: history bug fix
Browse files Browse the repository at this point in the history
  • Loading branch information
mesmo committed Aug 11, 2017
1 parent f0b19e1 commit 7b2ad18
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 63 deletions.
3 changes: 3 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## Version 5.11.1
Fix a bug that caused history semantics to be followed when reentering a region that did not have history defined.

## Version 5.11.0
Fix bug in transtions originating from pseudo states that cross composite state boundaries; this necessitates the following breaking changes:
* Make IInstance.setCurrent and IInstance.getCurrent set and get the last known Vertex for a given Region (was State previously);
Expand Down
6 changes: 0 additions & 6 deletions lib/README.md

This file was deleted.

9 changes: 2 additions & 7 deletions lib/node/state.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
// Type definitions for state.js
// Project: state,js
// Definitions by: David Mesquita-Morris <http://state.software>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped

/**
* Finite state machine library
* Copyright (c) 2014-6 David Mesquita-Morris
Expand Down Expand Up @@ -270,15 +265,15 @@ export declare class StateMachine extends State {
*/
export declare class Transition {
readonly source: Vertex;
readonly target: Vertex;
readonly target: Vertex | undefined;
readonly kind: TransitionKind;
/**
* Creates a new instance of the [[Transition]] class.
* @param source The source [[Vertex]] of the [[Transition]].
* @param source The target [[Vertex]] of the [[Transition]]; this is an optional parameter, omitting it will create an [[Internal]] [[Transition]].
* @param kind The kind the [[Transition]]; use this to set [[Local]] or [[External]] (the default if omitted) transition semantics.
*/
constructor(source: Vertex, target?: Vertex, kind?: TransitionKind);
constructor(source: Vertex, target?: Vertex | undefined, kind?: TransitionKind);
/**
* Turns a [[Transition]] into an else transition.
* Else [[Transitions]]s can be used at [[Junction]] or [[Choice]] [[PseudoState]] if no other [[Transition]] guards evaluate true, an else [[Transition]] if present will be traversed.
Expand Down
40 changes: 22 additions & 18 deletions lib/node/state.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
"use strict";
/**
* Finite state machine library
* Copyright (c) 2014-6 David Mesquita-Morris
* Licensed under the MIT and GPL v3 licences
* http://state.software
*/
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
/**
* An enumeration used to dictate the behavior of instances of the [[PseudoState]] class.
*
Expand Down Expand Up @@ -92,10 +98,10 @@ var NamedElement = (function (_super) {
NamedElement.prototype.toString = function () {
return this.qualifiedName;
};
/** The symbol used to separate [[NamedElement]] names within a fully qualified name. Change this static member to create different styles of qualified name generated by the [[toString]] method. */
NamedElement.namespaceSeparator = ".";
return NamedElement;
}(Element));
/** The symbol used to separate [[NamedElement]] names within a fully qualified name. Change this static member to create different styles of qualified name generated by the [[toString]] method. */
NamedElement.namespaceSeparator = ".";
exports.NamedElement = NamedElement;
/**
* An [[NamedElement]] within a [[StateMachine]] model that is a container (parent) of [[Vertex]] instances; a [[Region]] will be the child of a composite [[State]].
Expand Down Expand Up @@ -138,10 +144,10 @@ var Region = (function (_super) {
Region.prototype.accept = function (visitor, arg1) {
return visitor.visitRegion(this, arg1);
};
/** The name given to [[Region]] instances implicitly created (when a [[State]] instance is passed to a [[Vertex]] constructor as it's parent. */
Region.defaultName = "default";
return Region;
}(NamedElement));
/** The name given to [[Region]] instances implicitly created (when a [[State]] instance is passed to a [[Vertex]] constructor as it's parent. */
Region.defaultName = "default";
exports.Region = Region;
/** An abstract [[NamedElement]] within a [[StateMachine]] model that can be the source or target of a [[Transition]]. */
var Vertex = (function (_super) {
Expand Down Expand Up @@ -920,7 +926,7 @@ exports.evaluate = evaluate;
/** @internal */ var InitialiseTransitions = (function (_super) {
__extends(InitialiseTransitions, _super);
function InitialiseTransitions() {
return _super.apply(this, arguments) || this;
return _super !== null && _super.apply(this, arguments) || this;
}
InitialiseTransitions.prototype.visitTransition = function (transition, behavior) {
// reset transition behavior
Expand Down Expand Up @@ -1011,7 +1017,7 @@ exports.evaluate = evaluate;
/** @internal */ var InitialiseElements = (function (_super) {
__extends(InitialiseElements, _super);
function InitialiseElements() {
var _this = _super.apply(this, arguments) || this;
var _this = _super !== null && _super.apply(this, arguments) || this;
/** @internal */ _this.behaviors = {};
return _this;
}
Expand Down Expand Up @@ -1062,12 +1068,10 @@ exports.evaluate = evaluate;
// evaluate comppletion transitions once vertex entry is complete
if (pseudoState.isInitial()) {
this.behavior(pseudoState).endEnter.push(function (message, instance, deepHistory) {
if (instance.getLastKnownState(pseudoState.parent)) {
var currentState;
if ((deepHistory || pseudoState.isHistory()) && (currentState = instance.getLastKnownState(pseudoState.parent))) {
invoke(_this.behavior(pseudoState).leave, message, instance);
var currentState = instance.getLastKnownState(pseudoState.parent);
if (currentState) {
invoke(_this.behavior(currentState).enter(), message, instance, deepHistory || pseudoState.kind === PseudoStateKind.DeepHistory);
}
invoke(_this.behavior(currentState).enter(), message, instance, deepHistory || pseudoState.kind === PseudoStateKind.DeepHistory);
}
else {
traverse(pseudoState.outgoing[0], instance);
Expand Down Expand Up @@ -1156,7 +1160,7 @@ exports.validate = validate;
/** @internal */ var Validator = (function (_super) {
__extends(Validator, _super);
function Validator() {
return _super.apply(this, arguments) || this;
return _super !== null && _super.apply(this, arguments) || this;
}
/** Validates a [[PseudoState]]. */
Validator.prototype.visitPseudoState = function (pseudoState) {
Expand Down
40 changes: 22 additions & 18 deletions lib/web/state.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
"use strict";
/**
* Finite state machine library
* Copyright (c) 2014-6 David Mesquita-Morris
* Licensed under the MIT and GPL v3 licences
* http://state.software
*/
"use strict";
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
exports.__esModule = true;
/**
* An enumeration used to dictate the behavior of instances of the [[PseudoState]] class.
*
Expand Down Expand Up @@ -93,10 +99,10 @@ var NamedElement = (function (_super) {
NamedElement.prototype.toString = function () {
return this.qualifiedName;
};
/** The symbol used to separate [[NamedElement]] names within a fully qualified name. Change this static member to create different styles of qualified name generated by the [[toString]] method. */
NamedElement.namespaceSeparator = ".";
return NamedElement;
}(Element));
/** The symbol used to separate [[NamedElement]] names within a fully qualified name. Change this static member to create different styles of qualified name generated by the [[toString]] method. */
NamedElement.namespaceSeparator = ".";
exports.NamedElement = NamedElement;
/**
* An [[NamedElement]] within a [[StateMachine]] model that is a container (parent) of [[Vertex]] instances; a [[Region]] will be the child of a composite [[State]].
Expand Down Expand Up @@ -139,10 +145,10 @@ var Region = (function (_super) {
Region.prototype.accept = function (visitor, arg1) {
return visitor.visitRegion(this, arg1);
};
/** The name given to [[Region]] instances implicitly created (when a [[State]] instance is passed to a [[Vertex]] constructor as it's parent. */
Region.defaultName = "default";
return Region;
}(NamedElement));
/** The name given to [[Region]] instances implicitly created (when a [[State]] instance is passed to a [[Vertex]] constructor as it's parent. */
Region.defaultName = "default";
exports.Region = Region;
/** An abstract [[NamedElement]] within a [[StateMachine]] model that can be the source or target of a [[Transition]]. */
var Vertex = (function (_super) {
Expand Down Expand Up @@ -921,7 +927,7 @@ exports.evaluate = evaluate;
/** @internal */ var InitialiseTransitions = (function (_super) {
__extends(InitialiseTransitions, _super);
function InitialiseTransitions() {
return _super.apply(this, arguments) || this;
return _super !== null && _super.apply(this, arguments) || this;
}
InitialiseTransitions.prototype.visitTransition = function (transition, behavior) {
// reset transition behavior
Expand Down Expand Up @@ -1012,7 +1018,7 @@ exports.evaluate = evaluate;
/** @internal */ var InitialiseElements = (function (_super) {
__extends(InitialiseElements, _super);
function InitialiseElements() {
var _this = _super.apply(this, arguments) || this;
var _this = _super !== null && _super.apply(this, arguments) || this;
/** @internal */ _this.behaviors = {};
return _this;
}
Expand Down Expand Up @@ -1063,12 +1069,10 @@ exports.evaluate = evaluate;
// evaluate comppletion transitions once vertex entry is complete
if (pseudoState.isInitial()) {
this.behavior(pseudoState).endEnter.push(function (message, instance, deepHistory) {
if (instance.getLastKnownState(pseudoState.parent)) {
var currentState;
if ((deepHistory || pseudoState.isHistory()) && (currentState = instance.getLastKnownState(pseudoState.parent))) {
invoke(_this.behavior(pseudoState).leave, message, instance);
var currentState = instance.getLastKnownState(pseudoState.parent);
if (currentState) {
invoke(_this.behavior(currentState).enter(), message, instance, deepHistory || pseudoState.kind === PseudoStateKind.DeepHistory);
}
invoke(_this.behavior(currentState).enter(), message, instance, deepHistory || pseudoState.kind === PseudoStateKind.DeepHistory);
}
else {
traverse(pseudoState.outgoing[0], instance);
Expand Down Expand Up @@ -1157,7 +1161,7 @@ exports.validate = validate;
/** @internal */ var Validator = (function (_super) {
__extends(Validator, _super);
function Validator() {
return _super.apply(this, arguments) || this;
return _super !== null && _super.apply(this, arguments) || this;
}
/** Validates a [[PseudoState]]. */
Validator.prototype.visitPseudoState = function (pseudoState) {
Expand Down
2 changes: 1 addition & 1 deletion lib/web/state.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "state.js",
"version": "5.11.0",
"version": "5.11.1",
"author": "David Mesquita-Morris",
"contributors": [
"David Mesquita-Morris"
Expand Down
5 changes: 0 additions & 5 deletions src/header.d.ts

This file was deleted.

11 changes: 4 additions & 7 deletions src/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1221,14 +1221,11 @@ export function evaluate(model: StateMachine, instance: IInstance, message: any,
// evaluate comppletion transitions once vertex entry is complete
if (pseudoState.isInitial()) {
this.behavior(pseudoState).endEnter.push((message, instance, deepHistory) => {
if (instance.getLastKnownState(pseudoState.parent)) {
invoke(this.behavior(pseudoState).leave, message, instance);

const currentState = instance.getLastKnownState(pseudoState.parent);
let currentState: State | undefined;

if (currentState) {
invoke(this.behavior(currentState).enter(), message, instance, deepHistory || pseudoState.kind === PseudoStateKind.DeepHistory);
}
if ((deepHistory || pseudoState.isHistory()) && (currentState = instance.getLastKnownState(pseudoState.parent))) {
invoke(this.behavior(pseudoState).leave, message, instance);
invoke(this.behavior(currentState).enter(), message, instance, deepHistory || pseudoState.kind === PseudoStateKind.DeepHistory);
} else {
traverse(pseudoState.outgoing[0], instance);
}
Expand Down
64 changes: 64 additions & 0 deletions test/second-pass.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* global describe, it */
var assert = require("assert"),
state = require("../lib/node/state");

state.setConsole(console);

// States
const model = new state.StateMachine("model");
const initial = new state.PseudoState("initial", model, state.PseudoStateKind.Initial);
const identify = new state.State("identify", model);
const exception_1 = new state.State("exception_1", model);
const model_pass = new state.State("model_pass", model);
const model_fail = new state.State("model_fail", model);

const A = new state.State("A", model);
const A_initial = new state.PseudoState("A_initial", A, state.PseudoStateKind.Initial);
const A_1 = new state.State("A_1", A);
const A_2 = new state.State("A_2", A);
const A_3 = new state.State("A_3", A);
const A_4 = new state.State("A_4", A);
const A_pass = new state.State("A_pass", A);
const A_fail = new state.State("A_fail", A);

// Transitions
initial.to(identify);
identify.to(exception_1).when((message) => message === "Continue");

exception_1.to(identify).when((message) => message === "Yes");
exception_1.to(A).when((message) => message === "No");
exception_1.to(model_fail).when((message) => message === "Unsure");

A_initial.to(A_1);

A_1.to(A_2).when((message) => message === "Yes");
A_1.to(A_fail).when((message) => /No|Unsure/.test(message));

A_2.to(A_pass).when((message) => message === "Yes");
A_2.to(A_3).when((message) => message === "No");
A_2.to(A_fail).when((message) => message === "Unsure");

A_3.to(A_pass).when((message) => message === "Yes");
A_3.to(A_4).when((message) => message === "No");
A_3.to(A_fail).when((message) => message === "Unsure");

A_4.to(A_pass).when((message) => message === "Yes");
A_4.to(A_fail).when((message) => /No|Unsure/.test(message));

A_pass.to(model_pass);
A_fail.to(model_fail);

model_pass.to(identify);
model_fail.to(identify);

var instance = new state.StateMachineInstance("second-pass");

state.initialise(model, instance);

// Transitions
state.evaluate(model, instance, "Continue");
state.evaluate(model, instance, "No", "first time");
state.evaluate(model, instance, "Yes");
state.evaluate(model, instance, "Yes");
state.evaluate(model, instance, "Continue");
state.evaluate(model, instance, "No", "second time");

0 comments on commit 7b2ad18

Please sign in to comment.