Skip to content

Commit 25d8f24

Browse files
Improve JsonSchema for autocompletion (#2474)
* Add support for `title` in JSON schema generation * optimized schema for vc code autocompletion * adjust test
1 parent f6e4db3 commit 25d8f24

5 files changed

Lines changed: 65 additions & 34 deletions

File tree

annot/src/main/java/com/predic8/membrane/annot/generator/JsonSchemaGenerator.java

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,28 @@
1313
limitations under the License. */
1414
package com.predic8.membrane.annot.generator;
1515

16-
import com.fasterxml.jackson.databind.node.*;
17-
import com.predic8.membrane.annot.*;
18-
import com.predic8.membrane.annot.generator.kubernetes.*;
16+
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
17+
import com.predic8.membrane.annot.ProcessingException;
18+
import com.predic8.membrane.annot.generator.kubernetes.AbstractGrammar;
1919
import com.predic8.membrane.annot.generator.kubernetes.model.*;
2020
import com.predic8.membrane.annot.model.*;
21-
import com.predic8.membrane.annot.model.doc.*;
22-
import org.jetbrains.annotations.*;
23-
24-
import javax.annotation.processing.*;
25-
import javax.lang.model.element.*;
26-
import javax.tools.*;
27-
import java.io.*;
28-
import java.util.*;
29-
import java.util.stream.*;
21+
import com.predic8.membrane.annot.model.doc.Doc;
22+
import org.jetbrains.annotations.NotNull;
23+
24+
import javax.annotation.processing.ProcessingEnvironment;
25+
import javax.lang.model.element.Element;
26+
import javax.lang.model.element.TypeElement;
27+
import javax.tools.FileObject;
28+
import java.io.BufferedWriter;
29+
import java.io.IOException;
30+
import java.util.ArrayList;
31+
import java.util.HashMap;
32+
import java.util.List;
33+
import java.util.Map;
3034

3135
import static com.predic8.membrane.annot.generator.kubernetes.model.SchemaFactory.*;
32-
import static com.predic8.membrane.annot.generator.util.SchemaGeneratorUtil.*;
33-
import static javax.tools.StandardLocation.*;
36+
import static com.predic8.membrane.annot.generator.util.SchemaGeneratorUtil.escapeJsonContent;
37+
import static javax.tools.StandardLocation.CLASS_OUTPUT;
3438

3539
/**
3640
* TODOs:
@@ -76,13 +80,20 @@ private void assemble(Model m, MainInfo main) throws IOException {
7680

7781
private void addTopLevelProperties(Model m, MainInfo main) {
7882
schema.additionalProperties(false);
79-
List<AbstractSchema<?>> kinds = main.getElements().values().stream()
83+
84+
var top = main.getElements().values().stream()
8085
.filter(e -> e.getAnnotation().topLevel())
81-
.map(e -> createTopLevelProperty(e, m))
82-
.collect(Collectors.toUnmodifiableList());
86+
.toList();
87+
88+
for (ElementInfo e : top) {
89+
String name = e.getAnnotation().name();
90+
String refName = "#/$defs/" + e.getXSDTypeName(m);
91+
schema.property(ref(name).ref(refName));
92+
}
8393

84-
if (!kinds.isEmpty())
85-
schema.oneOf(kinds);
94+
if (!top.isEmpty()) {
95+
schema.minProperties(1).maxProperties(1);
96+
}
8697
}
8798

8899
private AbstractSchema<?> createTopLevelProperty(ElementInfo e, Model m) {
@@ -93,6 +104,7 @@ private AbstractSchema<?> createTopLevelProperty(ElementInfo e, Model m) {
93104
schema.property(ref(name).ref(refName));
94105

95106
return object()
107+
.title(name)
96108
.additionalProperties(false)
97109
.property(ref(name)
98110
.ref(refName)
@@ -251,17 +263,18 @@ private void processMCChilds(Model m, MainInfo main, ElementInfo i, AbstractSche
251263
continue;
252264

253265
sos.add(object()
266+
.title(ei.getAnnotation().name())
254267
.additionalProperties(false)
255268
.property(ref(ei.getAnnotation().name())
256-
.ref("#/$defs/" + ei.getXSDTypeName(m))
257-
.required(true)));
269+
.ref("#/$defs/" + ei.getXSDTypeName(m))));
258270
}
259271
// Allow referencing a component instance directly on list-item level:
260272
// flow:
261273
// - $ref: ...
262274
sos.add(object()
275+
.title("componentRef")
263276
.additionalProperties(false)
264-
.property( string("$ref").required(true)));
277+
.property( string("$ref")));
265278
return sos;
266279
}
267280

@@ -377,17 +390,17 @@ private SchemaObject createComponentsMapParser(Model m, MainInfo main, ElementIn
377390
var variants = new ArrayList<SchemaObject>();
378391

379392
for (ElementInfo comp : main.getElements().values()) {
380-
if (!comp.getAnnotation().component())
381-
continue;
393+
if (!comp.getAnnotation().component()) continue;
394+
if (comp.getAnnotation().topLevel()) continue;
382395

383-
if (comp.getAnnotation().topLevel())
384-
continue;
396+
String n = comp.getAnnotation().name();
385397

386398
variants.add(object()
399+
.title(n)
387400
.additionalProperties(false)
388-
.property(ref(comp.getAnnotation().name())
389-
.ref("#/$defs/" + comp.getXSDTypeName(m))
390-
.required(true)));
401+
.minProperties(1)
402+
.property(ref(n)
403+
.ref("#/$defs/" + comp.getXSDTypeName(m))));
391404
}
392405
return variants;
393406
}

annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/AbstractSchema.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public abstract class AbstractSchema<T extends AbstractSchema<T>> implements ISc
2222

2323
protected static final JsonNodeFactory jnf = JsonNodeFactory.instance;
2424

25+
protected String title;
2526
protected String name;
2627
protected String type;
2728
protected String description;
@@ -63,6 +64,11 @@ public T required(boolean b) {
6364
return self();
6465
}
6566

67+
public T title(String title) {
68+
this.title = title;
69+
return self();
70+
}
71+
6672
public T name(String name) {
6773
this.name = name;
6874
return self();
@@ -84,8 +90,12 @@ public boolean isObject() {
8490

8591
@Override
8692
public ObjectNode json(ObjectNode node) {
93+
if (title != null && !title.isBlank())
94+
node.put("title", title);
95+
8796
if (type != null)
8897
node.put("type", type);
98+
8999
return node;
90100
}
91101
}

annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/Schema.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@
1313
limitations under the License. */
1414
package com.predic8.membrane.annot.generator.kubernetes.model;
1515

16-
import com.fasterxml.jackson.databind.*;
17-
import com.fasterxml.jackson.databind.node.*;
18-
import com.fasterxml.jackson.databind.util.*;
16+
import com.fasterxml.jackson.databind.node.ObjectNode;
1917

20-
import java.util.*;
18+
import java.util.ArrayList;
19+
import java.util.List;
2120

2221
import static com.predic8.membrane.annot.generator.kubernetes.model.SchemaFactory.OBJECT;
2322

annot/src/main/java/com/predic8/membrane/annot/generator/kubernetes/model/SchemaObject.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ public class SchemaObject extends AbstractSchema<SchemaObject> {
3131
private List<AbstractSchema<?>> allOf;
3232
private final Map<String, AbstractSchema<?>> patternProperties = new LinkedHashMap<>();
3333

34+
private Integer minProperties;
35+
private Integer maxProperties;
36+
3437
SchemaObject(String name) {
3538
super(name);
3639
type = OBJECT;
@@ -47,6 +50,9 @@ public class SchemaObject extends AbstractSchema<SchemaObject> {
4750
public ObjectNode json(ObjectNode node) {
4851
super.json(node);
4952

53+
if (minProperties != null) node.put("minProperties", minProperties);
54+
if (maxProperties != null) node.put("maxProperties", maxProperties);
55+
5056
if (!additionalProperties && isObject()) {
5157
node.put("additionalProperties", false);
5258
}
@@ -168,6 +174,9 @@ public SchemaObject allOf(List<AbstractSchema<?>> allOf) {
168174
return this;
169175
}
170176

177+
public SchemaObject minProperties(int n) { this.minProperties = n; return this; }
178+
public SchemaObject maxProperties(int n) { this.maxProperties = n; return this; }
179+
171180
public boolean hasProperty(String name) {
172181
return properties.stream().anyMatch(p -> name.equals(p.getName()));
173182
}

annot/src/test/java/com/predic8/membrane/annot/YAMLComponentsParsingTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ public void componentDefinitionWithNoComponentKeyError() {
211211
components:
212212
x: {}
213213
"""));
214-
assertSchemaErrorContains(ex, "required property", "not found");
214+
assertSchemaErrorContains(ex, "must have at least 1 properties");
215215
}
216216

217217
@Test

0 commit comments

Comments
 (0)