Skip to content

Commit def6e59

Browse files
authored
22 ts const enum (#84)
* Add option for ts enum format * Render ts const enum
1 parent 0f8b712 commit def6e59

21 files changed

Lines changed: 274 additions & 114 deletions

File tree

annotation/src/main/java/online/sharedtype/SharedType.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,12 @@
159159
*/
160160
String[] typescriptOptionalFieldFormat() default {};
161161

162+
/**
163+
* Format of enum in Typescript.
164+
* @return either "union" (union types) or "const_enum" (const enum). If empty, fallback to global default.
165+
*/
166+
String typescriptEnumFormat() default "";
167+
162168
/**
163169
* Mark a method as an accessor regardless of its name.
164170
* Getter prefixes are configured in global properties.

client-test/typescript/src/types.java17.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
22
type DependencyClassA, type DependencyClassB, type DependencyClassC, type EnumGalaxy, type EnumSize,
3-
type EnumTShirt, type JavaRecord, type AnotherJavaClass, type RecursiveClass, type MapClass,
3+
EnumTShirt, type JavaRecord, type AnotherJavaClass, type RecursiveClass, type MapClass,
44
type OptionalMethod,
55
} from "./index.java17";
66

@@ -11,6 +11,7 @@ export const record1: Record<EnumTShirt, number> = {
1111
L: 3,
1212
}
1313
export const size1: EnumSize = 1;
14+
export const tshirtSize1: EnumTShirt = EnumTShirt.S;
1415

1516
export const dependencyClassC: DependencyClassC = {
1617
};

it/java8/src/main/java/online/sharedtype/it/java8/EnumSize.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
import lombok.RequiredArgsConstructor;
44
import online.sharedtype.SharedType;
55

6-
@SharedType(rustMacroTraits = {"PartialEq", "Eq", "Hash", "serde::Serialize", "serde::Deserialize"})
6+
@SharedType(
7+
rustMacroTraits = {"PartialEq", "Eq", "Hash", "serde::Serialize", "serde::Deserialize"},
8+
typescriptEnumFormat = "const_enum"
9+
)
710
@RequiredArgsConstructor
811
public enum EnumSize {
912
SMALL(1), MEDIUM(2), LARGE(3);

it/java8/src/main/java/online/sharedtype/it/java8/EnumTShirt.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import lombok.Getter;
44
import online.sharedtype.SharedType;
55

6-
@SharedType
6+
@SharedType(typescriptEnumFormat = "const_enum")
77
@Getter
88
public enum EnumTShirt {
99
S(EnumSize.SMALL, "S"),

processor/src/main/java/online/sharedtype/processor/context/Config.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.EnumSet;
1313
import java.util.List;
1414
import java.util.Set;
15+
import java.util.function.Function;
1516

1617
/**
1718
* Config wrappers.
@@ -30,6 +31,8 @@ public final class Config {
3031
private final boolean constantNamespaced;
3132
@Getter
3233
private final Set<Props.Typescript.OptionalFieldFormat> typescriptOptionalFieldFormats;
34+
@Getter
35+
private final Props.Typescript.EnumFormat typescriptEnumFormat;
3336

3437
@Retention(RetentionPolicy.RUNTIME)
3538
@interface AnnoContainer {
@@ -50,6 +53,7 @@ public Config(TypeElement typeElement, Context ctx) {
5053
this.includedComponentTypes = includedCompTypes.isEmpty() ? Collections.emptySet() : EnumSet.copyOf(includedCompTypes);
5154
constantNamespaced = evaluateOptionalBool(anno.constantNamespaced(), ctx.getProps().isConstantNamespaced());
5255
typescriptOptionalFieldFormats = parseTsOptionalFieldFormats(anno, ctx);
56+
typescriptEnumFormat = parseTsEnumFormat(anno, ctx);
5357
}
5458

5559
public boolean includes(SharedType.ComponentType componentType) {
@@ -69,16 +73,26 @@ private static boolean evaluateOptionalBool(SharedType.OptionalBool optionalBool
6973

7074
private static Set<Props.Typescript.OptionalFieldFormat> parseTsOptionalFieldFormats(SharedType anno, Context ctx) {
7175
if (anno.typescriptOptionalFieldFormat().length > 0) {
72-
EnumSet<Props.Typescript.OptionalFieldFormat> formats = EnumSet.noneOf(Props.Typescript.OptionalFieldFormat.class);
73-
for (String value : anno.typescriptOptionalFieldFormat()) {
74-
try {
75-
formats.add(Props.Typescript.OptionalFieldFormat.fromString(value));
76-
} catch (IllegalArgumentException e) {
77-
throw new SharedTypeException(String.format("Invalid value for SharedType.typescriptOptionalFieldFormat: '%s', only '?', 'null', 'undefined' are allowed.", value), e);
78-
}
76+
List<String> values = Arrays.asList(anno.typescriptOptionalFieldFormat());
77+
try {
78+
return EnumParsingUtils.parseEnumSet(values, Props.Typescript.OptionalFieldFormat.class, Props.Typescript.OptionalFieldFormat::fromString);
79+
} catch (IllegalArgumentException e) {
80+
throw new SharedTypeException(String.format(
81+
"Invalid value for SharedType.typescriptOptionalFieldFormat: %s, only '?', 'null', 'undefined' are allowed.", values), e);
7982
}
80-
return formats;
8183
}
8284
return ctx.getProps().getTypescript().getOptionalFieldFormats();
8385
}
86+
87+
private static Props.Typescript.EnumFormat parseTsEnumFormat(SharedType anno, Context ctx) {
88+
if (anno.typescriptEnumFormat() != null && !anno.typescriptEnumFormat().isEmpty()) {
89+
try {
90+
return Props.Typescript.EnumFormat.fromString(anno.typescriptEnumFormat());
91+
} catch (IllegalArgumentException e) {
92+
throw new SharedTypeException(String.format(
93+
"Invalid value for SharedType.typescriptEnumFormat: '%s', only 'union' or 'const_enum' is allowed.", anno.typescriptEnumFormat()), e);
94+
}
95+
}
96+
return ctx.getProps().getTypescript().getEnumFormat();
97+
}
8498
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package online.sharedtype.processor.context;
2+
3+
import lombok.experimental.UtilityClass;
4+
5+
import java.util.Collection;
6+
import java.util.EnumSet;
7+
import java.util.Set;
8+
import java.util.function.Function;
9+
10+
@UtilityClass
11+
final class EnumParsingUtils {
12+
static <T extends Enum<T>> Set<T> parseEnumSet(Collection<String> values, Class<T> type, Function<String, T> enumValueOf) {
13+
Set<T> set = EnumSet.noneOf(type);
14+
for (String trimmed : values) {
15+
set.add(enumValueOf.apply(trimmed));
16+
}
17+
return set;
18+
}
19+
}

processor/src/main/java/online/sharedtype/processor/context/Props.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public static final class Typescript {
3535
private final char interfacePropertyDelimiter;
3636
private final String javaObjectMapType;
3737
private final Set<OptionalFieldFormat> optionalFieldFormats;
38+
private final EnumFormat enumFormat;
3839

3940
@Getter
4041
public enum OptionalFieldFormat {
@@ -55,6 +56,14 @@ public static OptionalFieldFormat fromString(String value) {
5556
throw new IllegalArgumentException(String.format("Unknown optional field format: '%s', only '?', 'null', 'undefined' are allowed", value));
5657
}
5758
}
59+
60+
public enum EnumFormat {
61+
UNION, CONST_ENUM,
62+
;
63+
public static EnumFormat fromString(String value) {
64+
return EnumFormat.valueOf(value.toUpperCase());
65+
}
66+
}
5867
}
5968

6069
@Builder(access = AccessLevel.PACKAGE)

processor/src/main/java/online/sharedtype/processor/context/PropsFactory.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import java.io.InputStream;
77
import java.nio.file.Files;
88
import java.nio.file.Path;
9-
import java.util.EnumSet;
109
import java.util.LinkedHashSet;
1110
import java.util.Properties;
1211
import java.util.Set;
@@ -54,8 +53,9 @@ private static Props loadProps(Properties properties) {
5453
.outputFileName(properties.getProperty("sharedtype.typescript.output-file-name"))
5554
.interfacePropertyDelimiter(properties.getProperty("sharedtype.typescript.interface-property-delimiter").charAt(0))
5655
.javaObjectMapType(properties.getProperty("sharedtype.typescript.java-object-map-type"))
57-
.optionalFieldFormats(parseEnumSet(properties,"sharedtype.typescript.optional-field-format",
56+
.optionalFieldFormats(parseEnumSet(properties, "sharedtype.typescript.optional-field-format",
5857
Props.Typescript.OptionalFieldFormat.class, Props.Typescript.OptionalFieldFormat::fromString))
58+
.enumFormat(parseEnum(properties, "sharedtype.typescript.enum-format", Props.Typescript.EnumFormat::fromString))
5959
.build())
6060
.rust(Props.Rust.builder()
6161
.outputFileName(properties.getProperty("sharedtype.rust.output-file-name"))
@@ -68,15 +68,11 @@ private static Props loadProps(Properties properties) {
6868

6969
private static <T extends Enum<T>> Set<T> parseEnumSet(Properties properties, String propertyName, Class<T> type, Function<String, T> enumValueOf) {
7070
Set<String> trimmedElems = splitArray(properties.getProperty(propertyName));
71-
Set<T> set = EnumSet.noneOf(type);
7271
try {
73-
for (String trimmed : trimmedElems) {
74-
set.add(enumValueOf.apply(trimmed));
75-
}
72+
return EnumParsingUtils.parseEnumSet(trimmedElems, type, enumValueOf);
7673
} catch (Exception e) {
7774
throw new IllegalArgumentException(String.format("Failed to parse property '%s'", propertyName), e);
7875
}
79-
return set;
8076
}
8177

8278
private static Set<String> splitArray(String value) {
@@ -99,7 +95,7 @@ private static boolean parseBoolean(Properties properties, String key) {
9995
if ("false".equals(value)) {
10096
return false;
10197
}
102-
throw new SharedTypeException(String.format("property '%s', can only be 'true' or 'false'.", key));
98+
throw new IllegalArgumentException(String.format("property '%s', can only be 'true' or 'false'.", key));
10399
}
104100

105101
private static <T> Set<Class<? extends T>> parseClassSet(Properties properties, String propertyName) {
@@ -110,12 +106,21 @@ private static <T> Set<Class<? extends T>> parseClassSet(Properties properties,
110106
try {
111107
annotations.add(parseClass(propertyValue));
112108
} catch (ClassNotFoundException e) {
113-
throw new SharedTypeException(String.format("Invalid property %s=%s", propertyName, value), e);
109+
throw new IllegalArgumentException(String.format("Invalid property %s=%s", propertyName, value), e);
114110
}
115111
}
116112
return annotations;
117113
}
118114

115+
private static <T extends Enum<T>> T parseEnum(Properties properties, String propertyName, Function<String, T> fromString) {
116+
String value = properties.getProperty(propertyName);
117+
try {
118+
return fromString.apply(value);
119+
} catch (Exception e) {
120+
throw new IllegalArgumentException(String.format("Invalid property %s=%s", propertyName, value), e);
121+
}
122+
}
123+
119124
@SuppressWarnings("unchecked")
120125
private static <T> Class<? extends T> parseClass(String className) throws ClassNotFoundException {
121126
return (Class<? extends T>) Class.forName(className);

processor/src/main/java/online/sharedtype/processor/writer/converter/EnumUnionExpr.java

Lines changed: 0 additions & 16 deletions
This file was deleted.

processor/src/main/java/online/sharedtype/processor/writer/converter/TemplateDataConverter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public interface TemplateDataConverter {
1919
static Set<TemplateDataConverter> typescript(Context ctx) {
2020
Set<TemplateDataConverter> converters = new HashSet<>(3);
2121
converters.add(new TypescriptInterfaceConverter(ctx, TypeExpressionConverter.typescript(ctx)));
22-
converters.add(new TypescriptEnumUnionConverter());
22+
converters.add(new TypescriptEnumConverter(ctx));
2323
converters.add(new ConstantConverter(ctx, null, OutputTarget.TYPESCRIPT));
2424
return converters;
2525
}

0 commit comments

Comments
 (0)