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

[Question] What are the main files responsible for generating an app's views, through ifmlEdit? #38

Open
AlexandroDRK opened this issue May 26, 2023 · 6 comments
Labels

Comments

@AlexandroDRK
Copy link

@B3rn475 I've been studying the structure and behavior of ifmlEdit, in order to understand the entire flow of its operation, and despite the project being well organized and with very lean functions, it is so well structured that the abstraction of certain functionalities is not so easy. I have a hunch which files are responsible for the ifml transformation rules for the views code, but I would like to be more sure. If possible, could you explain to me or provide me with some kind of existing documentation related to this functionality. As I mentioned, I intend to add rules for generating interface test scripts for Cypress, but I need to understand as much as possible how the interfaces themselves are built based on a IFML model.

@B3rn475
Copy link
Owner

B3rn475 commented May 29, 2023

Hi.

First of all, you should take a look at https://github.com/B3rn475/almostjs which is the Model-to-"Anything" framework that is used by the project.

  • ALMOsT-Core provides a basic "map from a JavaScript object to any number of other object" framework with a highly customizable "reducer".
  • ALMOsT-Extend gives you, if you follow some simple rules in structuring your Model, a set of helpers to navigate the model. The main requirement is that your model is organized as a set of elements connected to each other via relationships.
  • ALMOsT builds on top of ALMOsT-Core, following the rules from ALMOsT-Extend, and privides you a simple way to write rules that apply to specific elements or relationships in your model (a.k.a. rules) and provides you somer default aggregators, i.e. Model To Model, Model To Almost (if you follow a specific structure the reducer can do more for you) or Model To Text. One nice property is that you can easily chain transformation.

The main concept you need to know about is "there are different types or Rules".

  • Model Rules they apply once for the whole mode.
  • Element Rules they apply once for each element in the model.
  • Relation Rules they apply once for each relationship betwen elements in the model.

There are a few papers linked in the ALMOsT repository.

IFMLEdit.org uses these libraries as follows:

  • client/js/ifml/index.js exposes an extend() function that is the ALMOsT-Extend extender configured with common concepts from IFML.
  • In client/js/ifml2pcn you will find a Model To Model (technically Model To Almost) transformation that generates a PCN model from an IFML model.
  • In client/js/ifml2code you will find 4 different transformations
    • client generates a thick client implementation of the application, with the ability to implement data sorces and actions either locally or invoking REST APIs, or a bit of both.
    • server generates a server implementation of the application, with the ability to implement data sources and actions server-side; the thin client always routes requests to the server.
    • mobile is similar to client, but focuses on a more mobile oriented design.
    • flutter [beta] is similar to mobile, but generates Flutter code, instead of JavaScript.

All of them follow a Model To Text approach, see m2t tranformation in ALMOsT.
TL;DR: the model generates folders and files which are then stored inside a Zip file.

These generators generally use Model Rules to generate global files that cannot be mapped to a specific element. E.g. the package.json file is always going to be there, or, in general, it is related to the entire model and not to a specific element or relationship.
They, instead, use Element Rules to generate files that are specific to an element, e.g. in client/js/ifml2code/client/elementrules/action.js there is a Rule that generates, for each action, a file implementing it.
There are no Relation Rules in these transformation only because the IFML model used here stores the Flows as entities, so, up to now, Element Rules were enough, but depending on what you need to do you may want to use them.

From a practical standpoint the Model Rules are stored in .../modelrules.js, while Element Rules are stored in the file of element they match against, e.g. ...elementrules/action.js focuses on Actions, while .../elementrules/viewcontainer.js on ViewContainers, ...

Taking a deeper dive into the rules you will notice that they are split into 2 functions. The first one decides if the rule applies, by returning a boolean, while the second actually generates the files/folders needed.

For practical purposes rules are generally implemented in 2 phases:

  1. Compute all the data needed to generate the files/folders.
  2. Generate
    • Folders are generated by just adding an element in the output object
    • Files are similar, but require the "content". To generate the content we invoke an ejs script that is implement in the .../templates folder next to it. We try to keep the templates as simple and linear as possible, if some complex decision needs to be made, we prefer to perform it in step (1) and just inject the information.

Now back to what you want to do

Depending on what you care about you may want to use either .../client or .../server as your starting point.
You probably want to add a new folder and copy the modelrules.js so that you can customize it.
Unless you have some specific requirement to alter the existing generated code, you can directly use the existing .../modelrules/*.js files and templates, this will guarantee that the generated files will be the same, and just add a few extra rules to generate the additional files/folder for Cypress.

If your rules are simple and easy to write, you could probably be happy already here.

But if you are having troubles...

How you can manage complexity

Depending on the complexity of what you want to do, you may even want to split your transformation in multiple stages.

Reasoning directly on IFML may be complicated in some cases.

A simple, but meaningful example.

You want to write a Model-to-Text transformation that generates SQL files needed to build a DB starting from an Entity-Relationship model.

If the original meta-model supports N-to-M relationships you cannot easily convert it directly in SQL, so it could be complicated to write the rules.

If you have the guarantee that you will only have 1-to-N relationships, the Model-to-Text transformation is way easier, right?

You can make your life easier by adding an intermediate Model-To-Model transformation that makes almost everything pass through "as-is", but transforms N-to-M relationships into a bridge Entity and the 2 1-to-N and a 1-to-M relationships. The output of this model can be then passed to a way simpler Model-To-Text transformation.

With ALMOsT this scenario is really easy complexModelToText(model) becomes simpleModelToText(simpleModelToModel(model)).

In your specific case, you can have the existing .../modelrules/*.js files take care of the generation of the application and, if you need to transform the model through multiple steps, a chain of transformations that generate the files for Cypress.
The output of the two can be naively merged together.

function serverWithCypress(ifmlModel) {
  var applicationFiles = client.transform(ifmlModel);

  var cypressFiles = cypress.modelToText(cypress.anyOtherTransformationNeeded(ifmlModel));

  return compact({...applicationFiles, ...cypressFiles});
}

Let me know if you have more questions.

@AlexandroDRK
Copy link
Author

Thank you very much, I'm glad to know that much of what I could infer just by analyzing the project is in fact valid. I've also read all the major articles related to almost and its components to understand how Ifmledit uses its rules. I intend to perform my implementation using the "server" transformation.

@AlexandroDRK
Copy link
Author

At first I intend to add new rules to the existing structure in order to reduce the initial implementation complexity. If necessary, I will be separating the new rules into a separate structure, but for this moment I will worry about leaving it working.

@AlexandroDRK
Copy link
Author

AlexandroDRK commented Jun 4, 2023

@B3rn475 I recently created a transform rule that should utilize the existing IFML transform framework. This rule should map the elements of an ifml template to a Cypress test script using the "form" stereotype. I also added the scripts template that should receive the data to assemble the script. However, when running the application, nothing is generated, as if the model data were not being provided to the template at the time of transformation. You could clone my fork, or just analyze my source code to suggest changes and/or show where I'm going wrong.

@AlexandroDRK
Copy link
Author

I would also like to know a way to debug the application code, since it is currently executed through the assets compiled using gulp routines. Maybe debugging the real-time execution flow would help me identify what's going wrong with my code.

@B3rn475
Copy link
Owner

B3rn475 commented Jun 6, 2023

You can easily debug the transformation in the browser. Just open the developer tools, find the file/line you care about in the source code and add a breakpoint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants