Skip to content

Commit

Permalink
Move to TS4
Browse files Browse the repository at this point in the history
  • Loading branch information
StoneCypher committed Jan 14, 2021
1 parent bc60d8c commit f19deb1
Show file tree
Hide file tree
Showing 16 changed files with 8,787 additions and 4,428 deletions.
7 changes: 7 additions & 0 deletions dist/es6/jssm-dot.nonmin.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion dist/es6/jssm.d.ts
@@ -1,5 +1,6 @@
declare type StateType = string;
import { JssmGenericState, JssmGenericConfig, JssmTransition, JssmTransitionList, JssmMachineInternalState, JssmParseTree, JssmStateDeclaration, JssmArrow, JssmArrowDirection, JssmArrowKind, JssmLayout, FslDirection, FslTheme } from './jssm_types';
import { JssmGenericState, JssmGenericConfig, JssmTransition, JssmTransitionList, // JssmTransitionRule,
JssmMachineInternalState, JssmParseTree, JssmStateDeclaration, JssmArrow, JssmArrowDirection, JssmArrowKind, JssmLayout, FslDirection, FslTheme } from './jssm_types';
import { seq, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key } from './jssm_util';
import { parse } from './jssm-dot';
import { version } from './version';
Expand Down
130 changes: 118 additions & 12 deletions dist/es6/jssm.js
@@ -1,7 +1,9 @@
// whargarbl lots of these return arrays could/should be sets
import { reduce as reduce_to_639 } from 'reduce-to-639-1';
import { seq, weighted_rand_select, weighted_sample_select, histograph, weighted_histo_key, array_box_if_string } from './jssm_util';
import { parse } from './jssm-dot';
import { version } from './version';
import { parse } from './jssm-dot'; // TODO FIXME WHARGARBL this could be post-typed
import { version } from './version'; // replaced from package.js in build // TODO FIXME currently broken
/* eslint-disable complexity */
function arrow_direction(arrow) {
switch (String(arrow)) {
case '->':
Expand Down Expand Up @@ -53,6 +55,8 @@ function arrow_direction(arrow) {
throw new Error(`arrow_direction: unknown arrow type ${arrow}`);
}
}
/* eslint-enable complexity */
/* eslint-disable complexity */
function arrow_left_kind(arrow) {
switch (String(arrow)) {
case '->':
Expand Down Expand Up @@ -93,6 +97,8 @@ function arrow_left_kind(arrow) {
throw new Error(`arrow_direction: unknown arrow type ${arrow}`);
}
}
/* eslint-enable complexity */
/* eslint-disable complexity */
function arrow_right_kind(arrow) {
switch (String(arrow)) {
case '<-':
Expand Down Expand Up @@ -133,6 +139,7 @@ function arrow_right_kind(arrow) {
throw new Error(`arrow_direction: unknown arrow type ${arrow}`);
}
}
/* eslint-enable complexity */
function makeTransition(this_se, from, to, isRight, _wasList, _wasIndex) {
const kind = isRight ? arrow_right_kind(this_se.kind) : arrow_left_kind(this_se.kind), edge = {
from,
Expand All @@ -141,6 +148,19 @@ function makeTransition(this_se, from, to, isRight, _wasList, _wasIndex) {
forced_only: kind === 'forced',
main_path: kind === 'main'
};
// if ((wasList !== undefined) && (wasIndex === undefined)) { throw new TypeError("Must have an index if transition was in a list"); }
// if ((wasIndex !== undefined) && (wasList === undefined)) { throw new TypeError("Must be in a list if transition has an index"); }
/*
if (typeof edge.to === 'object') {
if (edge.to.key === 'cycle') {
if (wasList === undefined) { throw "Must have a waslist if a to is type cycle"; }
const nextIndex = wrapBy(wasIndex, edge.to.value, wasList.length);
edge.to = wasList[nextIndex];
}
}
*/
const action = isRight ? 'r_action' : 'l_action', probability = isRight ? 'r_probability' : 'l_probability';
if (this_se[action]) {
edge.action = this_se[action];
Expand Down Expand Up @@ -230,7 +250,7 @@ function compile(tree) {
machine_version: []
};
tree.map((tr) => {
const rule = compile_rule_handler(tr), agg_as = rule.agg_as, val = rule.val;
const rule = compile_rule_handler(tr), agg_as = rule.agg_as, val = rule.val; // TODO FIXME no any
results[agg_as] = results[agg_as].concat(val);
});
const assembled_transitions = [].concat(...results['transition']);
Expand Down Expand Up @@ -294,6 +314,7 @@ function transfer_state_properties(state_decl) {
return state_decl;
}
class Machine {
// whargarbl this badly needs to be broken up, monolith master
constructor({ start_states, complete = [], transitions, machine_author, machine_comment, machine_contributor, machine_definition, machine_language, machine_license, machine_name, machine_version, state_declaration, fsl_version, dot_preamble = undefined, arrange_declaration = [], arrange_start_declaration = [], arrange_end_declaration = [], theme = 'default', flow = 'down', graph_layout = 'dot' }) {
this._state = start_states[0];
this._states = new Map();
Expand All @@ -303,7 +324,7 @@ class Machine {
this._named_transitions = new Map();
this._actions = new Map();
this._reverse_actions = new Map();
this._reverse_action_targets = new Map();
this._reverse_action_targets = new Map(); // todo
this._machine_author = array_box_if_string(machine_author);
this._machine_comment = machine_comment;
this._machine_contributor = array_box_if_string(machine_contributor);
Expand All @@ -323,7 +344,7 @@ class Machine {
this._graph_layout = graph_layout;
if (state_declaration) {
state_declaration.map((state_decl) => {
if (this._state_declarations.has(state_decl.state)) {
if (this._state_declarations.has(state_decl.state)) { // no repeats
throw new Error(`Added the same state declaration twice: ${JSON.stringify(state_decl.state)}`);
}
this._state_declarations.set(state_decl.state, transfer_state_properties(state_decl));
Expand All @@ -336,6 +357,7 @@ class Machine {
if (tr.to === undefined) {
throw new Error(`transition must define 'to': ${JSON.stringify(tr)}`);
}
// get the cursors. what a mess
const cursor_from = this._states.get(tr.from)
|| { name: tr.from, from: [], to: [], complete: complete.includes(tr.from) };
if (!(this._states.has(tr.from))) {
Expand All @@ -346,15 +368,18 @@ class Machine {
if (!(this._states.has(tr.to))) {
this._new_state(cursor_to);
}
// guard against existing connections being re-added
if (cursor_from.to.includes(tr.to)) {
throw new Error(`already has ${JSON.stringify(tr.from)} to ${JSON.stringify(tr.to)}`);
}
else {
cursor_from.to.push(tr.to);
cursor_to.from.push(tr.from);
}
// add the edge; note its id
this._edges.push(tr);
const thisEdgeId = this._edges.length - 1;
// guard against repeating a transition name
if (tr.name) {
if (this._named_transitions.has(tr.name)) {
throw new Error(`named transition "${JSON.stringify(tr.name)}" already created`);
Expand All @@ -363,13 +388,17 @@ class Machine {
this._named_transitions.set(tr.name, thisEdgeId);
}
}
// set up the mapping, so that edges can be looked up by endpoint pairs
const from_mapping = this._edge_map.get(tr.from) || new Map();
if (!(this._edge_map.has(tr.from))) {
this._edge_map.set(tr.from, from_mapping);
}
from_mapping.set(tr.to, thisEdgeId);
// const to_mapping = from_mapping.get(tr.to);
from_mapping.set(tr.to, thisEdgeId); // already checked that this mapping doesn't exist, above
// set up the action mapping, so that actions can be looked up by origin
if (tr.action) {
let actionMap = this._actions.get(tr.action);
// forward mapping first by action name
let actionMap = this._actions.get(tr.action); // TODO FIXME ?Map equiv
if (!(actionMap)) {
actionMap = new Map();
this._actions.set(tr.action, actionMap);
Expand All @@ -380,15 +409,32 @@ class Machine {
else {
actionMap.set(tr.from, thisEdgeId);
}
let rActionMap = this._reverse_actions.get(tr.from);
// reverse mapping first by state origin name
let rActionMap = this._reverse_actions.get(tr.from); // TODO FIXME ?Map equiv
if (!(rActionMap)) {
rActionMap = new Map();
this._reverse_actions.set(tr.from, rActionMap);
}
// no need to test for reverse mapping pre-presence;
// forward mapping already covers collisions
rActionMap.set(tr.action, thisEdgeId);
// reverse mapping first by state target name
if (!(this._reverse_action_targets.has(tr.to))) {
this._reverse_action_targets.set(tr.to, new Map());
}
/* todo comeback
fundamental problem is roActionMap needs to be a multimap
const roActionMap = this._reverse_action_targets.get(tr.to); // wasteful - already did has - refactor
if (roActionMap) {
if (roActionMap.has(tr.action)) {
throw new Error(`ro-action ${tr.to} already attached to action ${tr.action}`);
} else {
roActionMap.set(tr.action, thisEdgeId);
}
} else {
throw new Error('should be impossible - flow doesn\'t know .set precedes .get yet again. severe error?');
}
*/
}
});
}
Expand All @@ -402,10 +448,18 @@ class Machine {
state() {
return this._state;
}
/* whargarbl todo major
when we reimplement this, reintroduce this change to the is_final call
is_changing(): boolean {
return true; // todo whargarbl
}
*/
state_is_final(whichState) {
return ((this.state_is_terminal(whichState)) && (this.state_is_complete(whichState)));
}
is_final() {
// return ((!this.is_changing()) && this.state_is_final(this.state()));
return this.state_is_final(this.state());
}
graph_layout() {
Expand Down Expand Up @@ -458,10 +512,16 @@ class Machine {
edges: this._edges,
named_transitions: this._named_transitions,
reverse_actions: this._reverse_actions,
// reverse_action_targets : this._reverse_action_targets,
state: this._state,
states: this._states
};
}
/*
load_machine_state(): boolean {
return false; // todo whargarbl
}
*/
states() {
return Array.from(this._states.keys());
}
Expand Down Expand Up @@ -562,6 +622,15 @@ class Machine {
throw new Error(`No such state ${JSON.stringify(whichState)}`);
}
}
// comeback
/*
list_entrance_actions(whichState: mNT = this.state() ) : Array<mNT> {
return [... (this._reverse_action_targets.get(whichState) || new Map()).values()] // wasteful
.map( (edgeId:any) => (this._edges[edgeId] : any)) // whargarbl burn out any
.filter( (o:any) => o.to === whichState)
.map( filtered => filtered.from );
}
*/
list_exit_actions(whichState = this.state()) {
const ra_base = this._reverse_actions.get(whichState);
if (!(ra_base)) {
Expand All @@ -584,6 +653,7 @@ class Machine {
probability: filtered.probability
}));
}
// TODO FIXME test that is_unenterable on non-state throws
is_unenterable(whichState) {
if (!(this.has_state(whichState))) {
throw new Error(`No such state ${whichState}`);
Expand All @@ -596,6 +666,7 @@ class Machine {
is_terminal() {
return this.state_is_terminal(this.state());
}
// TODO FIXME test that state_is_terminal on non-state throws
state_is_terminal(whichState) {
if (!(this.has_state(whichState))) {
throw new Error(`No such state ${whichState}`);
Expand All @@ -621,6 +692,9 @@ class Machine {
return this.states().some((x) => this.state_is_complete(x));
}
action(name, newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
if (this.valid_action(name, newData)) {
const edge = this.current_action_edge_for(name);
this._state = edge.to;
Expand All @@ -631,6 +705,9 @@ class Machine {
}
}
transition(newState, newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
if (this.valid_transition(newState, newData)) {
this._state = newState;
return true;
Expand All @@ -639,7 +716,11 @@ class Machine {
return false;
}
}
// can leave machine in inconsistent state. generally do not use
force_transition(newState, newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
if (this.valid_force_transition(newState, newData)) {
this._state = newState;
return true;
Expand All @@ -660,9 +741,15 @@ class Machine {
return this._edges[idx];
}
valid_action(action, _newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
return this.current_action_for(action) !== undefined;
}
valid_transition(newState, _newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
const transition_for = this.lookup_transition_for(this.state(), newState);
if (!(transition_for)) {
return false;
Expand All @@ -673,13 +760,32 @@ class Machine {
return true;
}
valid_force_transition(newState, _newData) {
// todo whargarbl implement hooks
// todo whargarbl implement data stuff
// todo major incomplete whargarbl comeback
return (this.lookup_transition_for(this.state(), newState) !== undefined);
}
sm(template_strings, ...remainder) {
/* eslint-disable no-use-before-define */
/* eslint-disable class-methods-use-this */
sm(template_strings, ...remainder /* , arguments */) {
return sm(template_strings, ...remainder);
}
}
function sm(template_strings, ...remainder) {
return new Machine(make(template_strings.reduce((acc, val, idx) => `${acc}${remainder[idx - 1]}${val}`)));
function sm(template_strings, ...remainder /* , arguments */) {
// foo`a${1}b${2}c` will come in as (['a','b','c'],1,2)
// this includes when a and c are empty strings
// therefore template_strings will always have one more el than template_args
// therefore map the smaller container and toss the last one on on the way out
return new Machine(make(template_strings.reduce(
// in general avoiding `arguments` is smart. however with the template
// string notation, as designed, it's not really worth the hassle
/* eslint-disable fp/no-arguments */
/* eslint-disable prefer-rest-params */
(acc, val, idx) => `${acc}${remainder[idx - 1]}${val}` // arguments[0] is never loaded, so args doesn't need to be gated
/* eslint-enable prefer-rest-params */
/* eslint-enable fp/no-arguments */
)));
}
export { version, transfer_state_properties, Machine, make, parse, compile, sm, arrow_direction, arrow_left_kind, arrow_right_kind, seq, weighted_rand_select, histograph, weighted_sample_select, weighted_histo_key };
export { version, transfer_state_properties, Machine, make, parse, compile, sm, arrow_direction, arrow_left_kind, arrow_right_kind,
// WHARGARBL TODO these should be exported to a utility library
seq, weighted_rand_select, histograph, weighted_sample_select, weighted_histo_key };
1 change: 1 addition & 0 deletions dist/es6/jssm_types.js
@@ -0,0 +1 @@
export {};
23 changes: 16 additions & 7 deletions dist/es6/jssm_util.js
@@ -1,4 +1,6 @@
const array_box_if_string = n => typeof n === 'string' ? [n] : n;
// this is explicitly about other peoples' data, so it has to be weakly typed
/* eslint-disable flowtype/no-weak-types */
const weighted_rand_select = (options, probability_property = 'probability') => {
if (!Array.isArray(options)) {
throw new TypeError('options must be a non-empty array of objects');
Expand All @@ -8,15 +10,22 @@ const weighted_rand_select = (options, probability_property = 'probability') =>
}
const frand = (cap) => Math.random() * cap, or_one = (item) => item === undefined ? 1 : item, prob_sum = options.reduce((acc, val) => acc + or_one(val[probability_property]), 0), rnd = frand(prob_sum);
let cursor = 0, cursor_sum = 0;
while ((cursor_sum += or_one(options[cursor++][probability_property])) <= rnd) { }
while ((cursor_sum += or_one(options[cursor++][probability_property])) <= rnd) { } // eslint-disable-line no-empty,fp/no-loops
return options[cursor - 1];
};
/* eslint-enable flowtype/no-weak-types */
const seq = (n) => (new Array(n)).fill(true)
.map((_, i) => i);
const histograph = (ar) => ar.sort()
.reduce((m, v) => (m.set(v, (m.has(v) ? m.get(v) + 1 : 1)), m), new Map());
const weighted_sample_select = (n, options, probability_property) => seq(n)
.map((_i) => weighted_rand_select(options, probability_property));
const weighted_histo_key = (n, opts, prob_prop, extract) => histograph(weighted_sample_select(n, opts, prob_prop)
.map((s) => s[extract]));
const histograph = (ar) => // eslint-disable-line flowtype/no-weak-types
ar.sort()
.reduce((m, v) => // TODO FIXME eslint-disable-line flowtype/no-weak-types,no-sequences
(m.set(v, (m.has(v) ? m.get(v) + 1 : 1)), m), new Map());
const weighted_sample_select = (n, options, probability_property) => // TODO FIXME no any // eslint-disable-line flowtype/no-weak-types
seq(n)
.map((_i) => // TODO FIXME eslint-disable-line flowtype/no-weak-types
weighted_rand_select(options, probability_property));
const weighted_histo_key = (n, opts, prob_prop, extract) => // TODO FIXME no any // eslint-disable-line flowtype/no-weak-types
histograph(weighted_sample_select(n, opts, prob_prop)
.map((s) => s[extract] // TODO FIXME eslint-disable-line flowtype/no-weak-types
));
export { seq, histograph, weighted_histo_key, weighted_rand_select, weighted_sample_select, array_box_if_string };
2 changes: 1 addition & 1 deletion dist/es6/version.js
@@ -1,2 +1,2 @@
const version = "5.32.20";
const version = "5.33.0";
export { version };
2 changes: 1 addition & 1 deletion dist/jssm.es5.cjs.js

Large diffs are not rendered by default.

0 comments on commit f19deb1

Please sign in to comment.