@openmrs/esm-utils 3.1.10-pre.97 → 3.1.11-pre.595
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -13
- package/dist/openmrs-esm-utils.js +1 -1
- package/dist/openmrs-esm-utils.js.map +1 -1
- package/docs/API.md +269 -67
- package/docs/interfaces/RetryOptions.md +83 -0
- package/package.json +11 -8
- package/src/age-helpers.tsx +88 -0
- package/src/index.ts +4 -0
- package/src/omrs-dates.test.ts +33 -1
- package/src/retry.ts +83 -0
- package/src/translate.ts +13 -0
- package/src/version.test.ts +53 -0
- package/src/version.ts +30 -0
- package/webpack.config.js +5 -11
- package/src/set-public-path.ts +0 -3
package/src/omrs-dates.test.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
toOmrsIsoString,
|
|
3
|
+
toDateObjectStrict,
|
|
4
|
+
isOmrsDateStrict,
|
|
5
|
+
} from "./omrs-dates";
|
|
2
6
|
import dayjs from "dayjs";
|
|
3
7
|
|
|
4
8
|
describe("Openmrs Dates", () => {
|
|
@@ -9,4 +13,32 @@ describe("Openmrs Dates", () => {
|
|
|
9
13
|
).toDate();
|
|
10
14
|
expect(toOmrsIsoString(date, true)).toEqual("2018-03-18T21:05:03.999+0000");
|
|
11
15
|
});
|
|
16
|
+
|
|
17
|
+
it("checks if a string is openmrs date", () => {
|
|
18
|
+
expect(isOmrsDateStrict("2018-03-19T00:00:00.000+0300")).toEqual(true);
|
|
19
|
+
expect(isOmrsDateStrict(" 2018-03-19T00:00:00.000+0300 ")).toEqual(true);
|
|
20
|
+
// the exclusion test cases are important for strictness
|
|
21
|
+
expect(isOmrsDateStrict("2018-03-19 00:00:00.000+0300")).toEqual(false);
|
|
22
|
+
expect(isOmrsDateStrict("2018-03-19T00:00:00.000+03:00")).toEqual(false);
|
|
23
|
+
expect(isOmrsDateStrict("2018-03-19T00:00:00.000 0300")).toEqual(false);
|
|
24
|
+
expect(isOmrsDateStrict("2018-03-19T00:00:00 000+0300")).toEqual(false);
|
|
25
|
+
expect(isOmrsDateStrict("2018-03-1")).toEqual(false);
|
|
26
|
+
expect(isOmrsDateStrict("")).toEqual(false);
|
|
27
|
+
expect(isOmrsDateStrict(null as any)).toEqual(false);
|
|
28
|
+
expect(isOmrsDateStrict(undefined as any)).toEqual(false);
|
|
29
|
+
});
|
|
30
|
+
it("converts omrs date string version to js Date object", () => {
|
|
31
|
+
expect(
|
|
32
|
+
toDateObjectStrict("2018-03-19T00:00:00.000+0300")?.toUTCString()
|
|
33
|
+
).toEqual("Sun, 18 Mar 2018 21:00:00 GMT");
|
|
34
|
+
expect(toDateObjectStrict("2018-03-19")).toEqual(null);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("converts js Date object to omrs date string version", () => {
|
|
38
|
+
var date = dayjs(
|
|
39
|
+
"2018-03-19T00:05:03.999+0300",
|
|
40
|
+
"YYYY-MM-DDTHH:mm:ss.SSSZZ"
|
|
41
|
+
).toDate();
|
|
42
|
+
expect(toOmrsIsoString(date, true)).toEqual("2018-03-18T21:05:03.999+0000");
|
|
43
|
+
});
|
|
12
44
|
});
|
package/src/retry.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for configuring the behavior of the {@link retry} function.
|
|
3
|
+
*/
|
|
4
|
+
export interface RetryOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Determines whether the retry function should retry executing the function after it failed
|
|
7
|
+
* with an error on the current attempt.
|
|
8
|
+
* @param attempt The current (zero-based) retry attempt. `0` indicates the initial attempt.
|
|
9
|
+
*/
|
|
10
|
+
shouldRetry?(attempt: number);
|
|
11
|
+
/**
|
|
12
|
+
* Calculates the next delay (in milliseconds) before a retry attempt.
|
|
13
|
+
* Returning a value for the inital attempt (`0`) delays the initial function invocation.
|
|
14
|
+
* @param attempt The current (zero-based) retry attempt. `0` indicates the initial attempt.
|
|
15
|
+
*/
|
|
16
|
+
getDelay?(attempt: number): number;
|
|
17
|
+
/**
|
|
18
|
+
* Called when invoking the function resulted in an error.
|
|
19
|
+
* Allows running side-effects on errors, e.g. logging.
|
|
20
|
+
* @param e The error thrown by the function.
|
|
21
|
+
* @param attempt The current (zero-based) retry attempt. `0` indicates the initial attempt.
|
|
22
|
+
*/
|
|
23
|
+
onError?(e: any, attempt: number): void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Executes the specified function and retries executing on failure with a custom backoff strategy
|
|
28
|
+
* defined by the options.
|
|
29
|
+
*
|
|
30
|
+
* If not configured otherwise, this function uses the following default options:
|
|
31
|
+
* * Retries 5 times beyond the initial attempt.
|
|
32
|
+
* * Uses an exponential backoff starting with an initial delay of 1000ms.
|
|
33
|
+
* @param fn The function to be executed and retried on failure.
|
|
34
|
+
* @param options Additional options which configure the retry behavior.
|
|
35
|
+
* @returns The result of successfully executing `fn`.
|
|
36
|
+
* @throws Rethrows the final error of running `fn` when the function stops retrying.
|
|
37
|
+
*/
|
|
38
|
+
export async function retry<T>(
|
|
39
|
+
fn: () => Promise<T>,
|
|
40
|
+
options: RetryOptions = {}
|
|
41
|
+
) {
|
|
42
|
+
let { shouldRetry, getDelay, onError } = options;
|
|
43
|
+
shouldRetry = shouldRetry ?? ((attempt) => limitAttempts(attempt, 5));
|
|
44
|
+
getDelay = getDelay ?? ((attempt) => getExponentialDelay(attempt, 1000));
|
|
45
|
+
|
|
46
|
+
let attempt = 0;
|
|
47
|
+
let lastError: any = undefined;
|
|
48
|
+
|
|
49
|
+
do {
|
|
50
|
+
try {
|
|
51
|
+
await delay(getDelay(attempt));
|
|
52
|
+
return await fn();
|
|
53
|
+
} catch (e) {
|
|
54
|
+
onError?.(e, attempt);
|
|
55
|
+
lastError = e;
|
|
56
|
+
}
|
|
57
|
+
} while (shouldRetry(attempt++));
|
|
58
|
+
|
|
59
|
+
// If we reach this fn errored and shouldn't retry anymore. Simply rethrow the final error as
|
|
60
|
+
// a means of ending the retry process without a result.
|
|
61
|
+
throw lastError;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function limitAttempts(attempt: number, maxAttempts: number) {
|
|
65
|
+
return attempt <= maxAttempts;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getExponentialDelay(
|
|
69
|
+
attempt: number,
|
|
70
|
+
startingDelay: number,
|
|
71
|
+
initialDelay = false
|
|
72
|
+
) {
|
|
73
|
+
const exponent = initialDelay ? attempt + 1 : attempt;
|
|
74
|
+
return startingDelay * Math.pow(2, exponent);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function delay(ms: number) {
|
|
78
|
+
if (ms <= 0) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return new Promise<void>((res) => setTimeout(res, ms));
|
|
83
|
+
}
|
package/src/translate.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import _i18n from "i18next";
|
|
2
|
+
|
|
3
|
+
export function translateFrom(
|
|
4
|
+
moduleName: string,
|
|
5
|
+
key: string,
|
|
6
|
+
fallback?: string
|
|
7
|
+
) {
|
|
8
|
+
const i18n: typeof _i18n = (_i18n as any).default || _i18n;
|
|
9
|
+
return i18n.t(key, {
|
|
10
|
+
ns: moduleName,
|
|
11
|
+
defaultValue: fallback,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isVersionSatisfied } from "./version";
|
|
2
|
+
|
|
3
|
+
describe("Version utilities", () => {
|
|
4
|
+
it("Is satisfied if exactly equals", () => {
|
|
5
|
+
const result = isVersionSatisfied("1.2.3", "1.2.3");
|
|
6
|
+
expect(result).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("Is satisfied if caret and minor change", () => {
|
|
10
|
+
const result = isVersionSatisfied("^1.2.3", "1.3.0");
|
|
11
|
+
expect(result).toBe(true);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("Is not satisfied if exact and minor change", () => {
|
|
15
|
+
const result = isVersionSatisfied("1.2.3", "1.3.0");
|
|
16
|
+
expect(result).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("Is not satisfied if caret and major change", () => {
|
|
20
|
+
const result = isVersionSatisfied("^1.2.3", "2.0.0");
|
|
21
|
+
expect(result).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("Is satisfied if caret and minor change with prerelease", () => {
|
|
25
|
+
const result = isVersionSatisfied("^1.2.3", "1.3.0-alpha.1");
|
|
26
|
+
expect(result).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("Is not satisfied if version equals same prerelease", () => {
|
|
30
|
+
const result = isVersionSatisfied("^3.1.10", "3.1.10-pre.284");
|
|
31
|
+
expect(result).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("Is satisfied if version equals higher with build number", () => {
|
|
35
|
+
const result = isVersionSatisfied("^2.24.0", "2.30.0.7e24fb");
|
|
36
|
+
expect(result).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("Is satisfied if version equals higher with build number and pre", () => {
|
|
40
|
+
const result = isVersionSatisfied("^2.24.0", "2.30.0.7e24fb-pre.3");
|
|
41
|
+
expect(result).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("Is not satisfied if version equals same with build number and pre", () => {
|
|
45
|
+
const result = isVersionSatisfied("^2.24.0", "2.24.0.7e24fb-pre.3");
|
|
46
|
+
expect(result).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("Is satisfied if version equals same with only build number", () => {
|
|
50
|
+
const result = isVersionSatisfied("^2.24.0", "2.24.0.7e24fb");
|
|
51
|
+
expect(result).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
});
|
package/src/version.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as semver from "semver";
|
|
2
|
+
|
|
3
|
+
function normalizeOnlyVersion(version: string) {
|
|
4
|
+
const [major, minor, patch] = version.split(".");
|
|
5
|
+
return `${major}.${minor}.${patch}`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function normalizeFullVersion(version: string) {
|
|
9
|
+
const idx = version.indexOf("-");
|
|
10
|
+
const prerelease = idx >= 0;
|
|
11
|
+
|
|
12
|
+
if (prerelease) {
|
|
13
|
+
const ver = normalizeOnlyVersion(version.substr(0, idx));
|
|
14
|
+
const pre = version.substr(idx + 1);
|
|
15
|
+
return `${ver}-${pre}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return normalizeOnlyVersion(version);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isVersionSatisfied(
|
|
22
|
+
requiredVersion: string,
|
|
23
|
+
installedVersion: string
|
|
24
|
+
) {
|
|
25
|
+
const version = normalizeFullVersion(installedVersion);
|
|
26
|
+
|
|
27
|
+
return semver.satisfies(version, requiredVersion, {
|
|
28
|
+
includePrerelease: true,
|
|
29
|
+
});
|
|
30
|
+
}
|
package/webpack.config.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
|
|
2
|
+
const SystemJSPublicPathWebpackPlugin = require("systemjs-webpack-interop/SystemJSPublicPathWebpackPlugin");
|
|
2
3
|
const { resolve } = require("path");
|
|
3
4
|
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
|
4
5
|
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
|
|
@@ -6,23 +7,15 @@ const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
|
|
|
6
7
|
const { peerDependencies } = require("./package.json");
|
|
7
8
|
|
|
8
9
|
module.exports = (env) => ({
|
|
9
|
-
entry: [
|
|
10
|
-
resolve(__dirname, "src/set-public-path.ts"),
|
|
11
|
-
resolve(__dirname, "src/index.ts"),
|
|
12
|
-
],
|
|
10
|
+
entry: [resolve(__dirname, "src/index.ts")],
|
|
13
11
|
output: {
|
|
14
12
|
filename: "openmrs-esm-utils.js",
|
|
15
13
|
path: resolve(__dirname, "dist"),
|
|
16
14
|
libraryTarget: "system",
|
|
17
15
|
},
|
|
18
|
-
devtool: "
|
|
16
|
+
devtool: "source-map",
|
|
19
17
|
module: {
|
|
20
18
|
rules: [
|
|
21
|
-
{
|
|
22
|
-
parser: {
|
|
23
|
-
system: false,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
19
|
{
|
|
27
20
|
test: /\.m?(js|ts|tsx)$/,
|
|
28
21
|
exclude: /(node_modules|bower_components)/,
|
|
@@ -30,11 +23,12 @@ module.exports = (env) => ({
|
|
|
30
23
|
},
|
|
31
24
|
],
|
|
32
25
|
},
|
|
33
|
-
externals: Object.keys(peerDependencies),
|
|
26
|
+
externals: Object.keys(peerDependencies || {}),
|
|
34
27
|
resolve: {
|
|
35
28
|
extensions: [".ts", ".js", ".tsx", ".jsx"],
|
|
36
29
|
},
|
|
37
30
|
plugins: [
|
|
31
|
+
new SystemJSPublicPathWebpackPlugin(),
|
|
38
32
|
new CleanWebpackPlugin(),
|
|
39
33
|
new ForkTsCheckerWebpackPlugin(),
|
|
40
34
|
new BundleAnalyzerPlugin({
|
package/src/set-public-path.ts
DELETED