-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add support for message type generation from Json schemas (#77)
* Add support for message type generation from Json schemas * Fix typo * Minor cleanup * Remove FIXME as it is documented
- Loading branch information
Showing
21 changed files
with
2,085 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# Introduction | ||
|
||
This directory contains the Schema Table Generator plugin. The plugin generates readable type information in HTML for Json | ||
schema definitions found in the project source set. | ||
|
||
For example: | ||
|
||
```html | ||
|
||
<table class="message-table"> | ||
<tr> | ||
<td class="message-class" colspan="3">MessageOffer</td> | ||
</tr> | ||
<tr> | ||
<td class="message-properties-heading" colspan="3">Required properties</td> | ||
</tr> | ||
<tr> | ||
<td class="code">@id</td> | ||
<td>string</td> | ||
<td></td> | ||
</tr> | ||
<tr> | ||
<td class="code">@type</td> | ||
<td>string</td> | ||
<td>Value must be <span class="code">Offer</span></td> | ||
</tr> | ||
<tr> | ||
<td class="message-properties-heading" colspan="3">Optional properties</td> | ||
</tr> | ||
<tr> | ||
<td class="code">obligation</td> | ||
<td>array</td> | ||
<td></td> | ||
</tr> | ||
<tr> | ||
<td class="code">permission</td> | ||
<td>array</td> | ||
<td></td> | ||
</tr> | ||
<tr> | ||
<td class="code">profile</td> | ||
<td>any</td> | ||
<td></td> | ||
</tr> | ||
</table> | ||
``` | ||
|
||
For each type, a generated HTML table is created and output to `<build dir>/generated/tables`. File names are the | ||
typename in lowercase with an `.html` suffix. These files may then be imported into the ReSpec-based documentation using | ||
the `aside` element in the appropriate Markdown file: | ||
|
||
```html | ||
|
||
<aside data-include="generated/tables/messageoffer.html"></aside> | ||
``` | ||
|
||
## Implementation notes | ||
|
||
The Json Schema Object Model parser does not yet support all Json Schema features such `anyOf` or `oneOf`. | ||
|
||
# Build Setup | ||
|
||
The plugin can be applied and configured as follows: | ||
|
||
```kotlin | ||
apply<SchemaTableGeneratorPlugin>(); | ||
|
||
configure<SchemaTableGeneratorPluginExtension> { | ||
schemaPrefix = "https://w3id.org/dspace/2024/1/" | ||
schemaFileSuffix = "-schema.json" | ||
} | ||
``` | ||
|
||
The `schemPrefix` property is used to specify the base URL for resolving schema references. This base URL will be mapped | ||
relative to where the schema files reside on the local filesystem. The `schemaFileSuffix` propery is used to filter | ||
schema files to include. | ||
|
||
# Running | ||
|
||
The generation process can be run by specifying the `generateTablesFromSchemas` task: | ||
|
||
``` | ||
./gradlew generateTablesFromSchemas | ||
``` | ||
|
||
To debug the generation process, use: | ||
|
||
``` | ||
./gradlew -Dorg.gradle.debug=true --no-daemon generateTablesFromSchemas | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* | ||
* Copyright (c) 2024 Metaform Systems, Inc. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Apache License, Version 2.0 which is available at | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Contributors: | ||
* Metaform Systems, Inc. - initial API and implementation | ||
* | ||
*/ | ||
|
||
plugins { | ||
`java-library` | ||
checkstyle | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
dependencies { | ||
implementation("com.networknt:json-schema-validator:1.5.2") { | ||
exclude("com.fasterxml.jackson.dataformat", "jackson-dataformat-yaml") | ||
} | ||
testImplementation("org.assertj:assertj-core:3.26.3") | ||
} | ||
|
||
testing { | ||
suites { | ||
val test by getting(JvmTestSuite::class) { | ||
useJUnitJupiter("5.8.1") | ||
} | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/SchemaTableGeneratorPlugin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* Copyright (c) 2024 Metaform Systems, Inc. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Apache License, Version 2.0 which is available at | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Contributors: | ||
* Metaform Systems, Inc. - initial API and implementation | ||
* | ||
*/ | ||
|
||
package org.eclipse.dsp.generation; | ||
|
||
|
||
import org.eclipse.dsp.generation.jsom.JsomParser; | ||
import org.eclipse.dsp.generation.transformer.HtmlTableTransformer; | ||
import org.eclipse.dsp.generation.transformer.SchemaTypeTransformer; | ||
import org.gradle.api.Plugin; | ||
import org.gradle.api.Project; | ||
import org.gradle.api.plugins.JavaPluginExtension; | ||
import org.gradle.api.tasks.SourceSet; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import java.io.File; | ||
import java.io.FileWriter; | ||
import java.io.IOException; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
/** | ||
* Generates a table of schema properties to be included in the specification text. | ||
*/ | ||
public class SchemaTableGeneratorPlugin implements Plugin<Project> { | ||
private static final String TASK_NAME = "generateTablesFromSchemas"; | ||
private static final String CONFIG_NAME = "schemaTableGenerator"; | ||
private static final String GENERATED = "generated"; | ||
private static final String TABLES = "tables"; | ||
|
||
private final SchemaTypeTransformer<String> htmlTransformer = new HtmlTableTransformer(); | ||
|
||
@Override | ||
public void apply(@NotNull Project project) { | ||
var extension = project.getExtensions().create(CONFIG_NAME, SchemaTableGeneratorPluginExtension.class); | ||
|
||
project.task(TASK_NAME).doLast(task -> { | ||
var tablesDir = task.getProject().getLayout().getBuildDirectory().dir(GENERATED).get().dir(TABLES).getAsFile(); | ||
//noinspection ResultOfMethodCallIgnored | ||
tablesDir.mkdirs(); | ||
var sourceSet = requireNonNull(project.getExtensions() | ||
.findByType(JavaPluginExtension.class)).getSourceSets().getByName("main"); | ||
|
||
var prefix = extension.getSchemaPrefix(); | ||
String resolvePath = getResolutionPath(sourceSet); | ||
|
||
// parse the schema object model | ||
var parser = new JsomParser(prefix, resolvePath); | ||
var stream = sourceSet.getResources().getFiles().stream() | ||
.filter(f -> f.getName().endsWith(extension.getSchemaFileSuffix())); | ||
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 | ||
.forEach(type -> { | ||
var content = htmlTransformer.transform(type); | ||
var destination = new File(tablesDir, type.getName().toLowerCase() + ".html"); | ||
try (var writer = new FileWriter(destination)) { | ||
writer.write(content); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
}); | ||
task.getLogger().info("Completed generation"); | ||
}); | ||
|
||
} | ||
|
||
private String getResolutionPath(SourceSet sourceSet) { | ||
var files = sourceSet.getResources().getSourceDirectories().getFiles(); | ||
if (files.isEmpty()) { | ||
throw new IllegalStateException("No schema resource directories found"); | ||
} | ||
var path = files.iterator().next(); | ||
return path.getAbsolutePath().endsWith("/") ? path.getAbsolutePath() : path.getAbsolutePath() + "/"; | ||
} | ||
|
||
|
||
} |
42 changes: 42 additions & 0 deletions
42
...uildSrc/src/main/java/org/eclipse/dsp/generation/SchemaTableGeneratorPluginExtension.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright (c) 2024 Metaform Systems, Inc. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Apache License, Version 2.0 which is available at | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Contributors: | ||
* Metaform Systems, Inc. - initial API and implementation | ||
* | ||
*/ | ||
|
||
package org.eclipse.dsp.generation; | ||
|
||
/** | ||
* Defines the plugin configuration. | ||
*/ | ||
public class SchemaTableGeneratorPluginExtension { | ||
private String schemaPrefix; | ||
private String schemaFileSuffix = "-schema.json"; | ||
|
||
public SchemaTableGeneratorPluginExtension() { | ||
} | ||
|
||
public String getSchemaPrefix() { | ||
return schemaPrefix; | ||
} | ||
|
||
public void setSchemaPrefix(String schemaPrefix) { | ||
this.schemaPrefix = schemaPrefix; | ||
} | ||
|
||
public String getSchemaFileSuffix() { | ||
return schemaFileSuffix; | ||
} | ||
|
||
public void setSchemaFileSuffix(String schemaFileSuffix) { | ||
this.schemaFileSuffix = schemaFileSuffix; | ||
} | ||
} |
61 changes: 61 additions & 0 deletions
61
artifacts/buildSrc/src/main/java/org/eclipse/dsp/generation/jsom/ElementDefinition.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* Copyright (c) 2024 Metaform Systems, Inc. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Apache License, Version 2.0 which is available at | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Contributors: | ||
* Metaform Systems, Inc. - initial API and implementation | ||
* | ||
*/ | ||
|
||
package org.eclipse.dsp.generation.jsom; | ||
|
||
import org.jetbrains.annotations.NotNull; | ||
|
||
import java.util.Set; | ||
import java.util.TreeSet; | ||
|
||
/** | ||
* Models an element such as {@code contains} object or an {@code items} object. | ||
*/ | ||
public class ElementDefinition implements Comparable<ElementDefinition> { | ||
|
||
public enum Type { | ||
REFERENCE, CONSTANT | ||
} | ||
|
||
private final Type type; | ||
private final String value; | ||
private final Set<SchemaType> resolvedTypes = new TreeSet<>(); | ||
|
||
public ElementDefinition(Type type, String value) { | ||
this.type = type; | ||
this.value = value; | ||
} | ||
|
||
public Type getType() { | ||
return type; | ||
} | ||
|
||
public String getValue() { | ||
return value; | ||
} | ||
|
||
public Set<SchemaType> getResolvedTypes() { | ||
return resolvedTypes; | ||
} | ||
|
||
public void resolvedType(SchemaType resolvedType) { | ||
this.resolvedTypes.add(resolvedType); | ||
} | ||
|
||
@Override | ||
public int compareTo(@NotNull ElementDefinition o) { | ||
return value.compareTo(o.value); | ||
} | ||
|
||
} |
Oops, something went wrong.