diff --git a/changelog.md b/changelog.md index 03139f0a..cd6faebb 100644 --- a/changelog.md +++ b/changelog.md @@ -4,6 +4,7 @@ - structurizr-dsl: Adds support for `element!=` expressions. - structurizr-dsl: `!elements` and `!relationships` now work inside deployment environment blocks. +- structurizr-dsl: `description` and `technology` now work inside `!elements` blocks. ## 3.1.0 (4th November 2024) diff --git a/structurizr-dsl/src/main/java/com/structurizr/dsl/ElementsDslContext.java b/structurizr-dsl/src/main/java/com/structurizr/dsl/ElementsDslContext.java index 7e056c15..3ef8706e 100644 --- a/structurizr-dsl/src/main/java/com/structurizr/dsl/ElementsDslContext.java +++ b/structurizr-dsl/src/main/java/com/structurizr/dsl/ElementsDslContext.java @@ -29,6 +29,8 @@ Set getModelItems() { protected String[] getPermittedTokens() { return new String[] { StructurizrDslTokens.RELATIONSHIP_TOKEN, + StructurizrDslTokens.DESCRIPTION_TOKEN, + StructurizrDslTokens.TECHNOLOGY_TOKEN, StructurizrDslTokens.TAG_TOKEN, StructurizrDslTokens.TAGS_TOKEN, StructurizrDslTokens.URL_TOKEN, diff --git a/structurizr-dsl/src/main/java/com/structurizr/dsl/ElementsParser.java b/structurizr-dsl/src/main/java/com/structurizr/dsl/ElementsParser.java new file mode 100644 index 00000000..b2862307 --- /dev/null +++ b/structurizr-dsl/src/main/java/com/structurizr/dsl/ElementsParser.java @@ -0,0 +1,50 @@ +package com.structurizr.dsl; + +import com.structurizr.model.*; + +final class ElementsParser extends AbstractParser { + + private final static int DESCRIPTION_INDEX = 1; + private final static int TECHNOLOGY_INDEX = 1; + + void parseDescription(ElementsDslContext context, Tokens tokens) { + // description + if (tokens.hasMoreThan(DESCRIPTION_INDEX)) { + throw new RuntimeException("Too many tokens, expected: description "); + } + + if (!tokens.includes(DESCRIPTION_INDEX)) { + throw new RuntimeException("Expected: description "); + } + + String description = tokens.get(DESCRIPTION_INDEX); + for (Element element : context.getElements()) { + element.setDescription(description); + } + } + + void parseTechnology(ElementsDslContext context, Tokens tokens) { + // technology + if (tokens.hasMoreThan(TECHNOLOGY_INDEX)) { + throw new RuntimeException("Too many tokens, expected: technology "); + } + + if (!tokens.includes(TECHNOLOGY_INDEX)) { + throw new RuntimeException("Expected: technology "); + } + + String technology = tokens.get(TECHNOLOGY_INDEX); + for (Element element : context.getElements()) { + if (element instanceof Container) { + ((Container)element).setTechnology(technology); + } else if (element instanceof Component) { + ((Component)element).setTechnology(technology); + } else if (element instanceof DeploymentNode) { + ((DeploymentNode)element).setTechnology(technology); + } else if (element instanceof InfrastructureNode) { + ((InfrastructureNode)element).setTechnology(technology); + } + } + } + +} \ No newline at end of file diff --git a/structurizr-dsl/src/main/java/com/structurizr/dsl/StructurizrDslParser.java b/structurizr-dsl/src/main/java/com/structurizr/dsl/StructurizrDslParser.java index 9f6d4af2..f0faf6f4 100644 --- a/structurizr-dsl/src/main/java/com/structurizr/dsl/StructurizrDslParser.java +++ b/structurizr-dsl/src/main/java/com/structurizr/dsl/StructurizrDslParser.java @@ -537,6 +537,9 @@ void parse(List lines, File dslFile, boolean fragment, boolean includeIn } else if (DESCRIPTION_TOKEN.equalsIgnoreCase(firstToken) && inContext(ElementDslContext.class) && !isGroup(getContext())) { new ModelItemParser().parseDescription(getContext(ElementDslContext.class), tokens); + } else if (DESCRIPTION_TOKEN.equalsIgnoreCase(firstToken) && inContext(ElementsDslContext.class)) { + new ElementsParser().parseDescription(getContext(ElementsDslContext.class), tokens); + } else if (TECHNOLOGY_TOKEN.equalsIgnoreCase(firstToken) && inContext(ContainerDslContext.class) && !getContext(ContainerDslContext.class).hasGroup()) { new ContainerParser().parseTechnology(getContext(ContainerDslContext.class), tokens); @@ -549,6 +552,9 @@ void parse(List lines, File dslFile, boolean fragment, boolean includeIn } else if (TECHNOLOGY_TOKEN.equalsIgnoreCase(firstToken) && inContext(InfrastructureNodeDslContext.class)) { new InfrastructureNodeParser().parseTechnology(getContext(InfrastructureNodeDslContext.class), tokens); + } else if (TECHNOLOGY_TOKEN.equalsIgnoreCase(firstToken) && inContext(ElementsDslContext.class)) { + new ElementsParser().parseTechnology(getContext(ElementsDslContext.class), tokens); + } else if (INSTANCES_TOKEN.equalsIgnoreCase(firstToken) && inContext(DeploymentNodeDslContext.class)) { new DeploymentNodeParser().parseInstances(getContext(DeploymentNodeDslContext.class), tokens); diff --git a/structurizr-dsl/src/test/java/com/structurizr/dsl/ElementsParserTests.java b/structurizr-dsl/src/test/java/com/structurizr/dsl/ElementsParserTests.java new file mode 100644 index 00000000..1c183620 --- /dev/null +++ b/structurizr-dsl/src/test/java/com/structurizr/dsl/ElementsParserTests.java @@ -0,0 +1,70 @@ +package com.structurizr.dsl; + +import com.structurizr.model.*; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +class ElementsParserTests extends AbstractTests { + + private final ElementsParser parser = new ElementsParser(); + + @Test + void test_parseTechnology_ThrowsAnException_WhenNoTechnologyIsSpecified() { + try { + parser.parseTechnology(null, tokens("technology")); + fail(); + } catch (Exception e) { + assertEquals("Expected: technology ", e.getMessage()); + } + } + + @Test + void test_parseTechnology() { + SoftwareSystem softwareSystem = model.addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Container"); + Component component = container.addComponent("Component"); + DeploymentNode deploymentNode = model.addDeploymentNode("Deployment Node"); + InfrastructureNode infrastructureNode = deploymentNode.addInfrastructureNode("Infrastructure Node"); + + ElementsDslContext context = new ElementsDslContext(null, Set.of(softwareSystem, container, component, deploymentNode, infrastructureNode)); + + parser.parseTechnology(context, tokens("technology", "Technology")); + assertEquals("Technology", container.getTechnology()); + assertEquals("Technology", component.getTechnology()); + assertEquals("Technology", deploymentNode.getTechnology()); + assertEquals("Technology", infrastructureNode.getTechnology()); + } + + @Test + void test_parseDescription_ThrowsAnException_WhenNoDescriptionIsSpecified() { + try { + parser.parseDescription(null, tokens("description")); + fail(); + } catch (Exception e) { + assertEquals("Expected: description ", e.getMessage()); + } + } + + @Test + void test_parseDescription() { + SoftwareSystem softwareSystem = model.addSoftwareSystem("Software System"); + Container container = softwareSystem.addContainer("Container"); + Component component = container.addComponent("Component"); + DeploymentNode deploymentNode = model.addDeploymentNode("Deployment Node"); + InfrastructureNode infrastructureNode = deploymentNode.addInfrastructureNode("Infrastructure Node"); + + ElementsDslContext context = new ElementsDslContext(null, Set.of(softwareSystem, container, component, deploymentNode, infrastructureNode)); + + parser.parseDescription(context, tokens("description", "Description")); + assertEquals("Description", softwareSystem.getDescription()); + assertEquals("Description", container.getDescription()); + assertEquals("Description", component.getDescription()); + assertEquals("Description", deploymentNode.getDescription()); + assertEquals("Description", infrastructureNode.getDescription()); + } + +} \ No newline at end of file