Skip to content
This repository was archived by the owner on Jan 10, 2024. It is now read-only.

Commit 17026e7

Browse files
Fixes some clashing issues with automatic key generation for views.
1 parent d24d70f commit 17026e7

23 files changed

+121
-37
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ targetCompatibility = 1.8
2727

2828
description = 'Structurizr DSL'
2929
group = 'com.structurizr'
30-
version = '1.24.0'
30+
version = '1.25.0'
3131

3232
test {
3333
useJUnitPlatform()

docs/changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 1.25.0 (3rd February 2023)
4+
5+
- Fixes some clashing issues with automatic key generation for views.
6+
37
## 1.24.0 (28th January 2023)
48

59
- More variables are exposed to scripts, based upon where the script is defined (`element`, `relationship`, `view`).

docs/language-reference.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Please see the [DSL cookbook](cookbook) for a tutorial guide to the Structurizr
7878

7979
In addition, workspaces are subject to the following rules:
8080

81-
- Each view must have a unique "key" (this is autogenerated if not specified).
81+
- Each view must have a unique "key" (this is generated for you if not specified; __warning: you will likely lose manual layout information when using automatically generated view keys__).
8282
- Software and people names must be unique.
8383
- Container names must be unique within the context of a software system.
8484
- Component names must be unique within the context of a container.
@@ -927,8 +927,6 @@ Or, if you're extending a JSON-based workspace, you can reference an element by
927927

928928
See [ref.dsl](../src/test/dsl/ref.dsl) for some usage examples.
929929

930-
__Please note that `!ref` is currently an experimental feature.__
931-
932930
### views
933931

934932
Each workspace can also contain one or more views, defined with the `views` block.
@@ -966,6 +964,8 @@ systemLandscape [key] [description] {
966964
}
967965
```
968966

967+
A view key will be generated for you if not specified; __you will likely lose manual layout information when using automatically generated view keys__.
968+
969969
Permitted children:
970970

971971
- [include](#include)
@@ -986,6 +986,8 @@ systemContext <software system identifier> [key] [description] {
986986
}
987987
```
988988

989+
A view key will be generated for you if not specified; __you will likely lose manual layout information when using automatically generated view keys__.
990+
989991
Permitted children:
990992

991993
- [include](#include)
@@ -1006,6 +1008,8 @@ container <software system identifier> [key] [description] {
10061008
}
10071009
```
10081010

1011+
A view key will be generated for you if not specified; __you will likely lose manual layout information when using automatically generated view keys__.
1012+
10091013
Permitted children:
10101014

10111015
- [include](#include)
@@ -1026,6 +1030,8 @@ component <container identifier> [key] [description] {
10261030
}
10271031
```
10281032

1033+
A view key will be generated for you if not specified; __you will likely lose manual layout information when using automatically generated view keys__.
1034+
10291035
Permitted children:
10301036

10311037
- [include](#include)
@@ -1068,6 +1074,8 @@ The first property defines the scope of the view, and therefore what can be adde
10681074
- Software system scope: People, other software systems, and containers.
10691075
- Container scope: People, other software systems, other containers, and components.
10701076

1077+
A view key will be generated for you if not specified; __you will likely lose manual layout information when using automatically generated view keys__.
1078+
10711079
Unlike the other diagram types, Dynamic views are created by specifying the relationships that should be added to the view, within the `dynamic` block, as follows:
10721080

10731081
```
@@ -1101,6 +1109,8 @@ The first property defines the scope of the view, and the second property define
11011109
- `*` scope: All deployment nodes, infrastructure nodes, and container instances within the deployment environment.
11021110
- Software system scope: All deployment nodes and infrastructure nodes within the deployment environment. Container instances within the deployment environment that belong to the software system.
11031111

1112+
A view key will be generated for you if not specified; __you will likely lose manual layout information when using automatically generated view keys__.
1113+
11041114
Permitted children:
11051115

11061116
- [include](#include)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.structurizr.dsl;
2+
3+
import com.structurizr.Workspace;
4+
import com.structurizr.view.FilteredView;
5+
import com.structurizr.view.SystemLandscapeView;
6+
import com.structurizr.view.View;
7+
8+
import java.util.Collection;
9+
import java.util.HashSet;
10+
import java.util.Set;
11+
12+
abstract class AbstractViewParser extends AbstractParser {
13+
14+
protected String generateViewKey(Workspace workspace, String prefix) {
15+
int counter = 1;
16+
String key = prefix + "-" + counter;
17+
18+
while (hasViewWithKey(workspace, key)) {
19+
counter++;
20+
key = prefix + "-" + counter;
21+
}
22+
23+
return key;
24+
}
25+
26+
protected boolean hasViewWithKey(Workspace workspace, String key) {
27+
Set<View> views = new HashSet<>();
28+
views.addAll(workspace.getViews().getCustomViews());
29+
views.addAll(workspace.getViews().getSystemLandscapeViews());
30+
views.addAll(workspace.getViews().getSystemContextViews());
31+
views.addAll(workspace.getViews().getContainerViews());
32+
views.addAll(workspace.getViews().getComponentViews());
33+
views.addAll(workspace.getViews().getDynamicViews());
34+
views.addAll(workspace.getViews().getDeploymentViews());
35+
36+
Collection<FilteredView> filteredViews = workspace.getViews().getFilteredViews();
37+
38+
return
39+
views.stream().anyMatch(view -> view.getKey().equals(key)) ||
40+
filteredViews.stream().anyMatch(view -> view.getKey().equals(key));
41+
}
42+
43+
}

src/main/java/com/structurizr/dsl/ComponentViewParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.structurizr.model.Element;
66
import com.structurizr.view.ComponentView;
77

8-
final class ComponentViewParser extends AbstractParser {
8+
final class ComponentViewParser extends AbstractViewParser {
99

1010
private static final String GRAMMAR = "component <container identifier> [key] [description] {";
1111

@@ -45,7 +45,7 @@ ComponentView parse(DslContext context, Tokens tokens) {
4545
if (tokens.includes(KEY_INDEX)) {
4646
key = tokens.get(KEY_INDEX);
4747
} else {
48-
key = removeNonWordCharacters(container.getSoftwareSystem().getName()) + "-" + removeNonWordCharacters(container.getName()) + "-" + VIEW_TYPE;
48+
key = generateViewKey(workspace, VIEW_TYPE);
4949
}
5050
validateViewKey(key);
5151

src/main/java/com/structurizr/dsl/ContainerViewParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.structurizr.model.SoftwareSystem;
66
import com.structurizr.view.ContainerView;
77

8-
final class ContainerViewParser extends AbstractParser {
8+
final class ContainerViewParser extends AbstractViewParser {
99

1010
private static final String GRAMMAR = "container <software system identifier> [key] [description] {";
1111

@@ -45,7 +45,7 @@ ContainerView parse(DslContext context, Tokens tokens) {
4545
if (tokens.includes(KEY_INDEX)) {
4646
key = tokens.get(KEY_INDEX);
4747
} else {
48-
key = key = removeNonWordCharacters(softwareSystem.getName()) + "-" + VIEW_TYPE;
48+
key = generateViewKey(workspace, VIEW_TYPE);
4949
}
5050
validateViewKey(key);
5151

src/main/java/com/structurizr/dsl/CustomViewParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import com.structurizr.Workspace;
44
import com.structurizr.view.CustomView;
55

6-
final class CustomViewParser extends AbstractParser {
6+
final class CustomViewParser extends AbstractViewParser {
77

88
private static final String GRAMMAR = "custom [key] [title] [description] {";
99

@@ -28,7 +28,7 @@ CustomView parse(DslContext context, Tokens tokens) {
2828
if (tokens.includes(KEY_INDEX)) {
2929
key = tokens.get(KEY_INDEX);
3030
} else {
31-
key = VIEW_TYPE + (context.getWorkspace().getViews().getCustomViews().size() + 1);
31+
key = generateViewKey(workspace, VIEW_TYPE);
3232
}
3333
validateViewKey(key);
3434

src/main/java/com/structurizr/dsl/DeploymentViewParser.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import com.structurizr.model.SoftwareSystem;
77
import com.structurizr.view.DeploymentView;
88

9-
final class DeploymentViewParser extends AbstractParser {
9+
final class DeploymentViewParser extends AbstractViewParser {
1010

1111
private static final String GRAMMAR = "deployment <*|software system identifier> <environment> [key] [description] {";
1212

@@ -53,7 +53,7 @@ DeploymentView parse(DslContext context, Tokens tokens) {
5353
if (tokens.includes(KEY_INDEX)) {
5454
key = tokens.get(KEY_INDEX);
5555
} else {
56-
key = removeNonWordCharacters(environment) + "-" + VIEW_TYPE;
56+
key = generateViewKey(workspace, VIEW_TYPE);
5757
}
5858
validateViewKey(key);
5959

@@ -68,7 +68,7 @@ DeploymentView parse(DslContext context, Tokens tokens) {
6868
if (tokens.includes(KEY_INDEX)) {
6969
key = tokens.get(KEY_INDEX);
7070
} else {
71-
key = removeNonWordCharacters(element.getName()) + "-" + removeNonWordCharacters(environment) + "-" + VIEW_TYPE;
71+
key = generateViewKey(workspace, VIEW_TYPE);
7272
}
7373
validateViewKey(key);
7474

src/main/java/com/structurizr/dsl/DynamicViewParser.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import java.text.DecimalFormat;
1010

11-
class DynamicViewParser extends AbstractParser {
11+
class DynamicViewParser extends AbstractViewParser {
1212

1313
private static final String GRAMMAR = "dynamic <*|software system identifier|container identifier> [key] [description] {";
1414

@@ -47,7 +47,7 @@ DynamicView parse(DslContext context, Tokens tokens) {
4747
if (tokens.includes(KEY_INDEX)) {
4848
key = tokens.get(KEY_INDEX);
4949
} else {
50-
key = VIEW_TYPE + "-" + format.format(workspace.getViews().getDynamicViews().size() + 1);
50+
key = generateViewKey(workspace, VIEW_TYPE);
5151
}
5252
validateViewKey(key);
5353

@@ -62,7 +62,7 @@ DynamicView parse(DslContext context, Tokens tokens) {
6262
if (tokens.includes(KEY_INDEX)) {
6363
key = tokens.get(KEY_INDEX);
6464
} else {
65-
key = removeNonWordCharacters(element.getName()) + "-" + VIEW_TYPE + "-" + format.format(workspace.getViews().getDynamicViews().size() + 1);
65+
key = generateViewKey(workspace, VIEW_TYPE);
6666
}
6767
validateViewKey(key);
6868

@@ -72,7 +72,7 @@ DynamicView parse(DslContext context, Tokens tokens) {
7272
if (tokens.includes(KEY_INDEX)) {
7373
key = tokens.get(KEY_INDEX);
7474
} else {
75-
key = removeNonWordCharacters(container.getSoftwareSystem().getName()) + "-" + removeNonWordCharacters(container.getName()) + "-" + VIEW_TYPE + "-" + format.format(workspace.getViews().getDynamicViews().size() + 1);
75+
key = generateViewKey(workspace, VIEW_TYPE);
7676
}
7777
validateViewKey(key);
7878

src/main/java/com/structurizr/dsl/FilteredViewParser.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import java.util.HashSet;
1111
import java.util.Set;
1212

13-
final class FilteredViewParser extends AbstractParser {
13+
final class FilteredViewParser extends AbstractViewParser {
1414

1515
private static final String GRAMMAR = "filtered <baseKey> <include|exclude> <tags> [key] [description]";
1616

@@ -79,11 +79,10 @@ FilteredView parse(DslContext context, Tokens tokens) {
7979
if (tokens.includes(KEY_INDEX)) {
8080
key = tokens.get(KEY_INDEX);
8181
} else {
82-
key = baseView.getKey() + "-" + VIEW_TYPE + "-" + format.format(workspace.getViews().getDynamicViews().size() + 1);
82+
key = generateViewKey(workspace, VIEW_TYPE);
8383
}
8484
validateViewKey(key);
8585

86-
8786
return workspace.getViews().createFilteredView(baseView, key, description, filterMode, tags.toArray(new String[0]));
8887
}
8988

src/main/java/com/structurizr/dsl/SystemContextViewParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import com.structurizr.model.SoftwareSystem;
66
import com.structurizr.view.SystemContextView;
77

8-
final class SystemContextViewParser extends AbstractParser {
8+
final class SystemContextViewParser extends AbstractViewParser {
99

1010
private static final String GRAMMAR = "systemContext <software system identifier> [key] [description] {";
1111

@@ -45,7 +45,7 @@ SystemContextView parse(DslContext context, Tokens tokens) {
4545
if (tokens.includes(KEY_INDEX)) {
4646
key = tokens.get(KEY_INDEX);
4747
} else {
48-
key = removeNonWordCharacters(softwareSystem.getName()) + "-" + VIEW_TYPE;
48+
key = generateViewKey(workspace, VIEW_TYPE);
4949
}
5050
validateViewKey(key);
5151

src/main/java/com/structurizr/dsl/SystemLandscapeViewParser.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import com.structurizr.Workspace;
44
import com.structurizr.view.SystemLandscapeView;
55

6-
final class SystemLandscapeViewParser extends AbstractParser {
6+
final class SystemLandscapeViewParser extends AbstractViewParser {
77

88
private static final String GRAMMAR = "systemLandscape [key] [description] {";
99

@@ -26,7 +26,7 @@ SystemLandscapeView parse(DslContext context, Tokens tokens) {
2626
if (tokens.includes(KEY_INDEX)) {
2727
key = tokens.get(KEY_INDEX);
2828
} else {
29-
key = VIEW_TYPE;
29+
key = generateViewKey(workspace, VIEW_TYPE);
3030
}
3131
validateViewKey(key);
3232

src/test/dsl/views-without-keys.dsl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
workspace {
2+
3+
model {
4+
person "User"
5+
}
6+
7+
views {
8+
systemLandscape {
9+
}
10+
11+
systemLandscape {
12+
}
13+
14+
systemLandscape {
15+
}
16+
}
17+
18+
}

src/test/java/com/structurizr/dsl/ComponentViewParserTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void test_parse_CreatesAComponentView() {
7171
List<ComponentView> views = new ArrayList<>(context.getWorkspace().getViews().getComponentViews());
7272

7373
assertEquals(1, views.size());
74-
assertEquals("Name-Container-Component", views.get(0).getKey());
74+
assertEquals("Component-1", views.get(0).getKey());
7575
assertEquals("", views.get(0).getDescription());
7676
assertTrue(views.get(0).getExternalContainerBoundariesVisible());
7777
}

src/test/java/com/structurizr/dsl/ContainerViewParserTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void test_parse_CreatesAContainerView() {
7171
List<ContainerView> views = new ArrayList<>(context.getWorkspace().getViews().getContainerViews());
7272

7373
assertEquals(1, views.size());
74-
assertEquals("Name-Container", views.get(0).getKey());
74+
assertEquals("Container-1", views.get(0).getKey());
7575
assertEquals("", views.get(0).getDescription());
7676
assertTrue(views.get(0).getExternalSoftwareSystemBoundariesVisible());
7777
}

src/test/java/com/structurizr/dsl/CustomViewParserTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ void test_parse_CreatesACustomView() {
3131
List<CustomView> views = new ArrayList<>(context.getWorkspace().getViews().getCustomViews());
3232

3333
assertEquals(1, views.size());
34-
assertEquals("Custom1", views.get(0).getKey());
34+
assertEquals("Custom-1", views.get(0).getKey());
3535
assertEquals("", views.get(0).getTitle());
3636
assertEquals("", views.get(0).getDescription());
3737
}

src/test/java/com/structurizr/dsl/DeploymentViewParserTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ void test_parse_CreatesADeploymentViewWithNoScope() {
9696
List<DeploymentView> views = new ArrayList<>(this.views.getDeploymentViews());
9797

9898
assertEquals(1, views.size());
99-
assertEquals("Live-Deployment", views.get(0).getKey());
99+
assertEquals("Deployment-1", views.get(0).getKey());
100100
assertEquals("", views.get(0).getDescription());
101101
assertNull(views.get(0).getSoftwareSystem());
102102
}
@@ -163,7 +163,7 @@ void test_parse_CreatesADeploymentViewWithSoftwareSystemScope() {
163163
List<DeploymentView> views = new ArrayList<>(this.views.getDeploymentViews());
164164

165165
assertEquals(1, views.size());
166-
assertEquals("Name-Live-Deployment", views.get(0).getKey());
166+
assertEquals("Deployment-1", views.get(0).getKey());
167167
assertEquals("", views.get(0).getDescription());
168168
assertSame(softwareSystem, views.get(0).getSoftwareSystem());
169169
}

0 commit comments

Comments
 (0)