Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,28 @@ jobs:
- name: Tests
run: |
npm run test
# only added temporarily to run integration tests on Java
integration-tests-java:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup node.js
uses: actions/setup-node@v4
- name: Install
run: |
npm install
- name: Build
run: |
npm run build
- name: Install Java
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
- name: Prepare for testing
run: |
npm run
npm run test:setup-java
- name: Integration tests
run: |
JAVA_ES_REQUEST_CONVERTER_JAR=/home/runner/work/request-converter/request-converter/tests/integration/.java-request-converter/build/libs/java-request-converter-1.0.0.jar npm run test:integration-java
24 changes: 24 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,27 @@ jobs:
- name: Integration tests
run: |
npm run test:integration-ruby
integration-tests-java:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup node.js
uses: actions/setup-node@v4
- name: Install
run: |
npm install
- name: Build
run: |
npm run build
- name: Install Java
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 21
- name: Prepare for testing
run: |
npm run
npm run test:setup-java
- name: Integration tests
run: |
JAVA_ES_REQUEST_CONVERTER_JAR=/home/runner/work/request-converter/request-converter/tests/integration/.java-request-converter/build/libs/java-request-converter-1.0.0.jar npm run test:integration-java
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"compile-templates": "node scripts/compile-templates.mjs",
"copy-files": "copyfiles -u 1 src/**/*.js src/**/*.json dist/",
"docs": "typedoc src/index.ts",
"lint": "eslint src tests --ignore-pattern tests/wasm/",
"lint": "eslint src tests --ignore-pattern tests/wasm/ --ignore-pattern 'tests/integration/.*'",
"prettier": "prettier \"src/**/*.ts\" \"tests/**/*.ts\" --list-different",
"test": "npm run compile-templates && jest --test-path-ignore-patterns integration --coverage",
"test:setup": "./tests/integration/run-python.sh && ./tests/integration/run-javascript.sh && ./tests/integration/run-ruby.sh && ./tests/integration/run-php.sh",
Expand All @@ -29,15 +29,17 @@
"test:setup-javascript": "./tests/integration/run-javascript.sh",
"test:setup-php": "./tests/integration/run-php.sh",
"test:setup-ruby": "./tests/integration/run-ruby.sh",
"test:setup-java": "./tests/integration/run-java.sh",
"test:integration": "jest tests/integration",
"test:integration-curl": "./scripts/test-format.sh curl",
"test:integration-python": "./scripts/test-format.sh python",
"test:integration-javascript": "./scripts/test-format.sh javascript",
"test:integration-php": "./scripts/test-format.sh php",
"test:integration-ruby": "./scripts/test-format.sh ruby",
"test:integration-java": "./scripts/test-format.sh java",
"test:example": "./scripts/test-example.sh",
"fix": "npm run fix:lint && npm run fix:prettier",
"fix:lint": "eslint src tests --fix --ignore-pattern tests/wasm/",
"fix:lint": "eslint src tests --fix --ignore-pattern tests/wasm/ --ignore-pattern 'tests/integration/.*'",
"fix:prettier": "prettier \"src/**/*.ts\" \"tests/**/*.ts\" --write",
"fix:precommit": "./scripts/precommit.sh",
"watch:test": "npm run compile-templates && jest --test-path-ignore-patterns integration --coverage --watch",
Expand Down
16 changes: 14 additions & 2 deletions src/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { CurlExporter } from "./exporters/curl";
import { JavaScriptExporter } from "./exporters/javascript";
import { PHPExporter } from "./exporters/php";
import { RubyExporter } from "./exporters/ruby";
import { JavaExporter } from "./exporters/java";
import util from "util";

const isBrowser = typeof window !== "undefined";
Expand Down Expand Up @@ -35,6 +36,7 @@ export type ConvertOptions = {
* This interface defines the structure of a language exporter.
*/
export interface FormatExporter {
available?(): boolean;
check(requests: ParsedRequest[]): Promise<boolean>;
convert(requests: ParsedRequest[], options: ConvertOptions): Promise<string>;
}
Expand All @@ -44,9 +46,10 @@ const EXPORTERS: Record<string, FormatExporter> = {
php: new PHPExporter(),
python: new PythonExporter(),
ruby: new RubyExporter(),
java: new JavaExporter(),
curl: new CurlExporter(),
};
const LANGUAGES = ["JavaScript", "PHP", "Python", "Ruby", "curl"];
const LANGUAGES = ["JavaScript", "PHP", "Python", "Ruby", "Java", "curl"];

/**
* Return the list of available export formats.
Expand All @@ -55,7 +58,16 @@ const LANGUAGES = ["JavaScript", "PHP", "Python", "Ruby", "curl"];
* to use in the `convertRequests()` function.
*/
export function listFormats(): string[] {
return LANGUAGES;
return LANGUAGES.filter((lang) => {
const exporter = EXPORTERS[lang.toLowerCase()];
if (!exporter) {
return false;
}
if (!exporter.available) {
return true;
}
return exporter.available();
});
}

/**
Expand Down
88 changes: 88 additions & 0 deletions src/exporters/java.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import childProcess from "child_process";
import { FormatExporter, ConvertOptions } from "../convert";
import { ParsedRequest, JSONValue } from "../parse";
import { Request } from "../metamodel";
import util from "util";

const isBrowser = typeof window !== "undefined";
const execAsync = !isBrowser ? util.promisify(childProcess.exec) : undefined;

type JavaRequest = {
api?: string;
params: Record<string, string | undefined>;
query?: Record<string, string>;
body: JSONValue;
};

function getCodeGenParamNames(
params: Record<string, string | undefined>,
request: Request,
) {
for (const [key, value] of Object.entries(params)) {
if (request?.path) {
for (const prop of request.path) {
if (prop.name === key && prop.codegenName !== undefined) {
delete params[key];
params[prop.codegenName] = value;
}
}
}
}
return params;
}

export class JavaExporter implements FormatExporter {
available(): boolean {
return !isBrowser && !!process.env.JAVA_ES_REQUEST_CONVERTER_JAR;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
async check(requests: ParsedRequest[]): Promise<boolean> {
// only return true if all requests are for Elasticsearch
return requests
.map((req) => req.service == "es")
.reduce((prev, curr) => prev && curr, true);
}

async convert(
requests: ParsedRequest[],
options: ConvertOptions,
): Promise<string> {
const javaRequests: JavaRequest[] = [];
for (const request of requests) {
if (request.request) {
const correctParams = getCodeGenParamNames(
request.params,
request.request,
);
const body = request.body ?? {};

const javaRequest: JavaRequest = {
api: request.api,
params: correctParams,
query: request.query,
body: body,
};
javaRequests.push(javaRequest);
}
}

// escape single quotes that may appear in the payload
// (only for bash-style shells for now)
const req = JSON.stringify(javaRequests).replaceAll("'", "'\"'\"'");
// other arguments to the Java converter
const complete = options.complete ? "true" : "false";
const url = options.elasticsearchUrl ?? "";

if (execAsync === undefined) {
throw new Error("Cannot use exec()");
}
const { stdout, stderr } = await execAsync(
`java -jar ${process.env.JAVA_ES_REQUEST_CONVERTER_JAR} '${req}' '${complete}' '${url}'`,
);
if (!stdout) {
throw new Error(`Could not invoke exporter: ${stderr}`);
}
return stdout;
}
}
1 change: 1 addition & 0 deletions src/java-caller.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "java-caller";
Loading
Loading