diff --git a/docs/changelog.md b/docs/changelog.md index 5a90a22..7f4513c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -4,6 +4,7 @@ - Fixes https://github.com/structurizr/dsl/issues/364 (.DS_Store file causes exception during !include on Windows). - Adds a `getDslParser()` method to the `StructurizrDslPluginContext` class (https://github.com/structurizr/dsl/issues/361). +- Adds the ability to specify the workspace scope via a `scope` keyword inside the workspace `configuration`. - Updates structurizr/java to [v1.28.0](https://github.com/structurizr/java/releases/tag/v1.28.0). ## 1.33.0 (27th October 2023) diff --git a/src/main/java/com/structurizr/dsl/ConfigurationDslContext.java b/src/main/java/com/structurizr/dsl/ConfigurationDslContext.java index f8df431..18b211f 100644 --- a/src/main/java/com/structurizr/dsl/ConfigurationDslContext.java +++ b/src/main/java/com/structurizr/dsl/ConfigurationDslContext.java @@ -2,14 +2,10 @@ final class ConfigurationDslContext extends DslContext { - private static final int FIRST_PROPERTY_INDEX = 1; - - private static final String PRIVATE = "private"; - private static final String PUBLIC = "public"; - @Override protected String[] getPermittedTokens() { return new String[] { + StructurizrDslTokens.SCOPE_TOKEN, StructurizrDslTokens.VISIBILITY_TOKEN, StructurizrDslTokens.USERS_TOKEN, StructurizrDslTokens.PROPERTIES_TOKEN diff --git a/src/main/java/com/structurizr/dsl/ConfigurationParser.java b/src/main/java/com/structurizr/dsl/ConfigurationParser.java index 702f12d..ddd2479 100644 --- a/src/main/java/com/structurizr/dsl/ConfigurationParser.java +++ b/src/main/java/com/structurizr/dsl/ConfigurationParser.java @@ -1,33 +1,60 @@ package com.structurizr.dsl; import com.structurizr.configuration.Visibility; +import com.structurizr.configuration.WorkspaceScope; final class ConfigurationParser extends AbstractParser { - private static final String GRAMMAR = "visibility "; + private static final String SCOPE_GRAMMAR = "scope "; + private static final String SCOPE_LANDSCAPE = "landscape"; + private static final String SCOPE_SOFTWARE_SYSTEM = "softwaresystem"; + private static final String SCOPE_NONE = "none"; + + private static final String VISIBILITY_GRAMMAR = "visibility "; + private static final String VISIBILITY_PRIVATE = "private"; + private static final String VISIBILITY_PUBLIC = "public"; private static final int FIRST_PROPERTY_INDEX = 1; - private static final String PRIVATE = "private"; - private static final String PUBLIC = "public"; + void parseScope(DslContext context, Tokens tokens) { + if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) { + throw new RuntimeException("Too many tokens, expected: " + SCOPE_GRAMMAR); + } + + if (tokens.includes(FIRST_PROPERTY_INDEX)) { + String scope = tokens.get(1).toLowerCase(); + + if (scope.equalsIgnoreCase(SCOPE_LANDSCAPE)) { + context.getWorkspace().getConfiguration().setScope(WorkspaceScope.Landscape); + } else if (scope.equalsIgnoreCase(SCOPE_SOFTWARE_SYSTEM)) { + context.getWorkspace().getConfiguration().setScope(WorkspaceScope.SoftwareSystem); + } else if (scope.equalsIgnoreCase(SCOPE_NONE)) { + context.getWorkspace().getConfiguration().setScope(null); + } else { + throw new RuntimeException("The scope \"" + scope + "\" is not valid"); + } + } else { + throw new RuntimeException("Expected: " + SCOPE_GRAMMAR); + } + } void parseVisibility(DslContext context, Tokens tokens) { if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) { - throw new RuntimeException("Too many tokens, expected: " + GRAMMAR); + throw new RuntimeException("Too many tokens, expected: " + VISIBILITY_GRAMMAR); } if (tokens.includes(FIRST_PROPERTY_INDEX)) { String visibility = tokens.get(1).toLowerCase(); - if (visibility.equalsIgnoreCase(PRIVATE)) { + if (visibility.equalsIgnoreCase(VISIBILITY_PRIVATE)) { context.getWorkspace().getConfiguration().setVisibility(Visibility.Private); - } else if (visibility.equalsIgnoreCase(PUBLIC)) { + } else if (visibility.equalsIgnoreCase(VISIBILITY_PUBLIC)) { context.getWorkspace().getConfiguration().setVisibility(Visibility.Public); } else { throw new RuntimeException("The visibility \"" + visibility + "\" is not valid"); } } else { - throw new RuntimeException("Expected: " + GRAMMAR); + throw new RuntimeException("Expected: " + VISIBILITY_GRAMMAR); } } diff --git a/src/main/java/com/structurizr/dsl/StructurizrDslParser.java b/src/main/java/com/structurizr/dsl/StructurizrDslParser.java index ba4abc7..e88e91b 100644 --- a/src/main/java/com/structurizr/dsl/StructurizrDslParser.java +++ b/src/main/java/com/structurizr/dsl/StructurizrDslParser.java @@ -835,6 +835,9 @@ void parse(List lines, File dslFile) throws StructurizrDslParserExceptio } else if (CONFIGURATION_TOKEN.equalsIgnoreCase(firstToken) && inContext(WorkspaceDslContext.class)) { startContext(new ConfigurationDslContext()); + } else if (SCOPE_TOKEN.equalsIgnoreCase(firstToken) && inContext(ConfigurationDslContext.class)) { + new ConfigurationParser().parseScope(getContext(), tokens); + } else if (VISIBILITY_TOKEN.equalsIgnoreCase(firstToken) && inContext(ConfigurationDslContext.class)) { new ConfigurationParser().parseVisibility(getContext(), tokens); diff --git a/src/main/java/com/structurizr/dsl/StructurizrDslTokens.java b/src/main/java/com/structurizr/dsl/StructurizrDslTokens.java index 814c24b..946185e 100644 --- a/src/main/java/com/structurizr/dsl/StructurizrDslTokens.java +++ b/src/main/java/com/structurizr/dsl/StructurizrDslTokens.java @@ -24,6 +24,7 @@ class StructurizrDslTokens { static final String PERSPECTIVES_TOKEN = "perspectives"; static final String WORKSPACE_TOKEN = "workspace"; static final String EXTENDS_TOKEN = "extends"; + static final String SCOPE_TOKEN = "scope"; static final String MODEL_TOKEN = "model"; static final String VIEWS_TOKEN = "views"; static final String ENTERPRISE_TOKEN = "enterprise"; diff --git a/src/test/dsl/test.dsl b/src/test/dsl/test.dsl index 800007c..e18d34a 100644 --- a/src/test/dsl/test.dsl +++ b/src/test/dsl/test.dsl @@ -334,6 +334,7 @@ workspace "Name" "Description" { } visibility public + scope softwaresystem } } \ No newline at end of file diff --git a/src/test/java/com/structurizr/dsl/ConfigurationParserTests.java b/src/test/java/com/structurizr/dsl/ConfigurationParserTests.java index 4eff20e..157c9bc 100644 --- a/src/test/java/com/structurizr/dsl/ConfigurationParserTests.java +++ b/src/test/java/com/structurizr/dsl/ConfigurationParserTests.java @@ -1,6 +1,7 @@ package com.structurizr.dsl; import com.structurizr.configuration.Visibility; +import com.structurizr.configuration.WorkspaceScope; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -10,6 +11,42 @@ class ConfigurationParserTests extends AbstractTests { private final ConfigurationParser parser = new ConfigurationParser(); + @Test + void test_parseScope_ThrowsAnException_WhenThereAreTooManyTokens() { + try { + parser.parseScope(context(), tokens("scope", "landscape", "extra")); + fail(); + } catch (Exception e) { + assertEquals("Too many tokens, expected: scope ", e.getMessage()); + } + } + + @Test + void test_parseScope_ThrowsAnException_WhenTheScopeIsMissing() { + try { + parser.parseScope(context(), tokens("scope")); + fail(); + } catch (Exception e) { + assertEquals("Expected: scope ", e.getMessage()); + } + } + + @Test + void test_parseScope_ThrowsAnException_WhenTheScopeIsNotValid() { + try { + parser.parseScope(context(), tokens("scope", "container")); + fail(); + } catch (Exception e) { + assertEquals("The scope \"container\" is not valid", e.getMessage()); + } + } + + @Test + void test_parseScope_SetsTheScope() { + parser.parseScope(context(), tokens("scope", "softwaresystem")); + assertEquals(WorkspaceScope.SoftwareSystem, workspace.getConfiguration().getScope()); + } + @Test void test_parseVisibility_ThrowsAnException_WhenThereAreTooManyTokens() { try {