Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
richturner committed Jan 29, 2024
1 parent 30ad5c1 commit 9c76406
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 131 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ allprojects {
if (findProject(":openremote") && !path.startsWith(":openremote")) {
apply from: "${project(":openremote").projectDir}/project.gradle"
} else if (!findProject(":openremote")) {
apply from: "${project.rootDir}/custom-project.gradle"
apply from: "${project.rootDir}/project.gradle"
}
}

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ projectName = custom-project
projectVersion = 1.0-SNAPSHOT
openremoteVersion = 0.2.0-SNAPSHOT
typescriptGeneratorVersion = 3.2.1263
jacksonVersion = 2.16.0
jacksonVersion = 2.16.0
8 changes: 5 additions & 3 deletions custom-project.gradle → project.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,13 @@ def createTSGeneratorConfig(boolean outputAPIClient, String outputFileName, Proj
}
}.toList()

def baseClassPattern = outputAPIClient
? customProjectsToScan.length == 0 ? [ "org.openremote.model.**Resource" ] : []
: [ "org.openremote.model.**" ]

return {
jsonLibrary = "jackson2"
classPatterns = [
(outputAPIClient ? "org.openremote.model.**Resource" : "org.openremote.model.**")
] + classPatternGlobs
classPatterns = baseClassPattern + classPatternGlobs
customTypeNamingFunction = "function(name, simpleName) { if (name.indexOf(\"\$\") > 0) return name.substr(name.lastIndexOf(\".\")+1).replace(\"\$\",\"\"); }"
excludeClassPatterns = [
"org.openremote.model.event.shared.*Filter**",
Expand Down
1 change: 1 addition & 0 deletions ui/component/model/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
src/model.ts
src/typescript-generator-info.json
6 changes: 3 additions & 3 deletions ui/component/model/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@openremote/model",
"name": "model",
"version": "1.1.0",
"description": "OpenRemote 3.x Model Types",
"description": "Model Types",
"main": "dist/umd/index.bundle.js",
"module": "lib/index.js",
"exports": {
Expand All @@ -21,7 +21,7 @@
"author": "OpenRemote",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@openremote/util": "workspace:*"
"@openremote/util": "^1.0.4"
},
"publishConfig": {
"access": "public"
Expand Down
90 changes: 7 additions & 83 deletions ui/component/rest/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,97 +12,21 @@ buildscript {
}

dependencies {
compileOnly findProject(":util")
compileOnly resolveDependency(":model-util")
implementation findProject(":model")
implementation findProject(":ui:component:model")
implementation findProject(":agent")
implementation "cz.habarta.typescript-generator:typescript-generator-core:$typescriptGeneratorVersion"
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$jacksonVersion"
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonVersion"
implementation "com.fasterxml.jackson.module:jackson-module-parameter-names:$jacksonVersion"
}

task generateTypescriptModelInfo(type: cz.habarta.typescript.generator.gradle.GenerateTask) {
jsonLibrary = "jackson2"
classPatterns = [
"org.openremote.model.**"
]
outputKind = "module"
generateInfoJson = true
excludeClassPatterns = [
"org.openremote.model.util.**",
"org.openremote.model.flow.**",
"java.io.**",
"java.lang.**",
"org.hibernate.**",
"jakarta.**"
]
customTypeProcessor = "CustomTypeProcessor"
customTypeNamingFunction = "function(name, simpleName) { if (name.indexOf(\"\$\") > 0) return name.substr(name.lastIndexOf(\".\")+1).replace(\"\$\",\"\"); }"
customTypeMappings = [
"com.fasterxml.jackson.databind.node.ObjectNode:{ [id: string]: any }",
"java.lang.Class<T>:string"
]
optionalProperties = "all" // TODO: cleanup model to be more explicit about optional params
mapEnum = cz.habarta.typescript.generator.EnumMapping.asEnum
mapDate = cz.habarta.typescript.generator.DateMapping.asNumber
jackson2Modules = [
"com.fasterxml.jackson.datatype.jdk8.Jdk8Module",
"com.fasterxml.jackson.datatype.jsr310.JavaTimeModule",
"com.fasterxml.jackson.module.paramnames.ParameterNamesModule"
]
extensions = [
"CustomExtension",
"JsonSerializeExtension"
]
}
// This seems hacky but it is the only way to get the closure from the method call
project.task(Collections.singletonMap(Task.TASK_TYPE, cz.habarta.typescript.generator.gradle.GenerateTask), "generateTypescriptModelInfo")
generateTypescriptModelInfo createTSGeneratorConfigForModel("$buildDir/model.ts", findProject(":model"))

generateTypeScript {
dependsOn generateTypescriptModelInfo
jsonLibrary = "jackson2"
customTypeNamingFunction = "function(name, simpleName) { if (name.indexOf(\"\$\") > 0) return name.substr(name.lastIndexOf(\".\")+1).replace(\"\$\",\"\"); }"
customTypeMappings = [
"com.fasterxml.jackson.databind.node.ObjectNode:{ [id: string]: any }",
"java.lang.Class<T>:string",
"org.openremote.model.asset.Asset<T>:Model.Asset",
"org.openremote.model.asset.AssetDescriptor<T>:Model.AssetDescriptor",
"org.openremote.model.asset.agent.Agent<T,U,V>:Model.Agent",
"org.openremote.model.asset.agent.AgentDescriptor<T,U,V>:Model.AgentDescriptor",
"org.openremote.model.value.MetaItemDescriptor<T>:Model.MetaItemDescriptor",
"org.openremote.model.value.ValueDescriptor<T>:Model.ValueDescriptor"
]
classPatterns = [
"org.openremote.model.**Resource"
]
excludeClassPatterns = [
"org.openremote.model.util.**",
"org.openremote.model.flow.**",
"java.io.**",
"java.lang.**",
"org.hibernate.**",
"jakarta.**"
]
moduleDependencies = [
cz.habarta.typescript.generator.ModuleDependency.module(
"@openremote/model",
"Model",
new File("$buildDir/typescript-generator/typescript-generator-info.json"),
(String)null,
(String)null
)
]
outputFile = "src/restclient.ts"
outputFileType = "implementationFile"
outputKind = "module"
mapEnum = cz.habarta.typescript.generator.EnumMapping.asEnum
mapDate = cz.habarta.typescript.generator.DateMapping.asNumber
restNamespacing = "perResource"
extensions = [
"CustomExtension",
"JsonSerializeExtension",
"AggregatedApiClient",
"cz.habarta.typescript.generator.ext.AxiosClientExtension"
]
}
generateTypeScript createTSGeneratorConfigForClient("src/restclient.ts", findProject(":model"))
generateTypeScript.dependsOn(generateTypescriptModelInfo)

clean {
doLast {
Expand Down
6 changes: 3 additions & 3 deletions ui/component/rest/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "rest",
"version": "1.1.0",
"description": "OpenRemote 3.x REST API",
"description": "REST API",
"main": "dist/umd/index.bundle.js",
"private": true,
"module": "lib/index.js",
Expand All @@ -22,12 +22,12 @@
"author": "OpenRemote",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@openremote/model": "workspace:*",
"@openremote/model": "^1.1.0",
"axios": "0.24.0",
"qs": "^6.8.0"
},
"devDependencies": {
"@openremote/util": "workspace:*",
"@openremote/util": "^1.0.4",
"@types/qs": "^6.9.7"
}
}
37 changes: 2 additions & 35 deletions ui/component/rest/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,10 @@
import axios, {AxiosInstance, AxiosRequestConfig, GenericAxiosResponse, AxiosError} from "axios";
import {ApiClient, RestResponse} from "./restclient";
import Qs from "qs";
import rest from "@openremote/rest";

const isAxiosError = axios.isAxiosError;

export {RestResponse, GenericAxiosResponse, AxiosError, isAxiosError};

export class RestApi {

get api() {
return this._client;
}

protected _client!: ApiClient;
protected _axiosInstance!: AxiosInstance;

constructor() {
this._axiosInstance = axios.create();
this._axiosInstance.defaults.headers.common["Content-Type"] = "application/json";
this._axiosInstance.interceptors.request.use((config) => {
config.paramsSerializer = (params) => Qs.stringify(params, {arrayFormat: "repeat"});
return config;
});
}

get axiosInstance() {
return this._axiosInstance;
}

public setTimeout(timeout: number) {
this._axiosInstance.defaults.timeout = timeout;
}

public addRequestInterceptor(interceptor: (config: AxiosRequestConfig) => AxiosRequestConfig) {
this._axiosInstance.interceptors.request.use(interceptor);
}

public initialise(baseUrl: string) {
this._client = new ApiClient(baseUrl, this._axiosInstance);
return rest.api;
}
}

Expand Down
84 changes: 84 additions & 0 deletions ui/component/rest/src/main/java/ExtendedAggregatedApiClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import cz.habarta.typescript.generator.Settings;
import cz.habarta.typescript.generator.emitter.EmitterExtension;
import cz.habarta.typescript.generator.emitter.EmitterExtensionFeatures;
import cz.habarta.typescript.generator.emitter.TsBeanModel;
import cz.habarta.typescript.generator.emitter.TsModel;

import java.util.List;
import java.util.stream.Collectors;

/**
* Creates a wrapper class around all of the clients the generator creates so that they can easily be exported as a single
* entity; this is specifically for custom projects and creates a reference to the main rest client.
*/
public class ExtendedAggregatedApiClient extends EmitterExtension {

private static final String fieldFormatString = "protected %1$s : Axios%2$sClient;";
private static final String ctorFormatString = "this.%1$s = new Axios%2$sClient(baseURL, axiosInstance);";
private static final String getter1FormatString = "get %1$s() : Axios%1$sClient {";
private static final String getter2FormatString = "return this.%1$s;";

private static class FieldAndGetter {
String field;
String getter;

public FieldAndGetter(String field, String getter) {
this.field = field;
this.getter = getter;
}
}

@Override
public EmitterExtensionFeatures getFeatures() {
final EmitterExtensionFeatures features = new EmitterExtensionFeatures();
features.generatesRuntimeCode = true;
return features;
}


@Override
public void emitElements(Writer writer, Settings settings, boolean exportKeyword, TsModel model) {

writer.writeIndentedLine("export class ApiClient {");
writer.writeIndentedLine("");
List<TsBeanModel> clients = model.getBeans().stream()
.filter(TsBeanModel::isJaxrsApplicationClientBean)
.collect(Collectors.toList());

List<FieldAndGetter> fieldsAndGetters = clients.stream().map(this::getOutputs).collect(Collectors.toList());

fieldsAndGetters.forEach(fieldAndGetter -> this.emitField(writer, fieldAndGetter));

writer.writeIndentedLine("");
writer.writeIndentedLine("constructor(baseURL: string, axiosInstance: Axios.AxiosInstance = axios.create()) {");

fieldsAndGetters.forEach(fieldAndGetter -> this.emitCtor(writer, fieldAndGetter));

writer.writeIndentedLine("}");
writer.writeIndentedLine("");

fieldsAndGetters.forEach(fieldAndGetter -> this.emitGetter(writer, fieldAndGetter));

writer.writeIndentedLine("}");
}

private void emitField(Writer writer, FieldAndGetter fieldAndGetter) {
writer.writeIndentedLine(String.format(fieldFormatString, fieldAndGetter.field, fieldAndGetter.getter));
}

private void emitCtor(Writer writer, FieldAndGetter fieldAndGetter) {
writer.writeIndentedLine(String.format(ctorFormatString, fieldAndGetter.field, fieldAndGetter.getter));
}

private void emitGetter(Writer writer, FieldAndGetter fieldAndGetter) {
writer.writeIndentedLine(String.format(getter1FormatString, fieldAndGetter.getter));
writer.writeIndentedLine(String.format(getter2FormatString, fieldAndGetter.field));
writer.writeIndentedLine("}");
}

private FieldAndGetter getOutputs(TsBeanModel client) {
String getterName = client.getName().getSimpleName().substring(0, client.getName().getSimpleName().length()-6);
String fieldName = "_" + Character.toLowerCase(getterName.charAt(0)) + getterName.substring(1);
return new FieldAndGetter(fieldName, getterName);
}
}
24 changes: 22 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2360,7 +2360,7 @@ __metadata:
languageName: node
linkType: hard

"@openremote/model@npm:1.1.0":
"@openremote/model@npm:1.1.0, @openremote/model@npm:^1.1.0":
version: 1.1.0
resolution: "@openremote/model@npm:1.1.0"
checksum: 0adf48e94b72f49b1941b279838d66010dc9371a04ec3616de613e01c0039abf66483772fc2748157f6670e242b0a2316d4f686a49ca5399d30bec0dea565f08
Expand Down Expand Up @@ -2964,7 +2964,7 @@ __metadata:
languageName: node
linkType: hard

"@types/qs@npm:*":
"@types/qs@npm:*, @types/qs@npm:^6.9.7":
version: 6.9.11
resolution: "@types/qs@npm:6.9.11"
checksum: 620ca1628bf3da65662c54ed6ebb120b18a3da477d0bfcc872b696685a9bb1893c3c92b53a1190a8f54d52eaddb6af8b2157755699ac83164604329935e8a7f2
Expand Down Expand Up @@ -6983,6 +6983,14 @@ __metadata:
languageName: node
linkType: hard

"model@workspace:ui/component/model":
version: 0.0.0-use.local
resolution: "model@workspace:ui/component/model"
dependencies:
"@openremote/util": ^1.0.4
languageName: unknown
linkType: soft

"moment@npm:2.29.4":
version: 2.29.4
resolution: "moment@npm:2.29.4"
Expand Down Expand Up @@ -8032,6 +8040,18 @@ __metadata:
languageName: node
linkType: hard

"rest@workspace:ui/component/rest":
version: 0.0.0-use.local
resolution: "rest@workspace:ui/component/rest"
dependencies:
"@openremote/model": ^1.1.0
"@openremote/util": ^1.0.4
"@types/qs": ^6.9.7
axios: 0.24.0
qs: ^6.8.0
languageName: unknown
linkType: soft

"retry@npm:^0.12.0":
version: 0.12.0
resolution: "retry@npm:0.12.0"
Expand Down

0 comments on commit 9c76406

Please sign in to comment.