Skip to content

Commit d67c3da

Browse files
committed
use branded types for enums
1 parent c75732d commit d67c3da

16 files changed

Lines changed: 393 additions & 37 deletions

File tree

jsinterop-ts-defs-doclet/src/test/java/com/vertispan/tsdefs/tests/tsdocs/doclet/DocletTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,9 @@ public void testMethodsLinks() throws IOException {
7272
public void testIssue99() throws IOException {
7373
testDocs("links.issue99");
7474
}
75+
76+
@Test
77+
public void brandedTypes() throws IOException {
78+
testDocs("branded");
79+
}
7580
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright © 2023 Vertispan
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.vertispan.tsdefs.tests.tsdocs.doclet.branded;
17+
18+
import jsinterop.annotations.JsType;
19+
20+
/** Branded types enum test */
21+
@JsType
22+
public enum Direction {
23+
LEFT,
24+
RIGHT,
25+
UP,
26+
DOWN
27+
}

jsinterop-ts-defs-impl/src/main/java/com/vertispan/tsdefs/impl/Formatting.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class Formatting {
2626
public static final String NONE = "";
2727

2828
public static final String NEW_LINE = "\n";
29+
public static final String CR = "\r";
2930
public static final String SPACE = " ";
3031
public static final String END_LINE = ";";
3132
public static final String COMMA = ", ";

jsinterop-ts-defs-impl/src/main/java/com/vertispan/tsdefs/impl/builders/TsElement.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,10 @@ public boolean isClass() {
665665
return element.getKind().isClass() && !isTsInterface();
666666
}
667667

668+
public boolean isEnum() {
669+
return ElementKind.ENUM == element.getKind();
670+
}
671+
668672
public boolean isMethod() {
669673
return ElementKind.METHOD.equals(element.getKind());
670674
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright © 2023 Vertispan
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.vertispan.tsdefs.impl.model;
17+
18+
import static com.vertispan.tsdefs.impl.Formatting.NEW_LINE;
19+
20+
public class TsBrand {
21+
private final String name;
22+
private final String namespace;
23+
private final TsType type;
24+
25+
public TsBrand(String name, String namespace) {
26+
this.name = name;
27+
this.namespace = namespace;
28+
this.type = new TsType(name + "Type", namespace);
29+
}
30+
31+
public String emit(String indent) {
32+
StringBuffer sb = new StringBuffer();
33+
sb.append(indent);
34+
sb.append("const " + name + "__brand: unique symbol");
35+
sb.append(NEW_LINE);
36+
sb.append(indent);
37+
sb.append("type Brand<B> = { [" + name + "__brand]: B }");
38+
sb.append(NEW_LINE);
39+
sb.append(indent);
40+
sb.append("export type Branded<T, B> = T & Brand<B>");
41+
sb.append(NEW_LINE);
42+
sb.append(indent);
43+
sb.append("type " + name + "Type = Branded<string, \"" + name + "\">;");
44+
sb.append(NEW_LINE);
45+
sb.append(indent);
46+
return sb.toString();
47+
}
48+
49+
public TsType getType() {
50+
return this.type;
51+
}
52+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright © 2023 Vertispan
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.vertispan.tsdefs.impl.model;
17+
18+
import static com.vertispan.tsdefs.impl.Formatting.NEW_LINE;
19+
20+
import com.vertispan.tsdefs.impl.builders.HasDocs;
21+
import com.vertispan.tsdefs.impl.builders.HasFunctions;
22+
import com.vertispan.tsdefs.impl.builders.HasNamespace;
23+
import java.util.Arrays;
24+
import java.util.LinkedHashSet;
25+
import java.util.Set;
26+
27+
public class TsBrandedType implements HasNamespace {
28+
private final String name;
29+
private final String namespace;
30+
private TsType type;
31+
private final Set<TsModifier> modifiers = new LinkedHashSet<>();
32+
private final Set<String> enumerations = new LinkedHashSet<>();
33+
private final Set<TsMethod> functions = new LinkedHashSet<>();
34+
private TsDoc tsDoc;
35+
private boolean deprecated;
36+
37+
private TsBrandedType(String name, String namespace, TsType type) {
38+
this.name = name;
39+
this.namespace = namespace;
40+
this.type = type;
41+
}
42+
43+
public static TsBrandedType.TsBrandedTypeBuilder builder(
44+
String name, String namespace, TsType type) {
45+
return new TsBrandedType.TsBrandedTypeBuilder(name, namespace, type);
46+
}
47+
48+
public String getName() {
49+
return name;
50+
}
51+
52+
public String getNamespace() {
53+
return namespace;
54+
}
55+
56+
public TsType getType() {
57+
return type;
58+
}
59+
60+
public String emit(String indent, String parentNamespace) {
61+
StringBuffer sb = new StringBuffer();
62+
63+
TsBrand tsBrand = new TsBrand(name, namespace);
64+
sb.append(tsBrand.emit(indent));
65+
sb.append(NEW_LINE);
66+
67+
TsClass.TsClassBuilder classBuilder =
68+
TsClass.builder(name, namespace).addModifiers(TsModifier.EXPORT).setDocs(tsDoc);
69+
enumerations.stream()
70+
.map(
71+
enumeration ->
72+
TsProperty.builder(enumeration, tsBrand.getType())
73+
.setDocs(TsDoc.empty())
74+
.addModifiers(TsModifier.STATIC, TsModifier.READONLY)
75+
.build())
76+
.forEach(classBuilder::addProperty);
77+
78+
functions.forEach(classBuilder::addFunction);
79+
80+
sb.append(classBuilder.build().emit(indent, parentNamespace));
81+
82+
return sb.toString();
83+
}
84+
85+
public static class TsBrandedTypeBuilder
86+
implements HasDocs<TsBrandedType.TsBrandedTypeBuilder>,
87+
HasFunctions<TsBrandedType.TsBrandedTypeBuilder> {
88+
private final TsBrandedType tsEnum;
89+
90+
private TsBrandedTypeBuilder(String name, String namespace, TsType type) {
91+
this.tsEnum = new TsBrandedType(name, namespace, type);
92+
}
93+
94+
public TsBrandedType.TsBrandedTypeBuilder addEnumeration(String name) {
95+
this.tsEnum.enumerations.add(name);
96+
return this;
97+
}
98+
99+
public TsBrandedType.TsBrandedTypeBuilder addModifiers(TsModifier... modifiers) {
100+
this.tsEnum.modifiers.addAll(Arrays.asList(modifiers));
101+
return this;
102+
}
103+
104+
@Override
105+
public TsBrandedType.TsBrandedTypeBuilder setDocs(TsDoc tsDoc) {
106+
this.tsEnum.tsDoc = tsDoc;
107+
return this;
108+
}
109+
110+
public TsBrandedType.TsBrandedTypeBuilder setDeprecated(boolean deprecated) {
111+
this.tsEnum.deprecated = deprecated;
112+
return this;
113+
}
114+
115+
@Override
116+
public TsBrandedType.TsBrandedTypeBuilder addFunction(TsMethod function) {
117+
this.tsEnum.functions.add(function);
118+
return this;
119+
}
120+
121+
public TsBrandedType build() {
122+
return this.tsEnum;
123+
}
124+
}
125+
}

jsinterop-ts-defs-impl/src/main/java/com/vertispan/tsdefs/impl/model/TsNamespace.java

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ public class TsNamespace {
2828
private List<TsInterface> tsInterfaces = new ArrayList<>();
2929
private List<TsFunction> tsFunctions = new ArrayList<>();
3030
private List<TsClass> tsClasses = new ArrayList<>();
31-
private List<TsEnum> tsEnums = new ArrayList<>();
31+
private List<TsTypeDef> tsTypeDefs = new ArrayList<>();
32+
private List<TsBrandedType> tsBrandedTypes = new ArrayList<>();
3233

3334
public TsNamespace(String namespace) {
3435
this.namespace = namespace;
@@ -52,14 +53,19 @@ public void addFunction(TsFunction tsFunction) {
5253
this.tsFunctions.add(tsFunction);
5354
}
5455

55-
public void addTsEnum(TsEnum tsEnum) {
56-
this.tsEnums.add(tsEnum);
56+
public void addTsTypeDef(TsTypeDef tsTypeDef) {
57+
this.tsTypeDefs.add(tsTypeDef);
58+
}
59+
60+
public void addBrandedType(TsBrandedType tsBrandedType) {
61+
this.tsBrandedTypes.add(tsBrandedType);
5762
}
5863

5964
public boolean isEmpty() {
6065
return tsInterfaces.isEmpty()
6166
&& tsFunctions.isEmpty()
62-
&& tsEnums.isEmpty()
67+
&& tsTypeDefs.isEmpty()
68+
&& tsBrandedTypes.isEmpty()
6369
&& (tsClasses.isEmpty() || tsClasses.stream().allMatch(TsClass::isEmpty));
6470
}
6571

@@ -96,9 +102,16 @@ public String emit(String indent, String parentNamespace) {
96102
.collect(Collectors.joining(NEW_LINE, optionalln(tsClasses), optionalln(tsClasses))));
97103

98104
sb.append(
99-
tsEnums.stream()
100-
.map(tsEnum -> tsEnum.emit(indent + INDENT, namespace))
101-
.collect(Collectors.joining(NEW_LINE, optionalln(tsEnums), optionalln(tsEnums))));
105+
tsTypeDefs.stream()
106+
.map(tsTypeDef -> tsTypeDef.emit(indent + INDENT, namespace))
107+
.collect(Collectors.joining(NEW_LINE, optionalln(tsTypeDefs), optionalln(tsTypeDefs))));
108+
109+
sb.append(
110+
tsBrandedTypes.stream()
111+
.map(tsTypeDef -> tsTypeDef.emit(indent + INDENT, namespace))
112+
.collect(
113+
Collectors.joining(
114+
NEW_LINE, optionalln(tsBrandedTypes), optionalln(tsBrandedTypes))));
102115

103116
sb.append("}").append(NEW_LINE);
104117

jsinterop-ts-defs-impl/src/main/java/com/vertispan/tsdefs/impl/model/TsEnum.java renamed to jsinterop-ts-defs-impl/src/main/java/com/vertispan/tsdefs/impl/model/TsTypeDef.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import java.util.LinkedHashSet;
2626
import java.util.Set;
2727

28-
public class TsEnum implements HasNamespace {
28+
public class TsTypeDef implements HasNamespace {
2929
private final String name;
3030
private final String namespace;
3131
private TsCustomType type;
@@ -35,7 +35,7 @@ public class TsEnum implements HasNamespace {
3535
private TsDoc tsDoc;
3636
private boolean deprecated;
3737

38-
private TsEnum(String name, String namespace, TsCustomType type) {
38+
private TsTypeDef(String name, String namespace, TsCustomType type) {
3939
this.name = name;
4040
this.namespace = namespace;
4141
this.type = type;
@@ -84,41 +84,41 @@ public String emit(String indent, String parentNamespace) {
8484
}
8585

8686
public static class TsEnumBuilder implements HasDocs<TsEnumBuilder>, HasFunctions<TsEnumBuilder> {
87-
private final TsEnum tsEnum;
87+
private final TsTypeDef tsTypeDef;
8888

8989
private TsEnumBuilder(String name, String namespace, TsCustomType type) {
90-
this.tsEnum = new TsEnum(name, namespace, type);
90+
this.tsTypeDef = new TsTypeDef(name, namespace, type);
9191
}
9292

9393
public TsEnumBuilder addEnumeration(String name) {
94-
this.tsEnum.enumerations.add(name);
94+
this.tsTypeDef.enumerations.add(name);
9595
return this;
9696
}
9797

9898
public TsEnumBuilder addModifiers(TsModifier... modifiers) {
99-
this.tsEnum.modifiers.addAll(Arrays.asList(modifiers));
99+
this.tsTypeDef.modifiers.addAll(Arrays.asList(modifiers));
100100
return this;
101101
}
102102

103103
@Override
104104
public TsEnumBuilder setDocs(TsDoc tsDoc) {
105-
this.tsEnum.tsDoc = tsDoc;
105+
this.tsTypeDef.tsDoc = tsDoc;
106106
return this;
107107
}
108108

109109
public TsEnumBuilder setDeprecated(boolean deprecated) {
110-
this.tsEnum.deprecated = deprecated;
110+
this.tsTypeDef.deprecated = deprecated;
111111
return this;
112112
}
113113

114114
@Override
115115
public TsEnumBuilder addFunction(TsMethod function) {
116-
this.tsEnum.functions.add(function);
116+
this.tsTypeDef.functions.add(function);
117117
return this;
118118
}
119119

120-
public TsEnum build() {
121-
return this.tsEnum;
120+
public TsTypeDef build() {
121+
return this.tsTypeDef;
122122
}
123123
}
124124
}

0 commit comments

Comments
 (0)