Skip to content

Support for user-defined syntax entities in structurizr dsl #385

@Nifacy

Description

@Nifacy

Description

Summary

Feature will allow users to define custom syntax entities within Structurizr DSL,
enhancing it's extensibility and adaptability to diverse modeling requirements.

Background

Currently, structurizr dsl offers a fixed set of syntax entities for modeling software
architectures. While this sufficies for many scenarios, certain use cases necessitate
the definition of custom entities to represent domain-specific concepts more accurately.

Relevance

In large organizations like ours, recurring architectural patterns have emerged across
various projects. To effectively document and communicate these patterns within
our architecture descriptions, we require the ability to define them as distinct entities
in structurizr dsl.

While initial attempts using plugins and scripts provided some flexibility, a more
integrated and flexible approach is now necessary.

Priority

Low (I'm willing to make a pull request - please confirm approach first)

More information

Proposal

Implement functionality enabling users to create their own syntax entities
using a defined structure and parsing mechanism.

Details

Custom syntax entity format

Users can define custom entities using the following template:

$<entity-keyword> <param> ... {
    ...
}

Where:

  • <entity-keyword> - a unique keyword identifying the custom entity type.
    It must be alphanumeric and contain no spaces.

  • <param> ... - a set of parameters, each representing a distinct token.

  • { ... } - a context block containing additional information about the entity,
    similar to existing entities like container or group.

Parsing mechanism

Users will implement parsing logic for their custom entities,
adhering to a specified interface. This approach ensures that
the internal components of structurizr dsl remain encapsulated,
allowing users to extend functionality without having to
disclose the internal components form structurizr project.

The proposed interfaces are as follows:

Example

Here is an example of custom entity example:

import com.structurizr.dsl.CustomSyntaxEntity
import com.structurizr.dsl.CustomSyntaxEntityParser
import com.structurizr.dsl.CustomSyntaxEntityParserContext


class ExampleSyntaxEntityParser implements CustomSyntaxEntityParser {

    private String name;
    private String fieldA;
    private String fieldB;

    ExampleSyntaxEntityParser() {
        this.name = null;
        this.fieldA = null;
        this.fieldB = null;
    }

    public void parseHeader(String[] tokens) {
        if (tokens.length != 1) {
            throw new RuntimeException("Expected: $example <name>")
        }

        this.name = tokens[0];
    }

    public void parseContextBlockLine(String[] tokens) {
        if (tokens.length != 2) {
            throw new RuntimeException("Expected: <name> <value>");
        }

        String fieldName = tokens[0];
        String value = tokens[1];

        if (fieldName == "a") {
            if (this.fieldA != null) {
                throw new RuntimeException("Field 'a' already defined");
            }
            this.fieldA = value;
        }

        else if (fieldName == "b") {
            if (this.fieldB != null) {
                throw new RuntimeException("Field 'b' already defined");
            }
            this.fieldB = value;
        }

        else {
            throw new RuntimeException("Unknown field: " + key);
        }
    }

    public void onEnd() {
        System.out.println("Syntax entity info:");
        System.out.println("- name: " + this.name);
        System.out.println("- field a: " + this.fieldA);
        System.out.println("- field b: " + this.fieldB);
    }
}


class ExampleSyntaxEntity implements CustomSyntaxEntity {
    public String getKeyword() {
        return "example";
    }

    public CustomSyntaxEntityParser getParser(CustomSyntaxEntityParserContext context) {
        System.out.println("Parser context:");
        System.out.println("- workspace: " + context.getWorkspace());
        System.out.println("- file: " + context.getDslFile());
        System.out.println("- parser: " + context.getDslParser());

        return new ExampleSyntaxEntityParser();
    }
}

Conclusion

Benefits

  • Users can tailor the DSL to their specific needs without modifying the core library.
  • Facilitates the representation of domain-specific concepts, enhancing the
    expressiveness of models.
  • Maintains the integrity of core components by exposing only necessary interfaces
    for extension.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions