
com.structurizr.dsl.ElementStyleParser Maven / Gradle / Ivy
The newest version!
package com.structurizr.dsl;
import com.structurizr.Workspace;
import com.structurizr.util.ImageUtils;
import com.structurizr.util.StringUtils;
import com.structurizr.view.Border;
import com.structurizr.view.ElementStyle;
import com.structurizr.view.Shape;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
final class ElementStyleParser extends AbstractParser {
private static final int FIRST_PROPERTY_INDEX = 1;
ElementStyle parseElementStyle(DslContext context, Tokens tokens) {
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: element {");
} else if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String tag = tokens.get(1);
if (StringUtils.isNullOrEmpty(tag)) {
throw new RuntimeException("A tag must be specified");
}
Workspace workspace = context.getWorkspace();
ElementStyle elementStyle = workspace.getViews().getConfiguration().getStyles().getElementStyle(tag);
if (elementStyle == null) {
elementStyle = workspace.getViews().getConfiguration().getStyles().addElementStyle(tag);
}
return elementStyle;
} else {
throw new RuntimeException("Expected: element {");
}
}
void parseShape(ElementStyleDslContext context, Tokens tokens) {
Map shapes = new HashMap<>();
String shapesAsString = "";
for (Shape shape : Shape.values()) {
shapes.put(shape.toString().toLowerCase(), shape);
shapesAsString += shape;
shapesAsString += "|";
}
shapesAsString = shapesAsString.substring(0, shapesAsString.length()-1);
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: shape <" + shapesAsString + ">");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String shape = tokens.get(1).toLowerCase();
if (shapes.containsKey(shape)) {
style.setShape(shapes.get(shape));
} else {
throw new RuntimeException("The shape \"" + shape + "\" is not valid");
}
} else {
throw new RuntimeException("Expected: shape <" + shapesAsString + ">");
}
}
void parseBackground(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: background <#rrggbb|color name>");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String colour = tokens.get(1);
style.setBackground(colour);
} else {
throw new RuntimeException("Expected: background <#rrggbb|color name>");
}
}
void parseStroke(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: stroke <#rrggbb|color name>");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String colour = tokens.get(1);
style.setStroke(colour);
} else {
throw new RuntimeException("Expected: stroke <#rrggbb|color name>");
}
}
void parseStrokeWidth(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: strokeWidth <1-10>");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String strokeWidthAsString = tokens.get(1);
try {
int strokeWidth = Integer.parseInt(strokeWidthAsString);
style.setStrokeWidth(strokeWidth);
} catch (NumberFormatException e) {
throw new RuntimeException("Stroke width must be an integer between 1 and 10");
}
} else {
throw new RuntimeException("Expected: strokeWidth <1-10>");
}
}
void parseColour(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: colour <#rrggbb|color name>");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String colour = tokens.get(1);
style.setColor(colour);
} else {
throw new RuntimeException("Expected: colour <#rrggbb|color name>");
}
}
void parseBorder(ElementStyleDslContext context, Tokens tokens) {
Map borders = new HashMap<>();
for (Border border : Border.values()) {
borders.put(border.toString().toLowerCase(), border);
}
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: border ");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String border = tokens.get(1).toLowerCase();
if (borders.containsKey(border)) {
style.setBorder(borders.get(border));
} else {
throw new RuntimeException("The border \"" + border + "\" is not valid");
}
} else {
throw new RuntimeException("Expected: border ");
}
}
void parseOpacity(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: opacity <0-100>");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String opacityAsString = tokens.get(1);
try {
int opacity = Integer.parseInt(opacityAsString);
style.setOpacity(opacity);
} catch (NumberFormatException e) {
throw new RuntimeException("Opacity must be an integer between 0 and 100");
}
} else {
throw new RuntimeException("Expected: opacity <0-100>");
}
}
void parseWidth(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: width ");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String widthAsString = tokens.get(1);
try {
int width = Integer.parseInt(widthAsString);
style.setWidth(width);
} catch (RuntimeException e) {
throw new IllegalArgumentException("Width must be a positive integer");
}
} else {
throw new RuntimeException("Expected: width ");
}
}
void parseHeight(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: height ");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String heightAsString = tokens.get(1);
try {
int height = Integer.parseInt(heightAsString);
style.setHeight(height);
} catch (NumberFormatException e) {
throw new RuntimeException("Height must be a positive integer");
}
} else {
throw new RuntimeException("Expected: height ");
}
}
void parseFontSize(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: fontSize ");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String fontSizeAsString = tokens.get(1);
try {
int fontSize = Integer.parseInt(fontSizeAsString);
style.setFontSize(fontSize);
} catch (NumberFormatException e) {
throw new RuntimeException("Font size must be a positive integer");
}
} else {
throw new RuntimeException("Expected: fontSize ");
}
}
void parseMetadata(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: metadata ");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String metadata = tokens.get(1);
if ("true".equalsIgnoreCase(metadata)) {
style.setMetadata(true);
} else if ("false".equalsIgnoreCase(metadata)) {
style.setMetadata(false);
} else {
throw new RuntimeException("Metadata must be true or false");
}
} else {
throw new RuntimeException("Expected: metadata ");
}
}
void parseDescription(ElementStyleDslContext context, Tokens tokens) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: description ");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String description = tokens.get(1);
if ("true".equalsIgnoreCase(description)) {
style.setDescription(true);
} else if ("false".equalsIgnoreCase(description)) {
style.setDescription(false);
} else {
throw new RuntimeException("Description must be true or false");
}
} else {
throw new RuntimeException("Expected: description ");
}
}
void parseIcon(ElementStyleDslContext context, Tokens tokens, boolean restricted) {
ElementStyle style = context.getStyle();
if (tokens.hasMoreThan(FIRST_PROPERTY_INDEX)) {
throw new RuntimeException("Too many tokens, expected: icon ");
}
if (tokens.includes(FIRST_PROPERTY_INDEX)) {
String path = tokens.get(1);
if (path.startsWith("data:image/") || path.startsWith("https://") || path.startsWith("http://")) {
if (IconUtils.isSupported(path)) {
style.setIcon(path);
} else {
throw new IllegalArgumentException("Only PNG and JPG URLs/data URIs are supported: " + path);
}
} else {
if (!restricted) {
File file = new File(context.getFile().getParent(), path);
if (file.exists() && !file.isDirectory()) {
try {
style.setIcon(ImageUtils.getImageAsDataUri(file));
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
throw new RuntimeException(path + " does not exist");
}
}
}
} else {
throw new RuntimeException("Expected: icon ");
}
}
}