Comparing version 0.2.0 to 0.3.0
@@ -11,2 +11,3 @@ #!/usr/bin/env node | ||
var asl_puml_1 = require("../src/asl-puml"); | ||
var types_1 = require("../src/lib/types"); | ||
function doneValid() { | ||
@@ -24,2 +25,3 @@ process.exit(0); | ||
.option("-o --output <output>", "path to output") | ||
.option("-c --config <config>", "path to config file") | ||
.parse(process.argv); | ||
@@ -29,3 +31,6 @@ try { | ||
var definition = JSON.parse(fs_1.default.readFileSync(opts.input, "utf-8")); | ||
var response = (0, asl_puml_1.asl_to_puml)(definition); | ||
var config = opts.config | ||
? JSON.parse(fs_1.default.readFileSync(opts.config, "utf-8")) | ||
: types_1.DefaultConfig; | ||
var response = (0, asl_puml_1.asl_to_puml)(definition, config); | ||
if (response.isValid) { | ||
@@ -32,0 +37,0 @@ var dir = opts.output |
@@ -10,12 +10,17 @@ "use strict"; | ||
var validator_1 = require("./lib/validator"); | ||
var asl_to_puml = function (definition) { | ||
var config_1 = require("./lib/config"); | ||
var asl_to_puml = function (definition, userSpecifiedConfig) { | ||
(0, validator_1.aslValidator)(definition); | ||
var state_map = (0, build_state_map_1.build_state_map)(definition); | ||
// we know the definition is valid at this point | ||
var puml = (0, theme_1.theme)(definition, state_map); | ||
puml += (0, decls_1.decls)(definition, state_map); | ||
puml += (0, transitions_1.transitions)(definition, state_map); | ||
puml += (0, footer_1.footer)(definition, state_map); | ||
var response = (0, config_1.toConfig)(userSpecifiedConfig); | ||
if (!response.isValid) { | ||
return { isValid: false, message: response.message }; | ||
} | ||
var config = response.config; | ||
var state_map = (0, build_state_map_1.build_state_map)(definition, config); | ||
var puml = (0, theme_1.theme)(definition, state_map, config); | ||
puml += (0, decls_1.decls)(definition, state_map, config); | ||
puml += (0, transitions_1.transitions)(definition, state_map, config); | ||
puml += (0, footer_1.footer)(definition, state_map, config); | ||
return { isValid: true, puml: puml }; | ||
}; | ||
exports.asl_to_puml = asl_to_puml; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.must = void 0; | ||
exports.assertStateHints = exports.must = void 0; | ||
var must = function (nullable) { | ||
@@ -10,1 +10,7 @@ if (!nullable) { | ||
exports.must = must; | ||
var assertStateHints = function (stateHints) { | ||
if (!stateHints) { | ||
throw Error("state not found"); | ||
} | ||
}; | ||
exports.assertStateHints = assertStateHints; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.build_state_map = exports.assertStateHints = void 0; | ||
exports.build_state_map = void 0; | ||
var jsonpath_plus_1 = require("jsonpath-plus"); | ||
var types_1 = require("./types"); | ||
var assertStateHints = function (stateHints) { | ||
if (!stateHints) { | ||
throw Error("state not found"); | ||
} | ||
}; | ||
exports.assertStateHints = assertStateHints; | ||
var compute_stereotype = function (stateName, hints) { | ||
var assertions_1 = require("./assertions"); | ||
var compute_stereotype = function (stateName, hints, config) { | ||
if (hints.json.Type === types_1.AslStateType.Choice) { | ||
return "<<Choice>>"; | ||
} | ||
// todo - move this to a config | ||
var compensatePattern = /compensate/iu; | ||
var compensatePattern = new RegExp(config.theme.compensation.pattern, "iu"); | ||
if (compensatePattern.test(stateName)) { | ||
@@ -26,3 +20,3 @@ return "<<Compensate>>"; | ||
}; | ||
var build_state_map = function (definition) { | ||
var build_state_map = function (definition, config) { | ||
var state_map = new Map(); | ||
@@ -56,5 +50,5 @@ var id = 1; | ||
var child_value = state_map.get(stateName); | ||
(0, exports.assertStateHints)(child_value); | ||
(0, assertions_1.assertStateHints)(child_value); | ||
child_value.parent = key; | ||
child_value.stereotype = compute_stereotype(stateName, child_value); | ||
child_value.stereotype = compute_stereotype(stateName, child_value, config); | ||
}); | ||
@@ -78,3 +72,3 @@ }); | ||
var child_value = state_map.get(stateName); | ||
(0, exports.assertStateHints)(child_value); | ||
(0, assertions_1.assertStateHints)(child_value); | ||
child_value.parent = key; | ||
@@ -87,3 +81,3 @@ }); | ||
state_map.forEach(function (hints, stateName) { | ||
hints.stereotype = compute_stereotype(stateName, hints); | ||
hints.stereotype = compute_stereotype(stateName, hints, config); | ||
}); | ||
@@ -90,0 +84,0 @@ return state_map; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.theme = void 0; | ||
var theme = function () { | ||
return "@startuml\nhide empty description\nskinparam LineBackgroundColor #black\nskinparam ArrowColor #black\nskinparam state {\n BackgroundColor<<aslFail>> #red\n FontColor<<aslFail>> #white\n\n BackgroundColor<<aslTask>> #lightblue\n BackgroundColor<<Compensate>> #orange\n\n BackgroundColor<<aslSucceed>> #green\n FontColor<<aslSucceed>> #white\n}\n"; | ||
var types_1 = require("./types"); | ||
var jsonpath_plus_1 = require("jsonpath-plus"); | ||
var theme = function (definition, state_map, config) { | ||
var emitStateStyle = function (stateType) { | ||
var _a, _b; | ||
switch (stateType) { | ||
case types_1.AslStateType.Choice: | ||
return "\n BackgroundColor<<Choice>> ".concat(config.theme.states.Choice.BackgroundColor, "\n FontColor<<Choice>> ").concat((_a = config.theme.states.Choice.FontColor) !== null && _a !== void 0 ? _a : "automatic"); | ||
case types_1.AslStateType.Parallel: | ||
case types_1.AslStateType.Map: | ||
return "\n BackgroundColor<<asl".concat(stateType, ">> ").concat(config.theme.states[stateType].BackgroundColor); | ||
case types_1.AslStateType.Fail: | ||
case types_1.AslStateType.Pass: | ||
case types_1.AslStateType.Succeed: | ||
case types_1.AslStateType.Wait: | ||
case types_1.AslStateType.Task: | ||
return "\n BackgroundColor<<asl".concat(stateType, ">> ").concat(config.theme.states[stateType].BackgroundColor, "\n FontColor<<asl").concat(stateType, ">> ").concat((_b = config.theme.states[stateType].FontColor) !== null && _b !== void 0 ? _b : "automatic"); | ||
default: { | ||
var invalid = stateType; | ||
throw Error("invalid state type: ".concat(JSON.stringify(invalid))); | ||
} | ||
} | ||
}; | ||
var all_used_states = new Set(); | ||
var found = (0, jsonpath_plus_1.JSONPath)({ | ||
path: "$..States.*.Type", | ||
json: definition, | ||
}); | ||
found.forEach(function (used_state) { return all_used_states.add(used_state); }); | ||
var isStateTypeUsed = function (stateType) { | ||
return all_used_states.has(stateType); | ||
}; | ||
return "@startuml\nhide empty description\nskinparam ArrowColor ".concat(config.theme.skinparams.ArrowColor, "\nskinparam state {\n").concat([ | ||
types_1.AslStateType.Choice, | ||
types_1.AslStateType.Fail, | ||
types_1.AslStateType.Map, | ||
types_1.AslStateType.Parallel, | ||
types_1.AslStateType.Pass, | ||
types_1.AslStateType.Succeed, | ||
types_1.AslStateType.Task, | ||
types_1.AslStateType.Wait, | ||
] | ||
.filter(function (stateType) { return isStateTypeUsed(stateType); }) | ||
.map(function (stateType) { return emitStateStyle(stateType); }) | ||
.join("\n"), "\n BackgroundColor<<Compensate>> ").concat(config.theme.compensation.color, "\n}\n"); | ||
}; | ||
exports.theme = theme; |
@@ -5,7 +5,10 @@ "use strict"; | ||
var jsonpath_plus_1 = require("jsonpath-plus"); | ||
var build_state_map_1 = require("./build_state_map"); | ||
var transitions = function (definition, state_map) { | ||
var assertions_1 = require("./assertions"); | ||
var transitions = function (definition, state_map, config) { | ||
var catchTransitions = new Set(); | ||
// start w/ some whitespace | ||
var lines = [""]; | ||
var lineFromStyle = function (lineConfig) { | ||
return "-[".concat(lineConfig.bold ? "bold," : "").concat(lineConfig.color, "]->"); | ||
}; | ||
var emit_transition_with_color = function (args) { | ||
@@ -19,7 +22,7 @@ var srcHint = args.srcHint, targetHint = args.targetHint, extraHints = args.extraHints; | ||
RHS = "state".concat(targetHint.id); | ||
transitionLine = "-[#pink]->"; | ||
transitionLine = lineFromStyle(config.theme.lines.toFail); | ||
} | ||
else if (targetHint && (extraHints === null || extraHints === void 0 ? void 0 : extraHints.fromCatch)) { | ||
RHS = "state".concat(targetHint.id); | ||
transitionLine = "-[bold,#orange]->"; | ||
transitionLine = lineFromStyle(config.theme.lines.fromCatch); | ||
} | ||
@@ -38,3 +41,3 @@ else if (targetHint && srcHint.json.Type === "Choice") { | ||
RHS = "[*]"; | ||
transitionLine = "-[#pink]->"; | ||
transitionLine = lineFromStyle(config.theme.lines.toFail); | ||
} | ||
@@ -54,3 +57,3 @@ else if (!targetHint && srcHint.parent === null) { | ||
var head = state_map.get(definition.StartAt); | ||
(0, build_state_map_1.assertStateHints)(head); | ||
(0, assertions_1.assertStateHints)(head); | ||
lines.push("[*] --> state".concat(head.id)); | ||
@@ -67,3 +70,3 @@ // emit transition for each state to its Next/Default | ||
var targetHint = state_map.get(target.Next); | ||
(0, build_state_map_1.assertStateHints)(targetHint); | ||
(0, assertions_1.assertStateHints)(targetHint); | ||
var label = ""; | ||
@@ -83,3 +86,3 @@ if (target.StringEquals) { | ||
var targetHint = state_map.get(hints.json.Default); | ||
(0, build_state_map_1.assertStateHints)(targetHint); | ||
(0, assertions_1.assertStateHints)(targetHint); | ||
emit_transition_with_color({ srcHint: hints, targetHint: targetHint }); | ||
@@ -90,3 +93,3 @@ } | ||
var targetHint = state_map.get(hints.json.Next); | ||
(0, build_state_map_1.assertStateHints)(targetHint); | ||
(0, assertions_1.assertStateHints)(targetHint); | ||
emit_transition_with_color({ srcHint: hints, targetHint: targetHint }); | ||
@@ -108,5 +111,5 @@ } | ||
var catchTargetHints = state_map.get(katch.Next); | ||
(0, build_state_map_1.assertStateHints)(catchTargetHints); | ||
(0, assertions_1.assertStateHints)(catchTargetHints); | ||
if (catchTargetHints.json.Type === "Fail") { | ||
lines.push("state".concat(hints.id, " -[#pink]-> state").concat(catchTargetHints.id)); | ||
lines.push("state".concat(hints.id, " ").concat(lineFromStyle(config.theme.lines.toFail), " state").concat(catchTargetHints.id)); | ||
} | ||
@@ -113,0 +116,0 @@ else { |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.AslStateType = void 0; | ||
exports.DefaultConfig = exports.AslStateType = void 0; | ||
var AslStateType; | ||
@@ -15,1 +15,47 @@ (function (AslStateType) { | ||
})(AslStateType = exports.AslStateType || (exports.AslStateType = {})); | ||
exports.DefaultConfig = { | ||
theme: { | ||
skinparams: { | ||
ArrowColor: "#black", | ||
}, | ||
states: { | ||
Pass: { | ||
BackgroundColor: "#whitesmoke", | ||
}, | ||
Map: { | ||
BackgroundColor: "#whitesmoke", | ||
}, | ||
Choice: { | ||
BackgroundColor: "#whitesmoke", | ||
}, | ||
Parallel: { | ||
BackgroundColor: "#whitesmoke", | ||
}, | ||
Wait: { | ||
BackgroundColor: "#whitesmoke", | ||
}, | ||
Task: { | ||
BackgroundColor: "#lightblue", | ||
}, | ||
Fail: { | ||
BackgroundColor: "#red", | ||
}, | ||
Succeed: { | ||
BackgroundColor: "#green", | ||
}, | ||
}, | ||
lines: { | ||
fromCatch: { | ||
bold: true, | ||
color: "#orange", | ||
}, | ||
toFail: { | ||
color: "#pink", | ||
}, | ||
}, | ||
compensation: { | ||
pattern: "^.*(compensate).*$", | ||
color: "#orange", | ||
}, | ||
}, | ||
}; |
{ | ||
"name": "asl-puml", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "Generates a plant uml file from a valid ASL file", | ||
@@ -52,2 +52,3 @@ "main": "./dist/asl-puml.js", | ||
"dependencies": { | ||
"ajv": "^8.11.0", | ||
"asl-validator": "^2.2.0", | ||
@@ -54,0 +55,0 @@ "commander": "^9.3.0", |
101
README.md
@@ -14,3 +14,3 @@ # asl-puml | ||
The existing tools are good but I'm looking for a simpler rendering that encodes a little more info than the AWS Toolkit. | ||
The existing tools are good, but I'm looking for a simpler rendering that encodes a little more info than the AWS Toolkit. | ||
@@ -30,15 +30,79 @@ I also do all of my development in an IDE and don't want to switch to the browser based AWS Workflow Studio. | ||
| <br/><br/><br/>Feature or Style | asl-puml | AWS Toolkit | AWS Workflow Studio | | ||
|-----------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------| | ||
| renders the step function as a state diagram |  |  |  | | ||
| diagram matches the style seen in AWS Console for instance executions | :x: | :white_check_mark: | :x: | | ||
| renders the step function within Webstorm or other JetBrains products | :white_check_mark:, via the existing plantuml plugin | :x:, not in [AWS Toolkit for Webstorm](https://aws.amazon.com/webstorm/) | :x: | | ||
| renders the step function within VS Code | :white_check_mark:, via the existing plantuml plugin | :white_check_mark:, available in [AWS Toolkit for VS Code](https://aws.amazon.com/visualstudiocode/) | :x: | | ||
| conveys the behavior for the state | :white_check_mark:, via colors and some icons | :x: | :white_check_mark:, very familiar AWS icons and colors. | | ||
| avoid drawing duplicate paths to reduce clutter (catches) | :white_check_mark: | :white_check_mark: | :x:, all paths are drawn | | ||
| identify the compensate path | :white_check_mark:, albeit hard coded by state name regex | :x: | :x: | | ||
| label the state transition if conditional | :white_check_mark:, limited support with StringEquals | :x: | :white_check_mark:, expression is shown in a note on the line | | ||
| label the path from a catch | :white_check_mark:, with line weight and color | :x: | :white_check_mark:, path is labeled with a Catch | | ||
| label the path to a Fail state | :white_check_mark:, with line weight and color | :x: | :x: | | ||
| <br/><br/><br/>Feature or Style Requirement | asl-puml | AWS Toolkit | AWS Workflow Studio | | ||
|-----------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------| | ||
| renders the step function as a state diagram |  |  |  | | ||
| conveys the behavior for the state | :white_check_mark:, via colors and some icons | :x: | :white_check_mark:, very familiar AWS icons and colors. | | ||
| matches the style for instance executions | :x: | :white_check_mark: | :x: | | ||
| renders within Webstorm/JetBrains products | :white_check_mark:, via the existing plantuml plugin | :x:, not in [AWS Toolkit for Webstorm](https://aws.amazon.com/webstorm/) | :x: | | ||
| renders the step function within VS Code | :white_check_mark:, via the existing plantuml plugin | :white_check_mark:, available in [AWS Toolkit for VS Code](https://aws.amazon.com/visualstudiocode/) | :x: | | ||
| label the path from a catch | :white_check_mark:, with line weight and color | :x: | :white_check_mark:, path is labeled with a Catch | | ||
| label the path to a Fail state | :white_check_mark:, with line weight and color | :x: | :x: | | ||
| identify the compensation path | :white_check_mark:, albeit hard coded by state name regex | :x: | :x: | | ||
| label the state transition if conditional | :white_check_mark:, limited support with StringEquals | :x: | :white_check_mark:, expression is shown in a note on the line | | ||
| avoid drawing duplicate paths to reduce clutter (catches) | :white_check_mark: | :white_check_mark: | :x:, all paths are drawn | | ||
### Compensation Path | ||
The term "compensate" is borrowed from [business processes](http://docs.oasis-open.org/wsbpel/2.0/OS/wsbpel-v2.0-OS.html#_Toc164738526) where it refers to the undoing of work as part of handling a fault. | ||
When reviewing a process, it's useful to identify which parts of the process are in service of the happy path | ||
versus those in the compensation path. | ||
Currently, the library uses a regex to match on the state's name to decide if it's in the compensation path. This will | ||
be made configurable as part of the theme. There isn't a good way to determine the compensation path without hints from | ||
the config. | ||
### Configuration | ||
A user supplied file that conforms to the config-schema.json type can be provided to control the diagram theme. | ||
```json | ||
{ | ||
"theme": { | ||
"skinparams": { | ||
"ArrowColor": "#black" | ||
}, | ||
"states": { | ||
"Pass": { | ||
"BackgroundColor": "#whitesmoke" | ||
}, | ||
"Map": { | ||
"BackgroundColor": "#whitesmoke" | ||
}, | ||
"Choice": { | ||
"BackgroundColor": "#whitesmoke" | ||
}, | ||
"Parallel": { | ||
"BackgroundColor": "#whitesmoke" | ||
}, | ||
"Wait": { | ||
"BackgroundColor": "#whitesmoke" | ||
}, | ||
"Task": { | ||
"BackgroundColor": "#lightblue" | ||
}, | ||
"Fail": { | ||
"BackgroundColor": "#red" | ||
}, | ||
"Succeed": { | ||
"BackgroundColor": "#green" | ||
} | ||
}, | ||
"lines": { | ||
"fromCatch": { | ||
"bold": true, | ||
"color": "#orange" | ||
}, | ||
"toFail": { | ||
"color": "#pink" | ||
} | ||
}, | ||
"compensation": { | ||
"pattern": "^.*(compensate).*$", | ||
"color": "#orange" | ||
} | ||
} | ||
} | ||
``` | ||
## Install | ||
@@ -67,2 +131,3 @@ ```bash | ||
-o --output <output> path to output dir | ||
-c --config <config> path to config file | ||
-h, --help display help for command | ||
@@ -86,12 +151,2 @@ ``` | ||
## Test | ||
```bash | ||
npm run test | ||
``` | ||
## Lint | ||
```bash | ||
npm run lint | ||
``` | ||
## See also | ||
@@ -98,0 +153,0 @@ - [ASL specifications](https://states-language.net/spec.html) |
41687
19
808
155
4
+ Addedajv@^8.11.0
+ Addedajv@8.17.1(transitive)
+ Addedfast-uri@3.0.6(transitive)
+ Addedjson-schema-traverse@1.0.0(transitive)
+ Addedrequire-from-string@2.0.2(transitive)