Implemented a simpler way to process input data

This commit is contained in:
Kir_Antipov 2022-06-06 18:09:45 +03:00
parent a2e9aa9bb4
commit 24a3f2d11e
3 changed files with 196 additions and 23 deletions

View file

@ -1,7 +1,7 @@
import { getRequiredFiles, gradleOutputSelector } from "./utils/file-utils";
import PublisherFactory from "./publishing/publisher-factory";
import PublisherTarget from "./publishing/publisher-target";
import { getInputAsObject } from "./utils/input-utils";
import { getInputAsObject, mapNumberInput } from "./utils/input-utils";
import { getDefaultLogger } from "./utils/logger-utils";
import { retry } from "./utils/function-utils";
@ -21,8 +21,8 @@ async function main() {
const options = { ...commonOptions, ...publisherOptions };
const fileSelector = options.files && (typeof(options.files) === "string" || options.files.primary) ? options.files : gradleOutputSelector;
const files = await getRequiredFiles(fileSelector);
const retryAttempts = +options.retry?.["attempts"] || 0;
const retryDelay = +options.retry?.["delay"] || 0;
const retryAttempts = mapNumberInput(options.retry?.["attempts"]);
const retryDelay = mapNumberInput(options.retry?.["delay"]);
const publisher = publisherFactory.create(target, logger);
logger.info(`Publishing assets to ${targetName}...`);

View file

@ -32,3 +32,52 @@ function init(root: InputObject, path: string[], value: string): void {
init(inner, path.slice(1), value);
}
}
export function mapStringInput(value: any, defaultValue = ""): string {
return mapInput(value, defaultValue ?? "");
}
export function mapObjectInput(value: any, defaultValue: object = null): object {
return mapInput(value, defaultValue ?? null);
}
export function mapNumberInput(value: any, defaultValue = 0): number {
return mapInput(value, defaultValue ?? 0, {
string: x => {
const num = +x;
return isNaN(num) ? undefined : num;
}
});
}
export function mapBooleanInput(value: any, defaultValue = false): boolean {
return mapInput(value, defaultValue ?? false, {
string: x => {
const strValue = x.trim().toLowerCase();
return (
strValue === "true" ? true :
strValue === "false" ? false :
undefined
);
}
});
}
export function mapInput<T>(value: any, fallbackValue: T, mappers?: Record<string, (x: any) => T | undefined>): T {
if (value === undefinedValue || value === undefined || value === null) {
return fallbackValue;
}
if (typeof value === typeof fallbackValue) {
return value;
}
const mapper = mappers?.[typeof value];
if (mapper) {
const mappedValue = mapper(value);
if (typeof mappedValue === typeof fallbackValue) {
return mappedValue;
}
}
return fallbackValue;
}

View file

@ -1,9 +1,8 @@
import { describe, test, expect, beforeAll, afterAll } from "@jest/globals";
import { setupInput, unsetInput } from "./utils/input-utils";
import { getInputAsObject } from "../src/utils/input-utils";
import { getInputAsObject, mapStringInput, mapObjectInput, mapNumberInput, mapBooleanInput } from "../src/utils/input-utils";
describe("getInputAsObject", () => {
beforeAll(() => setupInput({
const defaultInput = {
"boolean": true,
"object": { foo: "bar" },
"number": 1,
@ -21,7 +20,10 @@ describe("getInputAsObject", () => {
"modrinth-files-secondary": "secondaryPath",
"This is a Very--Long_Name!": "foo"
}));
};
describe("getInputAsObject", () => {
beforeAll(() => setupInput(defaultInput));
afterAll(() => unsetInput());
test("input object contains only strings", () => {
@ -71,3 +73,125 @@ describe("getInputAsObject", () => {
expect(input.undefined).toBeUndefined();
});
});
describe("mapStringInput", () => {
beforeAll(() => setupInput(defaultInput));
afterAll(() => unsetInput());
test("returns default value if input is not a string", () => {
const input = getInputAsObject();
expect(input["undefined"]).toBeUndefined();
expect(mapStringInput(input["undefined"], "42")).toBe("42");
});
test("maps strings to string", () => {
const input = getInputAsObject();
expect(mapStringInput(input["boolean"], "")).toBe("true");
expect(mapStringInput(input["number"], "")).toBe("1");
expect(mapStringInput(input["object"])).toBe({}.toString());
});
});
describe("mapObjectInput", () => {
beforeAll(() => setupInput(defaultInput));
afterAll(() => unsetInput());
test("returns default value if input is not an object", () => {
const input = getInputAsObject();
expect(input["boolean"]).not.toBeUndefined();
expect(mapObjectInput(input["boolean"], null)).toBeNull();
expect(input["number"]).not.toBeUndefined();
expect(mapObjectInput(input["number"], null)).toBeNull()
expect(input["array"]).not.toBeUndefined();
expect(mapObjectInput(input["array"])).toBeNull()
expect(input["undefined"]).toBeUndefined();
expect(mapObjectInput(input["undefined"], { answer: 42 })).toStrictEqual({ answer: 42 });
});
test("maps object values to object", () => {
const input = getInputAsObject();
expect(mapObjectInput(input["modrinth"], null)).toStrictEqual({ id: "42", token: "1234", filesPrimary: "primaryPath", filesSecondary: "secondaryPath", files: { primary: "primaryPath", secondary: "secondaryPath" } });
});
});
describe("mapNumberInput", () => {
beforeAll(() => setupInput({
...defaultInput,
numberOne: 1,
numberOneString: "1",
numberOneStringWithWhitespace: " 1 ",
}));
afterAll(() => unsetInput());
test("returns default value if input is not number or number-like", () => {
const input = getInputAsObject();
expect(input["boolean"]).not.toBeUndefined();
expect(mapNumberInput(input["boolean"], 0)).toBe(0);
expect(input["object"]).not.toBeUndefined();
expect(mapNumberInput(input["object"], 0)).toBe(0);
expect(input["array"]).not.toBeUndefined();
expect(mapNumberInput(input["array"], 0)).toBe(0);
expect(input["undefined"]).toBeUndefined();
expect(mapNumberInput(input["undefined"], 1)).toBe(1);
});
test("maps number and number-like values to number", () => {
const input = getInputAsObject();
expect(mapNumberInput(input["numberone"], 0)).toBe(1);
expect(mapNumberInput(input["numberonestring"], 0)).toBe(1);
expect(mapNumberInput(input["numberonestringwithwhitespace"])).toBe(1);
});
});
describe("mapBooleanInput", () => {
beforeAll(() => setupInput({
...defaultInput,
booleanTrue: true,
booleanTrueStringLowerCase: "true",
booleanTrueStringUpperCase: "TRUE",
booleanTrueStringUpperCaseWithWhitespace: " TRUE ",
booleanFalse: false,
booleanFalseStringLowerCase: "false",
booleanFalseStringUpperCase: "FALSE",
booleanFalseStringUpperCaseWithWhitespace: " FALSE ",
}));
afterAll(() => unsetInput());
test("returns default value if input is not boolean or boolean-like", () => {
const input = getInputAsObject();
expect(input["object"]).not.toBeUndefined();
expect(mapBooleanInput(input["object"], false)).toBe(false);
expect(input["number"]).not.toBeUndefined();
expect(mapBooleanInput(input["number"], false)).toBe(false);
expect(input["array"]).not.toBeUndefined();
expect(mapBooleanInput(input["array"], false)).toBe(false);
expect(input["undefined"]).toBeUndefined();
expect(mapBooleanInput(input["undefined"], true)).toBe(true);
});
test("maps boolean and boolean-like values to boolean", () => {
const input = getInputAsObject();
expect(mapBooleanInput(input["booleantrue"], false)).toBe(true);
expect(mapBooleanInput(input["booleantruestringlowercase"], false)).toBe(true);
expect(mapBooleanInput(input["booleantruestringuppercase"], false)).toBe(true);
expect(mapBooleanInput(input["booleantruestringuppercasewithwhitespace"])).toBe(true);
expect(mapBooleanInput(input["booleanfalse"], true)).toBe(false);
expect(mapBooleanInput(input["booleanfalsestringlowercase"], true)).toBe(false);
expect(mapBooleanInput(input["booleanfalsestringuppercase"], true)).toBe(false);
expect(mapBooleanInput(input["booleanfalsestringuppercasewithwhitespace"], true)).toBe(false);
});
});