Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: adds a 'class' attribute #135

Merged
merged 7 commits into from
Jan 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dcignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/**/*-parser.js
66 changes: 66 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,72 @@ What does 'experimental' mean?
> or in a shade smartly derived? Or should I include a bunch of color attributes
> (e.g. fillcolor, textcolor, textbgcolor) for ultimate control?

#### classes

As of version 7.4.0 you can use the keyword `class` as an extended keyword on
both states and transitions. When you render `svg` or `dot` you'll see what you
entered there in the output in the `class` attributes of their respective
elements, along with the type of element (either 'state' or 'transition') and
optionally the type of state or transtion (e.g. for state: 'initial', 'regular',
'final' etc.).

For example, this ...

```smcat
a [class="dismissed"],
b [class="y"];

a => b [class="a bunch of classes"];
```

... will yield this 'dot' program ...

```graphviz
digraph "state transitions" {
fontname="Helvetica" fontsize=12 penwidth=2.0 splines=true ordering=out compound=true overlap=scale nodesep=0.3 ranksep=0.1
node [shape=plaintext style=filled fillcolor="#FFFFFF01" fontname=Helvetica fontsize=12 penwidth=2.0]
edge [fontname=Helvetica fontsize=10]

"a" [margin=0 class="state regular dismissed" label= <
<table align="center" cellborder="0" border="2" style="rounded" width="48">
<tr><td width="48" cellpadding="7">a</td></tr>
</table>
>]
"b" [margin=0 class="state regular y" label= <
<table align="center" cellborder="0" border="2" style="rounded" width="48">
<tr><td width="48" cellpadding="7">b</td></tr>
</table>
>]

"a" -> "b" [label=" " class="transition a bunch of classes"]
}
```

Which will pass the class attributes on to the svg like so. E.g. the svg snippet
for the `a` state will look like this:

```svg
<!-- ... -->
<g id="node1" class="node state regular dismissed">
<title>a</title>
<polygon fill="#ffffff" fill-opacity="0.003922" stroke="transparent" stroke-width="2" points="56,-100 0,-100 0,-64 56,-64 56,-100"></polygon>
<text text-anchor="start" x="24.6646" y="-78.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">a</text>
<path fill="none" stroke="#000000" stroke-width="2" d="M12.3333,-65C12.3333,-65 43.6667,-65 43.6667,-65 49.3333,-65 55,-70.6667 55,-76.3333 55,-76.3333 55,-87.6667 55,-87.6667 55,-93.3333 49.3333,-99 43.6667,-99 43.6667,-99 12.3333,-99 12.3333,-99 6.6667,-99 1,-93.3333 1,-87.6667 1,-87.6667 1,-76.3333 1,-76.3333 1,-70.6667 6.6667,-65 12.3333,-65"></path>
</g>
<!-- ... -->
```

#### Gotchas

- You will have to provide the style sheet defining the classes yourself in the
context where you render the svg in order for them to actually show up
- The characters you can use for class names is limited to alpha-numerics, dashes,
underscores - and spaces to separate them. This to make it harder to use
state-machine-cat to construct svg's that are either invalid or malicious. The
limited character set is in contrast to what css allows, which is
[everything under the sun and then some](https://mathiasbynens.be/notes/css-escapes) -
but it seems like a reasonable compromise.

### overriding the type of a state

As you read above, _state machine cat_ derives the type of a state from its name.
Expand Down
1,111 changes: 725 additions & 386 deletions docs/dev/smcat-online-interpreter.bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/dev/smcat-online-interpreter.bundle.js.map

Large diffs are not rendered by default.

1,111 changes: 725 additions & 386 deletions docs/dev/state-machine-cat-inpage.bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/dev/state-machine-cat-inpage.bundle.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/smcat-online-interpreter.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/smcat-online-interpreter.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/state-machine-cat-inpage.min.js

Large diffs are not rendered by default.

19 changes: 10 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "state-machine-cat",
"version": "7.3.0",
"version": "7.4.0-beta-2",
"description": "write beautiful state charts",
"main": "src/index.js",
"scripts": {
Expand All @@ -9,15 +9,16 @@
"build:cli": "make cli-build",
"check": "run-p --aggregate-output depcruise lint test:cover",
"depcruise": "depcruise --output-type err-long --config config/dependency-cruiser.js src test bin/smcat",
"depcruise:graph": "run-s depcruise:graph:*",
"depcruise:graph:archi-html": "depcruise --output-type archi --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg | depcruise-wrap-stream-in-html > docs/dependency-cruiser-archi-graph.html",
"depcruise:graph:archi-svg": "depcruise --output-type archi --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg > docs/dependency-cruiser-archi-graph.svg",
"depcruise:graph:dir-html": "depcruise --output-type ddot --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg | depcruise-wrap-stream-in-html > docs/dependency-cruiser-dir-graph.html",
"depcruise:graph:dir-svg": "depcruise --output-type ddot --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg > docs/dependency-cruiser-dir-graph.svg",
"depcruise:graph:deps-html": "depcruise --output-type dot --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg | depcruise-wrap-stream-in-html > docs/dependency-cruiser-graph.html",
"depcruise:graph:deps-svg": "depcruise --output-type dot --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg > docs/dependency-cruiser-graph.svg",
"depcruise:graph": "run-s depcruise:graph:doc:*",
"depcruise:graph:doc:archi-html": "depcruise --output-type archi --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg | depcruise-wrap-stream-in-html > docs/dependency-cruiser-archi-graph.html",
"depcruise:graph:doc:archi-svg": "depcruise --output-type archi --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg > docs/dependency-cruiser-archi-graph.svg",
"depcruise:graph:doc:dir-html": "depcruise --output-type ddot --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg | depcruise-wrap-stream-in-html > docs/dependency-cruiser-dir-graph.html",
"depcruise:graph:doc:dir-svg": "depcruise --output-type ddot --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg > docs/dependency-cruiser-dir-graph.svg",
"depcruise:graph:doc:deps-html": "depcruise --output-type dot --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg | depcruise-wrap-stream-in-html > docs/dependency-cruiser-graph.html",
"depcruise:graph:doc:deps-svg": "depcruise --output-type dot --config config/dependency-cruiser-graph.js src bin/smcat | dot -Tsvg > docs/dependency-cruiser-graph.svg",
"depcruise:html-report": "depcruise --output-type err-html --config config/dependency-cruiser.js src test bin/smcat --output-to dependency-violation-report.html",
"depcruise:view": "depcruise --output-type dot --config config/dependency-cruiser-graph.js --prefix vscode://file/$(pwd)/ src bin/smcat | dot -Tsvg | depcruise-wrap-stream-in-html | browser",
"depcruise:graph:dev": "depcruise --output-type dot --config config/dependency-cruiser-graph.js --prefix vscode://file/$(pwd)/ src bin/smcat | dot -Tsvg | depcruise-wrap-stream-in-html | browser",
"depcruise:graph:dev:flat": "depcruise --output-type flat --config config/dependency-cruiser-graph.js --prefix vscode://file/$(pwd)/ src bin/smcat | circo -Tsvg | depcruise-wrap-stream-in-html | browser",
"depcruise:view-report": "depcruise --output-type err-html --config config/dependency-cruiser.js --prefix vscode://file/$(pwd)/ src test bin/smcat | browser",
"lint": "run-p --aggregate-output lint:eslint lint:prettier lint:types",
"lint:eslint": "eslint --cache --cache-location .cache src test config",
Expand Down
14 changes: 13 additions & 1 deletion src/parse/smcat-ast.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "state-machine-cat abstract syntax tree schema",
"$ref": "#/definitions/StateMachineType",
"$id": "org.js.state-machine-cat/v5.4.0",
"$id": "org.js.state-machine-cat/v7.4.0",
"definitions": {
"StateType": {
"type": "string",
Expand Down Expand Up @@ -44,6 +44,10 @@
"body": { "type": "string" }
}
},
"ClassType": {
"type": "string",
"pattern": "^[a-zA-Z0-9_\\- ]*$"
},
"StateMachineType": {
"type": "object",
"additionalProperties": false,
Expand Down Expand Up @@ -72,6 +76,10 @@
"description": "Color to use for rendering the state. Accepts all css color names (\"blue\") and hex notation - with (\"#0000FF77\") or without (\"#0000FF\") transparency.",
"type": "string"
},
"class": {
"description": "Class name to give the state in dot and svg output.",
"$ref": "#/definitions/ClassType"
},
"active": {
"description": "If true the state is considered to be active and rendered as such.",
"type": "boolean"
Expand Down Expand Up @@ -139,6 +147,10 @@
"description": "Color to use for rendering the transition. Accepts all css color names (\"blue\") and hex notation - with (\"#0000FF77\") or without (\"#0000FF\") transparency.",
"type": "string"
},
"class": {
"description": "Class name to give the state in dot and svg output.",
"$ref": "#/definitions/ClassType"
},
"type": {
"description": "Whether the transition is external (default) or internal. See https://www.w3.org/TR/scxml/#transition for details.",
"$ref": "#/definitions/TransitionType"
Expand Down
28 changes: 24 additions & 4 deletions src/parse/smcat/peg/smcat-parser.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ extended_state_attribute "extended state attribute"
{
return {name, value};
}
/ _ name:class_attribute_name _ "=" _ value:class_string _
{
return {name, value}
}
/ _ name:extended_state_boolean_attribute_name _
{
return {name, value:true}
Expand All @@ -83,6 +87,12 @@ extended_state_string_attribute_name "state attribute name"
return name.toLowerCase();
}

class_attribute_name "class attribute"
= name:("class"i)
{
return name.toLowerCase();
}

extended_state_boolean_attribute_name "state flag"
= name:("active"i)
{
Expand Down Expand Up @@ -157,20 +167,24 @@ extended_transition_attribute "extended transition attribute"
= _ name:extended_transition_string_attribute_name _ "=" _ value:quotedstring _
{
return {name, value};
} /
_ name:(extended_transition_type_name) _ "=" _ value:extended_transition_type_value _
}
/ _ name:class_attribute_name _ "=" _ value:class_string _
{
return {name, value};
}
/ _ name:(extended_transition_type_name) _ "=" _ value:extended_transition_type_value _
{
return {name, value};
}

extended_transition_string_attribute_name "transition attribute name"
= name:( "color"i)
= name:("color"i)
{
return name.toLowerCase();
}

extended_transition_type_name "transition type name"
= name:( "type"i)
= name:("type"i)
{
return name.toLowerCase();
}
Expand Down Expand Up @@ -216,6 +230,12 @@ quotedstring "double quoted string"
stringcontent
= (!'"' c:('\\"'/ .) {return c})*

class_string "valid class string"
= '"' s:class_stringcontent '"' {return s.join("")}

class_stringcontent
= (!'"' c:([a-zA-Z0-9_\- ]) {return c})*

unquotedtransitionstring
= s:transitionnonsep {return s.join("").trim()}

Expand Down
Loading