Skip to content

Commit

Permalink
feat: enforce FTL name rules in JVM (#2835)
Browse files Browse the repository at this point in the history
fixes: #2366
  • Loading branch information
stuartwdouglas authored Sep 26, 2024
1 parent ccac623 commit 13fa198
Showing 1 changed file with 48 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.regex.Pattern;

import org.jboss.jandex.ArrayType;
import org.jboss.jandex.ClassInfo;
Expand Down Expand Up @@ -56,6 +57,7 @@
import xyz.block.ftl.v1.schema.MetadataCalls;
import xyz.block.ftl.v1.schema.MetadataTypeMap;
import xyz.block.ftl.v1.schema.Module;
import xyz.block.ftl.v1.schema.Position;
import xyz.block.ftl.v1.schema.Ref;
import xyz.block.ftl.v1.schema.Time;
import xyz.block.ftl.v1.schema.Type;
Expand All @@ -74,6 +76,7 @@ public class ModuleBuilder {
public static final DotName OFFSET_DATE_TIME = DotName.createSimple(OffsetDateTime.class.getName());
public static final DotName GENERATED_REF = DotName.createSimple(GeneratedRef.class);
public static final DotName EXPORT = DotName.createSimple(Export.class);
private static final Pattern NAME_PATTERN = Pattern.compile("^[A-Za-z_][A-Za-z0-9_]*$");

private final IndexView index;
private final Module.Builder moduleBuilder;
Expand Down Expand Up @@ -176,7 +179,7 @@ public void registerVerbMethod(MethodInfo method, String className,
List<BiFunction<ObjectMapper, CallRequest, Object>> paramMappers = new ArrayList<>();
org.jboss.jandex.Type bodyParamType = null;
xyz.block.ftl.v1.schema.Verb.Builder verbBuilder = xyz.block.ftl.v1.schema.Verb.newBuilder();
String verbName = ModuleBuilder.methodToName(method);
String verbName = validateName(className, ModuleBuilder.methodToName(method));
MetadataCalls.Builder callsMetadata = MetadataCalls.newBuilder();
for (var param : method.parameters()) {
if (param.hasAnnotation(Secret.class)) {
Expand Down Expand Up @@ -400,6 +403,7 @@ public Type buildType(org.jboss.jandex.Type type, boolean export) {
.build();
} else {
ClassInfo classByName = index.getClassByName(paramType.name());
validateName(classByName.name().toString(), classByName.name().local());
var cb = ClassType.builder(classByName.name());
var main = buildType(cb.build(), export);
var builder = main.toBuilder();
Expand Down Expand Up @@ -446,6 +450,29 @@ private void buildDataElement(Data.Builder data, DotName className) {
}

public ModuleBuilder addDecls(Decl decl) {
if (decl.hasDatabase()) {
validateName(decl.getDatabase().getPos(), decl.getDatabase().getName());
} else if (decl.hasData()) {
validateName(decl.getData().getPos(), decl.getData().getName());
} else if (decl.hasConfig()) {
validateName(decl.getConfig().getPos(), decl.getConfig().getName());
} else if (decl.hasEnum()) {
validateName(decl.getEnum().getPos(), decl.getEnum().getName());
} else if (decl.hasSecret()) {
validateName(decl.getSecret().getPos(), decl.getSecret().getName());
} else if (decl.hasVerb()) {
validateName(decl.getVerb().getPos(), decl.getVerb().getName());
} else if (decl.hasTypeAlias()) {
validateName(decl.getTypeAlias().getPos(), decl.getTypeAlias().getName());
} else if (decl.hasTopic()) {
validateName(decl.getTopic().getPos(), decl.getTopic().getName());
} else if (decl.hasFsm()) {
validateName(decl.getFsm().getPos(), decl.getFsm().getName());
} else if (decl.hasSubscription()) {
validateName(decl.getSubscription().getPos(), decl.getSubscription().getName());
} else if (decl.hasTypeAlias()) {
validateName(decl.getTypeAlias().getPos(), decl.getTypeAlias().getName());
}
moduleBuilder.addDecls(decl);
return this;
}
Expand All @@ -463,6 +490,7 @@ public void writeTo(OutputStream out) throws IOException {
}

public void registerTypeAlias(String name, org.jboss.jandex.Type finalT, org.jboss.jandex.Type finalS, boolean exported) {
validateName(finalT.name().toString(), name);
moduleBuilder.addDecls(Decl.newBuilder()
.setTypeAlias(TypeAlias.newBuilder().setType(buildType(finalS, exported)).setName(name).addMetadata(Metadata
.newBuilder()
Expand All @@ -483,4 +511,23 @@ public enum BodyType {

record ValidationFailure(String className, String message) {
}

String validateName(Position position, String name) {
//we group all validation failures together so we can report them all at once
if (!NAME_PATTERN.matcher(name).matches()) {
validationFailures.add(
new ValidationFailure(position == null ? "<unknown>" : position.getFilename() + ":" + position.getLine(),
String.format("Invalid name %s, must match " + NAME_PATTERN, name)));
}
return name;
}

String validateName(String className, String name) {
//we group all validation failures together so we can report them all at once
if (!NAME_PATTERN.matcher(name).matches()) {
validationFailures
.add(new ValidationFailure(className, String.format("Invalid name %s, must match " + NAME_PATTERN, name)));
}
return name;
}
}

0 comments on commit 13fa198

Please sign in to comment.