diff --git a/.github/scripts/index.html b/.github/scripts/index.html index f3f4b41..49856de 100644 --- a/.github/scripts/index.html +++ b/.github/scripts/index.html @@ -3,12 +3,12 @@ - + content="0;url=PAGES_REDIRECT_URL"/> +

- This redirects to the latest Release Candidate here + This redirects to the latest Release Candidate here

\ No newline at end of file diff --git a/.github/workflows/autopublish.yaml b/.github/workflows/autopublish.yaml index 3300e33..fd8c608 100644 --- a/.github/workflows/autopublish.yaml +++ b/.github/workflows/autopublish.yaml @@ -19,7 +19,11 @@ jobs: chmod +x ./.github/scripts/checkout-tags.sh ./.github/scripts/checkout-tags.sh - name: Redirect top to head - run: cp .github/scripts/index.html . + run: | + REPO_OWNER="${GITHUB_REPOSITORY%%/*}" + REPO_NAME="${GITHUB_REPOSITORY##*/}" + PAGES_REDIRECT_URL="https://${REPO_OWNER}.github.io/${REPO_NAME}/2025-1-err1" + sed "s|PAGES_REDIRECT_URL|${PAGES_REDIRECT_URL}|g" .github/scripts/index.html > index.html - uses: actions/upload-pages-artifact@v3 with: path: . diff --git a/WEBSITE.md b/WEBSITE.md index 01d6c57..2721107 100644 --- a/WEBSITE.md +++ b/WEBSITE.md @@ -38,7 +38,7 @@ When wanting to pin and publish a snapshot in time via a separate url-path, foll When the content is finished, a release requires a first commit with 1. a tag with the exact version string (like `2025-1-RC1`) on the release commit -2. to change the redirect in `.github/scripts/index.html` to point to latest release candidate +2. to change the redirect target version in `.github/workflows/autopublish.yaml` (`PAGES_REDIRECT_URL`) to point to the latest release candidate (the URL is constructed dynamically from the repository owner and name) 3. set the `respecConfig.publishDate` in `index.html` to a string like `"2025-02-27"`,` 4. set the `respecConfig.specStatus` in `index.html` to `base` diff --git a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/SchemaTableGeneratorPlugin.java b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/SchemaTableGeneratorPlugin.java index 80ed744..b0cb45a 100644 --- a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/SchemaTableGeneratorPlugin.java +++ b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/SchemaTableGeneratorPlugin.java @@ -62,7 +62,7 @@ public void apply(@NotNull Project project) { var schemaModel = parser.parseFiles(stream); schemaModel.getSchemaTypes().stream() - .filter(type -> !type.isRootDefinition() && !type.isJsonBaseType()) // do not process built-in Json types and root schema types + .filter(type -> !type.isRootDefinition() && !type.isJsonBaseType() && !type.isNamedScalar()) // do not process built-in Json types and root schema types .forEach(type -> { var content = htmlTransformer.transform(type); var destination = new File(tablesDir, type.getName().toLowerCase() + ".html"); diff --git a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/JsomParser.java b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/JsomParser.java index de5bd2e..b8f87ee 100644 --- a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/JsomParser.java +++ b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/JsomParser.java @@ -146,6 +146,10 @@ private Stream parseTypes(String schemaPath, Map par var itemType = parseItemType(definition, baseType); var context = prefix + schemaPath.substring(resolutionPath.length()); var schemaType = new SchemaType(type, baseType, itemType, context); + var enumValues = (List) definition.get(ENUM); + if (enumValues != null) { + schemaType.enumValues(enumValues); + } parseAttributes(definition, schemaType); return schemaType; } @@ -209,6 +213,12 @@ private void parseReferences(Map definition, ConstraintType cons .toList(); schemaType.properties(properties); + if (constraintType == ConstraintType.ALL_OF) { + constraintDef.stream() + .filter(e -> e.get(REF) == null) + .forEach(e -> parseRequired(e, schemaType)); + } + // parse references var references = constraintDef .stream() diff --git a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/SchemaModelContext.java b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/SchemaModelContext.java index 53cc614..6e0b5b2 100644 --- a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/SchemaModelContext.java +++ b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/SchemaModelContext.java @@ -121,20 +121,22 @@ public void resolve() { .stream() .filter(ref -> ref.getResolvedProperty() == null) .forEach(ref -> { - // check in allOf + // check in allOf (transitively, since properties may be defined in nested allOf entries) var resolved = type.getResolvedAllOf().stream() - .flatMap(t -> t.getProperties().stream() + .flatMap(t -> t.getTransitiveProperties().stream() .map(p -> p.getName().equals(ref.getName()) ? p : null) .filter(Objects::nonNull)).findFirst().orElse(null); - ref.resolvedProperty(resolved); - - resolved = type.getResolvedOneOf().stream() - .flatMap(t -> t.getProperties().stream() - .map(p -> p.getName().equals(ref.getName()) ? p : null) - .filter(Objects::nonNull)).findFirst().orElse(null); + if (resolved == null) { + resolved = type.getResolvedOneOf().stream() + .flatMap(t -> t.getTransitiveProperties().stream() + .map(p -> p.getName().equals(ref.getName()) ? p : null) + .filter(Objects::nonNull)).findFirst().orElse(null); + } - ref.resolvedProperty(resolved); + if (resolved != null) { + ref.resolvedProperty(resolved); + } })); diff --git a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/SchemaType.java b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/SchemaType.java index 621ce98..4a2374a 100644 --- a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/SchemaType.java +++ b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/SchemaType.java @@ -54,6 +54,7 @@ public class SchemaType implements Comparable { private final Map optionalProperties = new HashMap<>(); private boolean jsonBaseType; // denotes if this type represents a base Json type, e.g. string, object, array + private final Set enumValues = new TreeSet<>(); /** * Ctor for base Json types. @@ -110,11 +111,31 @@ public String getSchemaUri() { return schemaUri; } + public Set getEnumValues() { + return enumValues; + } + + public void enumValues(Collection values) { + enumValues.addAll(values); + } + + public boolean isNamedScalar() { + return !jsonBaseType && properties.isEmpty() && resolvedAllOf.isEmpty() && resolvedOneOf.isEmpty(); + } + @NotNull public Set getProperties() { return properties; } + @NotNull + public Set getTransitiveProperties() { + return concat(properties.stream(), + concat(resolvedAllOf.stream().flatMap(t -> t.getTransitiveProperties().stream()), + resolvedOneOf.stream().flatMap(t -> t.getTransitiveProperties().stream()))) + .collect(toCollection(TreeSet::new)); + } + public Collection getRequiredProperties() { return requiredProperties.values(); } @@ -129,8 +150,8 @@ public Set getTransitiveRequiredProperties() { @NotNull public Set getTransitiveOptionalProperties() { - // a type may include multiple other types (allOf) where a property is optional in one but mandatory in another - filter it - var required = getRequiredProperties().stream().map(SchemaPropertyReference::getName).collect(Collectors.toSet()); + // a type may include multiple other types (allOf/oneOf) where a property is optional in one but mandatory in another - filter it + var required = getTransitiveRequiredProperties().stream().map(SchemaPropertyReference::getName).collect(Collectors.toSet()); return concat(optionalProperties.values().stream(), concat(resolvedAllOf.stream().flatMap(type -> type.getTransitiveOptionalProperties().stream()), resolvedOneOf.stream().flatMap(type -> type.getTransitiveOptionalProperties().stream()))) diff --git a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/transformer/HtmlTableTransformer.java b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/transformer/HtmlTableTransformer.java index 40ffb6d..7d89274 100644 --- a/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/transformer/HtmlTableTransformer.java +++ b/artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/transformer/HtmlTableTransformer.java @@ -40,6 +40,10 @@ public class HtmlTableTransformer implements SchemaTypeTransformer { public String transform(SchemaType schemaType) { var builder = new StringBuilder(CSS).append(""); builder.append(format("", schemaType.getName(), schemaType.getName())); + if (!schemaType.getEnumValues().isEmpty()) { + var values = schemaType.getEnumValues().stream().map(Object::toString).collect(Collectors.joining(", ")); + builder.append(format("", values)); + } transformProperties(schemaType.getTransitiveRequiredProperties(), true, builder); transformProperties(schemaType.getTransitiveOptionalProperties(), false, builder); return builder.append("
%s
%s
").toString(); @@ -64,7 +68,22 @@ private void transformProperty(SchemaPropertyReference propertyReference, boolea resolvedTypes = parseResolvedTypes(resolvedProperty); } builder.append(format("%s", resolvedTypes)); - if (resolvedProperty.getConstantValue() != null) { + + // if all resolved types are named scalars, render their base type and enum values + var namedScalars = resolvedProperty.getResolvedTypes().stream() + .filter(this::isNamedScalar) + .toList(); + if (!namedScalars.isEmpty() && namedScalars.size() == resolvedProperty.getResolvedTypes().size()) { + var enumValues = namedScalars.stream() + .flatMap(t -> t.getEnumValues().stream()) + .map(Object::toString) + .collect(Collectors.joining(", ")); + if (!enumValues.isEmpty()) { + builder.append(format("Must be one of:
%s", enumValues)); + } else { + builder.append(format("%s", resolvedProperty.getDescription())); + } + } else if (resolvedProperty.getConstantValue() != null) { builder.append(format("Value must be %s", resolvedProperty.getConstantValue())); } else if (!resolvedProperty.getEnumValues().isEmpty()) { var values = resolvedProperty.getEnumValues().stream() @@ -88,39 +107,36 @@ private void transformProperty(SchemaPropertyReference propertyReference, boolea builder.append(""); } + private boolean isNamedScalar(SchemaType schemaType) { + return schemaType.isNamedScalar(); + } + private String parseResolvedTypes(SchemaProperty property) { - String resolvedTypes = ""; - if (property.getItemTypes().isEmpty()) { - resolvedTypes = property - .getResolvedTypes().stream().map(schemaType -> { - if (schemaType.getItemType() != null) { - return "array[" + schemaType.getItemType() + "]"; - } - return getTypeName(schemaType); - }).collect(joining(", ")); + if (!property.getItemTypes().isEmpty()) { + return ""; } - return resolvedTypes; + return property.getResolvedTypes().stream() + .map(schemaType -> { + if (schemaType.getItemType() != null) { + return "array[" + schemaType.getItemType() + "]"; + } + if (isNamedScalar(schemaType)) { + return schemaType.getBaseType(); + } + return typeNameWithLink(schemaType); + }) + .collect(joining(", ")); } private @NotNull String getConstraintOrArrayTypeName(SchemaProperty resolvedProperty) { var itemTypes = resolvedProperty.getItemTypes().stream() .flatMap(t -> t.getResolvedTypes().stream()) - .map(e -> { - if (e.isJsonBaseType() || getTypeName(e).startsWith("array")) { - return String.format("%s", getTypeName(e)); - } - return String.format("%s", getTypeName(e), getTypeName(e)); - }) + .map(this::typeNameWithLink) .collect(joining(", ")); if (itemTypes.isEmpty()) { itemTypes = resolvedProperty.getResolvedTypes().stream() .filter(e -> getTypeName(e) != null) - .map(e -> { - if (e.isJsonBaseType()) { - return String.format("%s", getTypeName(e)); - } - return String.format("%s", getTypeName(e), getTypeName(e)); - }) + .map(this::typeNameWithLink) .collect(joining(", ")); if (itemTypes.isEmpty()) { return "array"; @@ -138,6 +154,14 @@ private String parseResolvedTypes(SchemaProperty property) { return "array[" + itemTypes + "]"; } + private String typeNameWithLink(SchemaType schemaType) { + var name = getTypeName(schemaType); + if (name == null || schemaType.isJsonBaseType() || name.startsWith("array")) { + return name; + } + return String.format("%s", name, name); + } + private String getTypeName(SchemaType schemaType) { if (schemaType.isRootDefinition()) { // root definition, check to see if it has an allOf, and if not, fallback to the Json base type