Skip to content

Model representation in the form of Node in AST #628

@magicmatatjahu

Description

@magicmatatjahu

As I'm the "author" of the presets, I see that I made a big mistake of treating them as middlewares which are supposed to return the changed content (as a string) and not as data (in meaning of the structure) that is later changed to the correct model in the given language (class/interface/structure etc).

It seems to me that we should move to representing a given model as a node in a typical AST. What does that mean? During the processing of presets, the user/developer would have access to the model representation as a structure (not a string!) and then, after each preset (btw. we should change the name to hook), this structure should be transformed into a valid model in the given language. Here is an example to better understand the idea:

interface JavaClassNode {
  name: string;
  modifiers: Array<'public', 'private', 'static' ...>;
  annotations: Record<string, {
    ...
  }>;
  interfaces: Array<Type>; // interfaces which implements given class
  extends: Type; // we can extend only by one class
  properties: Record<string, {
    modifiers: Array<'public', 'private', 'final', 'protected', ...>;
    type: Type,
    initialValue: string,
    ...
  }>;
  methods: Record<string, {
    modifiers: Array<'public', 'private', 'final', 'protected', ...>;
    arguments: Array<{ name: string, type: Type }>;
    returnType: Type;
    body: string; // I think that body of method still be of string type, but we can discuss about it
  }>;
  ... // other things like comments etc
}

then we will have hooks only for given type kind - in Java class, interface, enum (maybe record?) - and we can remove all presets for properties, additionalProperties etc, because it's bullshit and they are difficult to use. Inside hooks we will be able to change that internal data in structure (and what is important, add/remove/update new properties, methods, annotations etc), e.g.:

// java hooks
const hook1 = {
  class: ({ model }) => {
    model.modifiers.push('private');
    model.interfaces.push({ name: 'ISomeInterface' });
    model.annotations.push({ name: 'SomeAnnotation', value: ... });
    model.extends = { name: 'AnotherJavaClass' };
  },
  interface: () => {...},
  enum: () => {...},
}
const hook2 = {
  class: ({ model }) => {
    model.interfaces.push({ name: 'IAnotherInterface' });
    model.properties['someProperty'] = { modifiers: ['private'], type: { name: 'SomeType', initialValue = 'new SomeType()' } };
    model.methods['someMethod'] = { modifiers: ['protected'], returnType: { name: 'SomeReturnType' }, arguments: [{ name: 'arg1', type: { name: 'SomeType' } }] };
  },
  interface: () => {...},
  enum: () => {...},
}

and then after running that hooks we will have rendered model:

@SomeAnnotation(...)
private class JavaClass extends AnotherJavaClass implements ISomeInterface, IAnotherInterface {
  private SomeType someProperty = new SomeType();
  protected SomeReturnType someMethod(SomeType arg1, ...) {...}
}

Benefits:

  • we don't operate on string and perform some regex to "retrieve" some metadata defined by previous defined presets, but we operate on the data structure, so we can easily add/remove/update given property/method/annotations (depending on the language) etc.
  • the representation in one language can be converted into another language representation (easier integration - that current one - of solutions like TS input data etc), because we will operate on AST.
  • since no one will be operating on strings (only for method/function body), this eliminates the problem of a given preset being incompatible with another and creating a bad syntax for given language.

Minuses:

  • we still need to operate on string for method/function body. I don't know if we should switch to the AST in this case, WDYT?
  • we still have boilerplate to add "metadata" for model, but I think that it's still much less that current solution with string operations.
  • each language and model type will have a different AST, resulting in a large number of interfaces on the core side - but that's not a problem for me -> see 2nd benefit point.

What do you think? I don't think we'll ever find a best solution that's easy to use and powerful, but this one is much easier than the current string-based presets.

cc @jonaslagoni @smoya
I see that you @panwauu @mahakporwal02 @ron-debajyoti are very active in that project. I think that it is interesting for you :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestkeepDont let stale get to it.stale

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions