Skip to content

Commit

Permalink
Adds an !elements keyword that can be used to find a set of element…
Browse files Browse the repository at this point in the history
…s via an expression.
  • Loading branch information
simonbrowndotje committed Aug 20, 2024
1 parent 52ec9be commit e30f5e8
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- structurizr-dsl: Fixes https://github.com/structurizr/java/issues/312 (!include doesn't work with files encoded as UTF-8 BOM).
- structurizr-dsl: Adds a way to explicitly specify the order of relationships in dynamic views.
- structurizr-dsl: Adds support for element technology expressions (e.g. "element.technology==Java").
- structurizr-dsl: Adds an `!elements` keyword that can be used to find a set of elements via an expression.

## 2.2.0 (2nd July 2024)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.structurizr.dsl;

import com.structurizr.model.Element;
import com.structurizr.model.ModelItem;

import java.util.Set;
import java.util.stream.Collectors;

class ElementsDslContext extends ModelItemsDslContext {

private final Set<Element> elements;

ElementsDslContext(DslContext parentDslContext, Set<Element> elements) {
super(parentDslContext);

this.elements = elements;
}

Set<Element> getElements() {
return elements;
}

@Override
Set<ModelItem> getModelItems() {
return elements.stream().map(e -> (ModelItem)e).collect(Collectors.toSet());
}

@Override
protected String[] getPermittedTokens() {
return new String[0];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.structurizr.dsl;

import com.structurizr.model.Element;
import com.structurizr.model.ModelItem;

import java.util.Set;
import java.util.stream.Collectors;

final class ElementsParser extends AbstractParser {

private static final String GRAMMAR = "!elements <expression>";

private final static int EXPRESSION_INDEX = 1;

Set<Element> parse(DslContext context, Tokens tokens) {
// !elements <expression>

if (tokens.hasMoreThan(EXPRESSION_INDEX)) {
throw new RuntimeException("Too many tokens, expected: " + GRAMMAR);
}

String expression = tokens.get(1);
Set<ModelItem> modelItems = new ExpressionParser().parseExpression(expression, context);

return modelItems.stream().filter(mi -> mi instanceof Element).map(mi -> (Element)mi).collect(Collectors.toSet());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.structurizr.dsl;

import com.structurizr.model.ModelItem;

import java.util.Set;

abstract class ModelItemsDslContext extends DslContext {

private final DslContext parentDslContext;

ModelItemsDslContext(DslContext parentDslContext) {
this.parentDslContext = parentDslContext;
}

DslContext getParentDslContext() {
return parentDslContext;
}

abstract Set<ModelItem> getModelItems();

@Override
protected String[] getPermittedTokens() {
return new String[0];
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,13 @@ void parse(List<String> lines, File dslFile, boolean include) throws Structurizr
}
}

} else if (ELEMENTS_TOKEN.equalsIgnoreCase(firstToken) && (inContext(ModelDslContext.class) || inContext(ModelItemDslContext.class))) {
Set<Element> elements = new ElementsParser().parse(getContext(), tokens.withoutContextStartToken());

if (shouldStartContext(tokens)) {
startContext(new ElementsDslContext(getContext(), elements));
}

} else if (CUSTOM_ELEMENT_TOKEN.equalsIgnoreCase(firstToken) && (inContext(ModelDslContext.class))) {
CustomElement customElement = new CustomElementParser().parse(getContext(GroupableDslContext.class), tokens.withoutContextStartToken());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class StructurizrDslTokens {
static final String IDENTIFIERS_TOKEN = "!identifiers";
static final String IMPLIED_RELATIONSHIPS_TOKEN = "!impliedRelationships";
static final String REF_TOKEN = "!ref";
static final String ELEMENTS_TOKEN = "!elements";
static final String EXTEND_TOKEN = "!extend";
static final String PLUGIN_TOKEN = "!plugin";
static final String SCRIPT_TOKEN = "!script";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.structurizr.dsl;

import com.structurizr.model.Component;
import com.structurizr.model.Container;
import com.structurizr.model.Element;
import com.structurizr.model.SoftwareSystem;
import org.junit.jupiter.api.Test;

import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

class ElementsParserTests extends AbstractTests {

private final ElementsParser parser = new ElementsParser();

@Test
void test_parse_ThrowsAnException_WhenThereAreTooManyTokens() {
try {
parser.parse(context(), tokens("!elements", "expression", "tokens"));
fail();
} catch (Exception e) {
assertEquals("Too many tokens, expected: !elements <expression>", e.getMessage());
}
}

@Test
void test_parse_FindsElementsByExpression() {
Container application = model.addSoftwareSystem("Software System").addContainer("Application");
Component componentA = application.addComponent("A");
Component componentB = application.addComponent("B");
Component componentC = application.addComponent("C");

ModelItemDslContext context = new ContainerDslContext(application);
context.setWorkspace(workspace);
IdentifiersRegister register = new IdentifiersRegister();
register.register("application", application);
context.setIdentifierRegister(register);

Set<Element> elements = parser.parse(context, tokens("!elements", "element.parent==application"));
assertTrue(elements.contains(componentA));
assertTrue(elements.contains(componentB));
assertTrue(elements.contains(componentC));
}

}
3 changes: 3 additions & 0 deletions structurizr-dsl/src/test/resources/dsl/test.dsl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ workspace "Name" "Description" {
perspectives {
"Security" "A description..."
}

!elements "element.parent==webApplication" {
}
}

url "https://structurizr.com"
Expand Down

0 comments on commit e30f5e8

Please sign in to comment.