Closed j2l closed 2 years ago
Bonjour Philippe,
yEd is about the best diagramming tools out there for modeling, and I tried many. I am glad you like it.
What do you want to achieve? You want to:
If you want to keep the same edge label grammar, then you don't need to change the yedEdgeLabelGrammar.ne
. That grammar is pretty simple and is as follows:
MAIN -> OneTransitionLabel {% d => d[0] %}
| MultipleTransitionLabel {% d => d[0] %}
MultipleTransitionLabel -> ("|" OneTransitionLabel):+ {% d => d[0].map(x => x[1]) %}
OneTransitionLabel ->
EventClause "[" GuardClause "]" _ "/" ActionsClause {% d => ({event: d[0], guard: d[2], actions: d[6]}) %}
| EventClause "[" GuardClause "]" _ {% d => ({event: d[0], guard: d[2], actions: []}) %}
| EventClause "/" ActionsClause {% d => ({event: d[0], guard: [], actions: d[2]}) %}
| EventClause {% d => ({event: d[0], guard: [], actions: []}) %}
| "[" GuardClause "]" _ "/" ActionsClause {% d => ({event: "", guard: d[1], actions: d[5]}) %}
| "/" ActionsClause {% d => ({event: "", guard: [], actions: d[1]}) %}
| "[" GuardClause "]" {% d => ({event: "", guard: d[1], actions: []}) %}
EventClause -> [^\/\[\]\|,]:+ {% d => d[0].join('') %}
GuardClause -> Guard ("," Guard):* {% d => [d[0]].concat(d[1].map(dd => dd[1])) %}
Guard -> [^\[\],]:* {% d => (d[0] || []).join('') %}
ActionsClause -> Action ("," Action):* {% d => [d[0]].concat(d[1].map(dd => dd[1])) %}
Action -> [^\/\|\[\]\(\),]:* ActionsComments:* {% d => (d[0] || []).join('') %}
ActionsComments -> "(" __ ")" _
StringLiteral -> [\w]:+
_ -> [\s]:*
__ -> [^()]:*
This file contains both a description of the label grammar with an eBNF-like syntax and instructions to convert a parse tree into an abstract syntax tree (the %d =>...
). You can play with it in the Nearley playground. Simply copy paste that grammar into the playground. Type some edge label on the input field in the right, and you will see the results of the parsing. .ne
denotes a Nearly extension. Nearley is the parser I use here. It is not the fastest parser but it is the most user-friendly (playground, ambiguity tolerance, etc.). The .ne
file is compiled to a .js
file that does the actual parsing. So Nearley is in fact a parser generator. It takes a language description file (.ne
) and generates a parser (.js
) with a CLI (cf. Nearley documentation).
If you want to change the output, then you need to modify index.js
. Namely you probably should write new code starting there. You should be able to use what is before: the parsing logic, the file reading and writing, and the data transformations. What you will have to change is the compiledContents
.
I hope that helps.
Tell me more about you want to do. If I understand your use case, I am happy to support you into generating your Svelte code. And also, you can speak French if that's better for you :-)
Bonjour ! Are you also French? I don't mind continuing writing in English to help others (use case through SEO) for the moment. I might switch to French if it goes deep though.
Thank you very much for all this information. OK, let's go ideal: I'd like to design in yED, and push a big red button (or a command line like slim or yed2kingly) to:
XState tried various javascript platforms (https://xstate.js.org/docs/recipes/svelte.html) and a particular svelte demo is pretty self explanatory about the diagram+code: https://github.com/kyrianda/svelte-xstate-inspect-plantuml/ But it totally lacks the awesomeness of designing in a robust (and so great at automatic layouts) diagramming solution like yED.
BTW, did you know you can start building yED diagrams from a table? https://yed.yworks.com/support/manual/import_excel.html This helps drafting big diagrams and avoid labeling mistakes for connections.
I do understand the French language :-) But yes English may be better. So:
Otherwise:
The great with state machines is that you don't really have to look at the code anymore. And if you keep it simple like Kingly tries to do, there is not much to learn and visualize. Anyways, I may try to turn the react-state-driven
@j2l I just realized I already did a Svelte integration: https://github.com/brucou/svelte-machine-component :-)
Just that I did not document it. It is 60 lines of code, so not too hard to understand, but I should write a proper documentation for it. I may take advantage from your interest to refresh the implementation and document it. I don't really remember what I did there, that was two years ago and apparently I never used it - it is just so simple with Svelte to directly used the machine in a component that making a wrapper does not have so many advantages.
Hihi, I also forget what I did a few years ago. Thank you! I'll take time to study this. Rapidly, it seems complicated, maybe because of svelte back.
Yeah it took me a while to get into it. This uses Svelte slot props which is a bit of a convoluted feature in any template language (e.g., same applies to Vue or Angular). So basically it goes like this:
<Machine commandHandlers initEvent fsm let:dispatch={dispatch}/>
fsm
: the machine created by Kingly's createStateMachine factory. That factory can be imported from the JavaScript compiled from yEd. Sth like import {createStateMachine}
from yourYedCompiledFileHere.js
.`commandHandlers
: a POJO that maps every one of its properties to a command handler that, well, handle the matching command. For instance {FETCH_THIS: function fetch (dispatch, params) {fetch that thing; return something}}
initEvent
: the initial event to send to the machine. It is optional but generally you want to do that to get something to display the when the component mounts.How does this work?
let:dispatch
let you bind a dispatch
variable that can be used inside of the <Machine />
component. E.g:
<Machine commandHandlers=... initEvent=... fsm=... let:dispatch={dispatch}>
<button on:click="{e => dispatch(SOME_EVENT, some params computed from e, }" .../>
</Machine>
<button/>
)SOME_EVENT
event to the machine. The machine computes some commands. Those commands are matched to the corresponding command handler. The matching command handler is executed with the following parameters: commandHandler (dispatch, some params computed from e)
. Because the command handler is passed the dispatcher, it can also send events to the machine. For instance when the FETCH_THIS requests fails or succeeds, the command handler can send FETCHED_OK or FAILED_FETCH events to the machine.If you have a concrete example to use this with, I can guide you through how to do it. Just let me know. But again, I think that inlining works best, and that's probably why I did not publish this component in the end.
Hello! OK, I'm back to svelte and fsm. I hope you had time to finalize tests :smile:
As I wanted a real-life example to run svelte from, I started with the password fsm.
I successfully generated the password-meter.graphml.js
password-meter.graphml.fsm.js.zip
I tried to add the js file from the doc (https://codesandbox.io/s/mqx96pm64j?from-embed=&file=/src/index.js) and the basic html (div app) and import it as svelte component import KinglyPassword from "./kinglyPassword.svelte";
I adapted the INIT_SCREEN:
const INIT_SCREEN = `
<section>
<label for="password">Enter password</label>
<input
type="password"
name="password"
id="password"
onkeyup="${inputEventHandler}"
/>
<meter max="4" id="password-strength-meter"></meter>
<p id="password-strength-text"></p>
<button onclick="${buttonEventHandler}">Submit</button>
</section>
`;
But it never shows up (maybe because svelte needs @html?) I have no error in the console though, just the Kingly messages.
Maybe using the JS example is not the best way to make it work?
Si I tried another way I understand that, in App.svelte, I'll need:
import { NO_OUTPUT } from "kingly";
import emitonoff from "emitonoff";
import {
events,
states,
getKinglyTransitions,
createStateMachineFromGraph,
} from "../password-meter.graphml.fsm.js";
let commandHandlers, effectHandlers;
let initEvent = {};
let fsm = createStateMachineFromGraph(events, states, getKinglyTransitions);
But then, I don't know what to add to reach something like:
<Machine commandHandlers=... initEvent=... fsm=... let:dispatch={dispatch}></Machine>
Great to hear that you are back to Svelte and fsm :-) I will add a Svelte example for the password meter (hopefully tonight) to the documentation. We can then take it from there and address any questions you may have. What do you think?
Yes, if you could use the graph js file I attached, it's perfect!
@j2l I made a copy paste of the Vue implementation of the password meter, and converted it to Svelte. Quick and dirty but there it is: https://codesandbox.io/s/inspiring-wright-tdrxk?file=/App.svelte
Will have a look at your password-meter.graphml...js file tomorrow. But generally speaking, and reviewing our exchange from the beginning, I was telling you that abstracting the fsm into a component resulted in somewhat convoluted code with Svelte and that directly using the code was not a bad option. Cf. code comments, I will abstract a bit more the code tomorrow.
Going to bed!
This is great! Thank you! Can't wait for a yed to svelte FSM to happen.
Here is the version with the event handler logic abstracted: https://codesandbox.io/s/fast-breeze-9736z?file=/App.svelte.
As you can see the abstraction is a 3-liner. That is very much how I would use Kingly fsm with Svelte. Abstracting with a <Machine>
component, while seemingly attractive, is not the best option in my opinion with Svelte.
I realize that I still haven't looked at your file :-) Will do tomorrow. But you see that once you have your machine exported (that's fsm.js
), it does not matter how you created that machine (with createStateMachineFromGraph
, or from the slim
compiler, or directly written by you).
More tomorrow
Well I did it now https://codesandbox.io/s/billowing-currying-0jlkr?file=/fsm.js
Gotchas:
properties.js
must match the ones you used in the yed file)createStateMachineFromGraph
. Cf. fsm.js
fsm.js
. That's how I was able to put back in properties.js
the right values for the events.Wow! Trop bien !
Thank you soooo much for delivering so fast and perfectly. I really appreciate you took the challenge. I'll study this ASAP. Closing.
Excellente journée à toi !!!
Merci, si tu as d'autres questions, tu me dis. Je vais ptet actualiser la docs et rajouter Svelte quand meme.
Ca marche, merci encore.
Hello, Your approach from diagram to code is fantastic! I'm discovering state machines but know yED. Thank you! What would be need to generate enhanced javascript code like react, vue, svelte? (the later is very close to javascript) Adapt by hand yedEdgeLabelGrammar.ne and js? Something else? Thank you!