@sparted/shared-library 1.0.7 → 1.0.8-alpha.0
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/.circleci/config.yml +40 -0
- package/.eslintignore +1 -0
- package/.eslintrc.js +17 -0
- package/.gitignore +37 -0
- package/CHANGELOG.md +34 -0
- package/README.md +26 -0
- package/dist/github/commits/create-git-blob.d.ts +26 -0
- package/dist/github/commits/create-git-blob.js +42 -0
- package/dist/github/commits/create-git-blob.js.map +1 -0
- package/dist/github/commits/create-git-commit.d.ts +23 -0
- package/dist/github/commits/create-git-commit.js +39 -0
- package/dist/github/commits/create-git-commit.js.map +1 -0
- package/dist/github/commits/create-git-tree.d.ts +29 -0
- package/dist/github/commits/create-git-tree.js +47 -0
- package/dist/github/commits/create-git-tree.js.map +1 -0
- package/dist/github/commits/get-sha-last-commit-of-branch.d.ts +21 -0
- package/dist/github/commits/get-sha-last-commit-of-branch.js +35 -0
- package/dist/github/commits/get-sha-last-commit-of-branch.js.map +1 -0
- package/dist/github/commits/get-tree-by-commit-sha.d.ts +23 -0
- package/dist/github/commits/get-tree-by-commit-sha.js +37 -0
- package/dist/github/commits/get-tree-by-commit-sha.js.map +1 -0
- package/dist/github/commits/index.d.ts +6 -0
- package/dist/github/commits/index.js +20 -0
- package/dist/github/commits/run-new-commit-process.d.ts +27 -0
- package/dist/github/commits/run-new-commit-process.js +49 -0
- package/dist/github/commits/run-new-commit-process.js.map +1 -0
- package/dist/github/commits/utils.d.ts +1 -0
- package/dist/github/commits/utils.js +29 -0
- package/dist/github/commits/utils.js.map +1 -0
- package/dist/github/github.d.ts +22 -0
- package/dist/github/github.js +50 -0
- package/dist/github/github.js.map +1 -0
- package/dist/github/index.d.ts +1 -0
- package/dist/github/index.js +10 -0
- package/dist/index.d.ts +15 -0
- package/{index.js → dist/index.js} +2 -0
- package/{index.js.map → dist/index.js.map} +1 -1
- package/dist/package.json +65 -0
- package/dist/string/index.js.map +1 -0
- package/dist/time/index.js.map +1 -0
- package/global.d.ts +2 -0
- package/package.json +5 -1
- package/rollup.config.ts +15 -0
- package/src/array/__tests__/array-to-map.test.ts +50 -0
- package/src/array/__tests__/get-values-from-keys.test.ts +14 -0
- package/src/array/array-to-map.ts +32 -0
- package/src/array/get-values-from-keys.ts +3 -0
- package/src/array/index.ts +2 -0
- package/src/cdn/__tests__/cdn.factory.test.ts +120 -0
- package/src/cdn/__tests__/utils.test.ts +456 -0
- package/src/cdn/cdn.factory.ts +63 -0
- package/src/cdn/index.ts +2 -0
- package/src/cdn/types/cdn-factory.type.ts +35 -0
- package/src/cdn/types/index.ts +1 -0
- package/src/cdn/utils/extract-info-from-url.util.ts +21 -0
- package/src/cdn/utils/get-cdn-from-s3-url.util.ts +20 -0
- package/src/cdn/utils/get-cdn-url.util.ts +26 -0
- package/src/formatting/__tests__/format-number.test.ts +11 -0
- package/src/formatting/format-number.ts +14 -0
- package/src/formatting/index.ts +1 -0
- package/src/fp/__tests__/run-while.test.ts +29 -0
- package/src/fp/index.ts +1 -0
- package/src/fp/run-while.ts +54 -0
- package/src/github/commits/create-git-blob.ts +57 -0
- package/src/github/commits/create-git-commit.ts +57 -0
- package/src/github/commits/create-git-tree.ts +68 -0
- package/src/github/commits/get-sha-last-commit-of-branch.ts +50 -0
- package/src/github/commits/get-tree-by-commit-sha.ts +52 -0
- package/src/github/commits/index.ts +6 -0
- package/src/github/commits/run-new-commit-process.ts +88 -0
- package/src/github/commits/utils.ts +31 -0
- package/src/github/github.ts +69 -0
- package/src/github/index.ts +1 -0
- package/src/http/__tests__/encode-search-object.test.ts +34 -0
- package/src/http/__tests__/fetch-with-timeout.test.ts +50 -0
- package/src/http/encode-search-object.ts +39 -0
- package/src/http/fetch-with-timeout.ts +24 -0
- package/src/http/index.ts +2 -0
- package/{index.d.ts → src/index.ts} +15 -14
- package/src/linked-list/__tests__/apply-diff-linked-list.test.ts +103 -0
- package/src/linked-list/__tests__/create-linked-list.test.ts +204 -0
- package/src/linked-list/__tests__/find-linked-list.test.ts +40 -0
- package/src/linked-list/__tests__/get-linked-list.test.ts +28 -0
- package/src/linked-list/__tests__/insert-linked-list.test.ts +186 -0
- package/src/linked-list/__tests__/linked-list-utils.test.ts +252 -0
- package/src/linked-list/__tests__/reduce-linked-list.test.ts +31 -0
- package/src/linked-list/__tests__/remove-linked-list.test.ts +129 -0
- package/src/linked-list/__tests__/update-linked-list.test.ts +53 -0
- package/src/linked-list/__tests__/while-linked-list.test.ts +58 -0
- package/src/linked-list/apply-diff-linked-list.ts +35 -0
- package/src/linked-list/create-linked-list.ts +79 -0
- package/src/linked-list/find-linked-list.ts +26 -0
- package/src/linked-list/get-linked-list.ts +9 -0
- package/src/linked-list/index.ts +2 -0
- package/src/linked-list/insert-linked-list.ts +50 -0
- package/src/linked-list/linked-list-utils.ts +143 -0
- package/src/linked-list/reduce-linked-list.ts +18 -0
- package/src/linked-list/remove-linked-list.ts +36 -0
- package/src/linked-list/type.ts +38 -0
- package/src/linked-list/update-linked-list.ts +29 -0
- package/src/linked-list/while-linked-list.ts +33 -0
- package/src/math/__tests__/clamp-number.test.ts +30 -0
- package/src/math/__tests__/interpolate.test.ts +28 -0
- package/src/math/__tests__/number-range.test.ts +59 -0
- package/src/math/__tests__/random-number.test.ts +11 -0
- package/src/math/clamp-number.ts +8 -0
- package/src/math/index.ts +4 -0
- package/src/math/interpolate.ts +18 -0
- package/src/math/number-range.ts +16 -0
- package/src/math/random-number.ts +10 -0
- package/src/object/__tests__/merge-deep.test.ts +56 -0
- package/src/object/index.ts +1 -0
- package/src/object/merge-deep.ts +27 -0
- package/src/parsing/__tests__/parse-boolean.test.ts +15 -0
- package/src/parsing/__tests__/parse-enum.test.ts +19 -0
- package/src/parsing/__tests__/parse-number.test.ts +20 -0
- package/src/parsing/index.ts +3 -0
- package/src/parsing/parse-boolean.ts +10 -0
- package/src/parsing/parse-enum.ts +16 -0
- package/src/parsing/parse-number.ts +12 -0
- package/src/predicates/__tests__/is-function.test.ts +11 -0
- package/src/predicates/__tests__/is-null.test.ts +11 -0
- package/src/predicates/__tests__/is-object.test.ts +11 -0
- package/src/predicates/__tests__/is-primitive.test.ts +42 -0
- package/src/predicates/__tests__/is-undefined.test.ts +11 -0
- package/src/predicates/__tests__/is-uuid.test.ts +13 -0
- package/src/predicates/index.ts +5 -0
- package/src/predicates/is-function.ts +3 -0
- package/src/predicates/is-null.ts +3 -0
- package/src/predicates/is-object.ts +3 -0
- package/src/predicates/is-primitive.ts +19 -0
- package/src/predicates/is-undefined.ts +3 -0
- package/src/predicates/is-uuid.ts +3 -0
- package/src/promise/__tests__/delay.test.ts +13 -0
- package/src/promise/__tests__/execute-or-resolve-default.test.ts +25 -0
- package/src/promise/__tests__/execute-with-delay.test.ts +24 -0
- package/src/promise/delay.ts +3 -0
- package/src/promise/execute-or-resolve-default.ts +14 -0
- package/src/promise/execute-with-delay.ts +6 -0
- package/src/promise/index.ts +3 -0
- package/src/string/__tests__/replace-in-template.test.ts +52 -0
- package/src/string/index.ts +1 -0
- package/src/string/replace-in-template.ts +45 -0
- package/src/time/__tests__/convert.test.ts +14 -0
- package/src/time/__tests__/format-minutes.test.ts +10 -0
- package/src/time/__tests__/get-time-diff-as-string.test.ts +128 -0
- package/src/time/constants.ts +4 -0
- package/src/time/convert.ts +5 -0
- package/src/time/format-minutes.ts +9 -0
- package/src/time/get-time-diff-as-string.ts +196 -0
- package/src/time/index.ts +4 -0
- package/src/types/function.ts +1 -0
- package/src/types/general.ts +8 -0
- package/src/types/index.ts +4 -0
- package/src/types/object.ts +33 -0
- package/src/types/search.ts +29 -0
- package/tsconfig.eslint.json +8 -0
- package/tsconfig.json +25 -0
- /package/{_virtual → dist/_virtual}/_tslib.js +0 -0
- /package/{_virtual → dist/_virtual}/_tslib.js.map +0 -0
- /package/{array → dist/array}/array-to-map.d.ts +0 -0
- /package/{array → dist/array}/array-to-map.js +0 -0
- /package/{array → dist/array}/array-to-map.js.map +0 -0
- /package/{array → dist/array}/get-values-from-keys.d.ts +0 -0
- /package/{array → dist/array}/get-values-from-keys.js +0 -0
- /package/{array → dist/array}/get-values-from-keys.js.map +0 -0
- /package/{array → dist/array}/index.d.ts +0 -0
- /package/{array → dist/array}/index.js +0 -0
- /package/{array → dist/array}/index.js.map +0 -0
- /package/{cdn → dist/cdn}/cdn.factory.d.ts +0 -0
- /package/{cdn → dist/cdn}/cdn.factory.js +0 -0
- /package/{cdn → dist/cdn}/cdn.factory.js.map +0 -0
- /package/{cdn → dist/cdn}/index.d.ts +0 -0
- /package/{cdn → dist/cdn}/index.js +0 -0
- /package/{cdn → dist/cdn}/index.js.map +0 -0
- /package/{cdn → dist/cdn}/types/cdn-factory.type.d.ts +0 -0
- /package/{cdn → dist/cdn}/types/index.d.ts +0 -0
- /package/{cdn → dist/cdn}/types/index.js +0 -0
- /package/{cdn → dist/cdn}/types/index.js.map +0 -0
- /package/{cdn → dist/cdn}/utils/extract-info-from-url.util.d.ts +0 -0
- /package/{cdn → dist/cdn}/utils/extract-info-from-url.util.js +0 -0
- /package/{cdn → dist/cdn}/utils/extract-info-from-url.util.js.map +0 -0
- /package/{cdn → dist/cdn}/utils/get-cdn-from-s3-url.util.d.ts +0 -0
- /package/{cdn → dist/cdn}/utils/get-cdn-from-s3-url.util.js +0 -0
- /package/{cdn → dist/cdn}/utils/get-cdn-from-s3-url.util.js.map +0 -0
- /package/{cdn → dist/cdn}/utils/get-cdn-url.util.d.ts +0 -0
- /package/{cdn → dist/cdn}/utils/get-cdn-url.util.js +0 -0
- /package/{cdn → dist/cdn}/utils/get-cdn-url.util.js.map +0 -0
- /package/{formatting → dist/formatting}/format-number.d.ts +0 -0
- /package/{formatting → dist/formatting}/format-number.js +0 -0
- /package/{formatting → dist/formatting}/format-number.js.map +0 -0
- /package/{formatting → dist/formatting}/index.d.ts +0 -0
- /package/{formatting → dist/formatting}/index.js +0 -0
- /package/{formatting → dist/formatting}/index.js.map +0 -0
- /package/{fp → dist/fp}/index.d.ts +0 -0
- /package/{fp → dist/fp}/index.js +0 -0
- /package/{fp → dist/fp}/index.js.map +0 -0
- /package/{fp → dist/fp}/run-while.d.ts +0 -0
- /package/{fp → dist/fp}/run-while.js +0 -0
- /package/{fp → dist/fp}/run-while.js.map +0 -0
- /package/{time → dist/github/commits}/index.js.map +0 -0
- /package/{linked-list → dist/github}/index.js.map +0 -0
- /package/{http → dist/http}/encode-search-object.d.ts +0 -0
- /package/{http → dist/http}/encode-search-object.js +0 -0
- /package/{http → dist/http}/encode-search-object.js.map +0 -0
- /package/{http → dist/http}/fetch-with-timeout.d.ts +0 -0
- /package/{http → dist/http}/fetch-with-timeout.js +0 -0
- /package/{http → dist/http}/fetch-with-timeout.js.map +0 -0
- /package/{http → dist/http}/index.d.ts +0 -0
- /package/{http → dist/http}/index.js +0 -0
- /package/{http → dist/http}/index.js.map +0 -0
- /package/{linked-list → dist/linked-list}/apply-diff-linked-list.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/apply-diff-linked-list.js +0 -0
- /package/{linked-list → dist/linked-list}/apply-diff-linked-list.js.map +0 -0
- /package/{linked-list → dist/linked-list}/create-linked-list.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/create-linked-list.js +0 -0
- /package/{linked-list → dist/linked-list}/create-linked-list.js.map +0 -0
- /package/{linked-list → dist/linked-list}/find-linked-list.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/find-linked-list.js +0 -0
- /package/{linked-list → dist/linked-list}/find-linked-list.js.map +0 -0
- /package/{linked-list → dist/linked-list}/get-linked-list.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/get-linked-list.js +0 -0
- /package/{linked-list → dist/linked-list}/get-linked-list.js.map +0 -0
- /package/{linked-list → dist/linked-list}/index.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/index.js +0 -0
- /package/{object → dist/linked-list}/index.js.map +0 -0
- /package/{linked-list → dist/linked-list}/insert-linked-list.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/insert-linked-list.js +0 -0
- /package/{linked-list → dist/linked-list}/insert-linked-list.js.map +0 -0
- /package/{linked-list → dist/linked-list}/linked-list-utils.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/linked-list-utils.js +0 -0
- /package/{linked-list → dist/linked-list}/linked-list-utils.js.map +0 -0
- /package/{linked-list → dist/linked-list}/reduce-linked-list.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/reduce-linked-list.js +0 -0
- /package/{linked-list → dist/linked-list}/reduce-linked-list.js.map +0 -0
- /package/{linked-list → dist/linked-list}/remove-linked-list.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/remove-linked-list.js +0 -0
- /package/{linked-list → dist/linked-list}/remove-linked-list.js.map +0 -0
- /package/{linked-list → dist/linked-list}/type.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/update-linked-list.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/update-linked-list.js +0 -0
- /package/{linked-list → dist/linked-list}/update-linked-list.js.map +0 -0
- /package/{linked-list → dist/linked-list}/while-linked-list.d.ts +0 -0
- /package/{linked-list → dist/linked-list}/while-linked-list.js +0 -0
- /package/{linked-list → dist/linked-list}/while-linked-list.js.map +0 -0
- /package/{math → dist/math}/clamp-number.d.ts +0 -0
- /package/{math → dist/math}/clamp-number.js +0 -0
- /package/{math → dist/math}/clamp-number.js.map +0 -0
- /package/{math → dist/math}/index.d.ts +0 -0
- /package/{math → dist/math}/index.js +0 -0
- /package/{math → dist/math}/index.js.map +0 -0
- /package/{math → dist/math}/interpolate.d.ts +0 -0
- /package/{math → dist/math}/interpolate.js +0 -0
- /package/{math → dist/math}/interpolate.js.map +0 -0
- /package/{math → dist/math}/number-range.d.ts +0 -0
- /package/{math → dist/math}/number-range.js +0 -0
- /package/{math → dist/math}/number-range.js.map +0 -0
- /package/{math → dist/math}/random-number.d.ts +0 -0
- /package/{math → dist/math}/random-number.js +0 -0
- /package/{math → dist/math}/random-number.js.map +0 -0
- /package/{object → dist/object}/index.d.ts +0 -0
- /package/{object → dist/object}/index.js +0 -0
- /package/{string → dist/object}/index.js.map +0 -0
- /package/{object → dist/object}/merge-deep.d.ts +0 -0
- /package/{object → dist/object}/merge-deep.js +0 -0
- /package/{object → dist/object}/merge-deep.js.map +0 -0
- /package/{parsing → dist/parsing}/index.d.ts +0 -0
- /package/{parsing → dist/parsing}/index.js +0 -0
- /package/{parsing → dist/parsing}/index.js.map +0 -0
- /package/{parsing → dist/parsing}/parse-boolean.d.ts +0 -0
- /package/{parsing → dist/parsing}/parse-boolean.js +0 -0
- /package/{parsing → dist/parsing}/parse-boolean.js.map +0 -0
- /package/{parsing → dist/parsing}/parse-enum.d.ts +0 -0
- /package/{parsing → dist/parsing}/parse-enum.js +0 -0
- /package/{parsing → dist/parsing}/parse-enum.js.map +0 -0
- /package/{parsing → dist/parsing}/parse-number.d.ts +0 -0
- /package/{parsing → dist/parsing}/parse-number.js +0 -0
- /package/{parsing → dist/parsing}/parse-number.js.map +0 -0
- /package/{predicates → dist/predicates}/index.d.ts +0 -0
- /package/{predicates → dist/predicates}/index.js +0 -0
- /package/{predicates → dist/predicates}/index.js.map +0 -0
- /package/{predicates → dist/predicates}/is-function.d.ts +0 -0
- /package/{predicates → dist/predicates}/is-function.js +0 -0
- /package/{predicates → dist/predicates}/is-function.js.map +0 -0
- /package/{predicates → dist/predicates}/is-null.d.ts +0 -0
- /package/{predicates → dist/predicates}/is-null.js +0 -0
- /package/{predicates → dist/predicates}/is-null.js.map +0 -0
- /package/{predicates → dist/predicates}/is-object.d.ts +0 -0
- /package/{predicates → dist/predicates}/is-object.js +0 -0
- /package/{predicates → dist/predicates}/is-object.js.map +0 -0
- /package/{predicates → dist/predicates}/is-primitive.d.ts +0 -0
- /package/{predicates → dist/predicates}/is-primitive.js +0 -0
- /package/{predicates → dist/predicates}/is-primitive.js.map +0 -0
- /package/{predicates → dist/predicates}/is-undefined.d.ts +0 -0
- /package/{predicates → dist/predicates}/is-undefined.js +0 -0
- /package/{predicates → dist/predicates}/is-undefined.js.map +0 -0
- /package/{predicates → dist/predicates}/is-uuid.d.ts +0 -0
- /package/{promise → dist/promise}/delay.d.ts +0 -0
- /package/{promise → dist/promise}/delay.js +0 -0
- /package/{promise → dist/promise}/delay.js.map +0 -0
- /package/{promise → dist/promise}/execute-or-resolve-default.d.ts +0 -0
- /package/{promise → dist/promise}/execute-or-resolve-default.js +0 -0
- /package/{promise → dist/promise}/execute-or-resolve-default.js.map +0 -0
- /package/{promise → dist/promise}/execute-with-delay.d.ts +0 -0
- /package/{promise → dist/promise}/execute-with-delay.js +0 -0
- /package/{promise → dist/promise}/execute-with-delay.js.map +0 -0
- /package/{promise → dist/promise}/index.d.ts +0 -0
- /package/{promise → dist/promise}/index.js +0 -0
- /package/{promise → dist/promise}/index.js.map +0 -0
- /package/{string → dist/string}/index.d.ts +0 -0
- /package/{string → dist/string}/index.js +0 -0
- /package/{string → dist/string}/replace-in-template.d.ts +0 -0
- /package/{string → dist/string}/replace-in-template.js +0 -0
- /package/{string → dist/string}/replace-in-template.js.map +0 -0
- /package/{time → dist/time}/constants.d.ts +0 -0
- /package/{time → dist/time}/constants.js +0 -0
- /package/{time → dist/time}/constants.js.map +0 -0
- /package/{time → dist/time}/convert.d.ts +0 -0
- /package/{time → dist/time}/convert.js +0 -0
- /package/{time → dist/time}/convert.js.map +0 -0
- /package/{time → dist/time}/format-minutes.d.ts +0 -0
- /package/{time → dist/time}/format-minutes.js +0 -0
- /package/{time → dist/time}/format-minutes.js.map +0 -0
- /package/{time → dist/time}/get-time-diff-as-string.d.ts +0 -0
- /package/{time → dist/time}/get-time-diff-as-string.js +0 -0
- /package/{time → dist/time}/get-time-diff-as-string.js.map +0 -0
- /package/{time → dist/time}/index.d.ts +0 -0
- /package/{time → dist/time}/index.js +0 -0
- /package/{types → dist/types}/function.d.ts +0 -0
- /package/{types → dist/types}/general.d.ts +0 -0
- /package/{types → dist/types}/index.d.ts +0 -0
- /package/{types → dist/types}/index.js +0 -0
- /package/{types → dist/types}/index.js.map +0 -0
- /package/{types → dist/types}/object.d.ts +0 -0
- /package/{types → dist/types}/search.d.ts +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { parseNumber } from '../parse-number';
|
|
2
|
+
|
|
3
|
+
describe('parseNumber', () => {
|
|
4
|
+
it('should return number 10 if value is "10', () => {
|
|
5
|
+
expect(parseNumber('10')).toStrictEqual(10);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should return -10 if value is "-10"', () => {
|
|
9
|
+
expect(parseNumber('-10')).toStrictEqual(-10);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should return 0 if value is "0"', () => {
|
|
13
|
+
expect(parseNumber('0')).toStrictEqual(0);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should throw an exception if value is not a number', () => {
|
|
17
|
+
expect(() => parseNumber('number')).toThrow();
|
|
18
|
+
expect(() => parseNumber('false')).toThrow();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a string to a boolean. Throw error if string is neither "true" nor "false"
|
|
3
|
+
*/
|
|
4
|
+
export const parseBoolean = (value: string): boolean => {
|
|
5
|
+
if (value !== 'true' && value !== 'false') {
|
|
6
|
+
throw new Error('Cannot parse value');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return value === 'true';
|
|
10
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Primitive } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Factory to build enum to parse a string to an enum. Throw error if string is not an enum value
|
|
5
|
+
*/
|
|
6
|
+
export const createEnumParser = <E extends Record<string, Primitive>>(enumType: E) => (
|
|
7
|
+
(value: string) => {
|
|
8
|
+
const enumValues = Object.values(enumType);
|
|
9
|
+
|
|
10
|
+
if (!enumValues.includes(value as any)) {
|
|
11
|
+
throw new Error('Can\'t parse this value');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return value as unknown as E;
|
|
15
|
+
}
|
|
16
|
+
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a string to a number. Throw error if string is NaN
|
|
3
|
+
*/
|
|
4
|
+
export const parseNumber = (value: string): number => {
|
|
5
|
+
const number = parseInt(value, 10);
|
|
6
|
+
|
|
7
|
+
if (Number.isNaN(number)) {
|
|
8
|
+
throw new Error('Cannot parse value');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return number;
|
|
12
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { isFunction } from '../is-function';
|
|
2
|
+
|
|
3
|
+
describe('isFunction', () => {
|
|
4
|
+
it('should return true if value is a function', () => {
|
|
5
|
+
expect(isFunction(() => {})).toBeTrue();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should return false if value is not a function', () => {
|
|
9
|
+
expect(isFunction('')).toBeFalse();
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { isNull } from '../is-null';
|
|
2
|
+
|
|
3
|
+
describe('isNull', () => {
|
|
4
|
+
it('should return true if value is null', () => {
|
|
5
|
+
expect(isNull(null)).toBeTrue();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should return false if value is not null', () => {
|
|
9
|
+
expect(isNull('')).toBeFalse();
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { isObject } from '../is-object';
|
|
2
|
+
|
|
3
|
+
describe('isObject', () => {
|
|
4
|
+
it('should return true if value is an object', () => {
|
|
5
|
+
expect(isObject({})).toBeTrue();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should return false if value is not an object', () => {
|
|
9
|
+
expect(isObject('')).toBeFalse();
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isPrimitive, isArrayOfPrimitive } from '../is-primitive';
|
|
2
|
+
|
|
3
|
+
describe('isPrimitive', () => {
|
|
4
|
+
it('should return true if value is a primitive', () => {
|
|
5
|
+
expect(isPrimitive('a value')).toBeTrue();
|
|
6
|
+
expect(isPrimitive(6)).toBeTrue();
|
|
7
|
+
expect(isPrimitive(true)).toBeTrue();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should return false if value is not a primitive', () => {
|
|
11
|
+
expect(isPrimitive({})).toBeFalse();
|
|
12
|
+
expect(isPrimitive(new Date())).toBeFalse();
|
|
13
|
+
expect(isPrimitive([])).toBeFalse();
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('isArrayOfPrimitive', () => {
|
|
18
|
+
it('should return false if value not an array', () => {
|
|
19
|
+
expect(isArrayOfPrimitive({})).toBeFalse();
|
|
20
|
+
expect(isArrayOfPrimitive(1)).toBeFalse();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should return false if not every value in the array is primitive', () => {
|
|
24
|
+
expect(isArrayOfPrimitive([
|
|
25
|
+
1,
|
|
26
|
+
'test',
|
|
27
|
+
true,
|
|
28
|
+
false,
|
|
29
|
+
[],
|
|
30
|
+
{},
|
|
31
|
+
])).toBeFalse();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return true if every value in the array is a primitive', () => {
|
|
35
|
+
expect(isArrayOfPrimitive([
|
|
36
|
+
1,
|
|
37
|
+
'test',
|
|
38
|
+
true,
|
|
39
|
+
false,
|
|
40
|
+
])).toBeTrue();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { isUndefined } from '../is-undefined';
|
|
2
|
+
|
|
3
|
+
describe('isUndefined', () => {
|
|
4
|
+
it('should return true if value is undefined', () => {
|
|
5
|
+
expect(isUndefined(undefined)).toBeTrue();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should return false if value is not undefined', () => {
|
|
9
|
+
expect(isUndefined('')).toBeFalse();
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { isUuidV4 } from '../is-uuid';
|
|
2
|
+
|
|
3
|
+
describe('isUuidV4', () => {
|
|
4
|
+
it('returns true if the string is uuid v4', () => {
|
|
5
|
+
expect(isUuidV4('dd819894-70f3-4629-8712-430445f93c5d')).toBeTrue();
|
|
6
|
+
});
|
|
7
|
+
it('returns false if argument is not a string', () => {
|
|
8
|
+
expect(isUuidV4(4)).toBeFalse();
|
|
9
|
+
});
|
|
10
|
+
it('returns false if argument is uuid V1', () => {
|
|
11
|
+
expect(isUuidV4('4dfde9e2-3988-11ed-a261-0242ac120002')).toBeFalse();
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Primitive } from '../types/general';
|
|
2
|
+
|
|
3
|
+
const PRIMITIVE_TYPES = [
|
|
4
|
+
'string',
|
|
5
|
+
'boolean',
|
|
6
|
+
'number',
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
export const isPrimitive = (value: any): value is Primitive => (
|
|
10
|
+
PRIMITIVE_TYPES.includes(typeof value)
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export const isArrayOfPrimitive = (value: any): value is Array<Primitive> => {
|
|
14
|
+
if (!Array.isArray(value)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return value.every((arrayValue) => isPrimitive(arrayValue));
|
|
19
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { delay } from '../delay';
|
|
2
|
+
|
|
3
|
+
jest.useFakeTimers();
|
|
4
|
+
jest.spyOn(global, 'setTimeout');
|
|
5
|
+
|
|
6
|
+
describe('delay.ts', () => {
|
|
7
|
+
it('waits ', () => {
|
|
8
|
+
delay(500);
|
|
9
|
+
|
|
10
|
+
expect(setTimeout).toHaveBeenCalledOnce();
|
|
11
|
+
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 500);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { executeOrResolveDefault } from '../execute-or-resolve-default';
|
|
2
|
+
|
|
3
|
+
describe('executeOrResolveDefault', () => {
|
|
4
|
+
it('should execute the function', async () => {
|
|
5
|
+
const cb = jest.fn().mockResolvedValue(8);
|
|
6
|
+
const res = await executeOrResolveDefault(cb, {
|
|
7
|
+
execute: true,
|
|
8
|
+
defaultValue: undefined,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
expect(res).toStrictEqual(8);
|
|
12
|
+
expect(cb).toHaveBeenCalledTimes(1);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should not execute the function', async () => {
|
|
16
|
+
const cb = jest.fn().mockResolvedValue(8);
|
|
17
|
+
const res = await executeOrResolveDefault(cb, {
|
|
18
|
+
execute: false,
|
|
19
|
+
defaultValue: 'sup m8',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
expect(res).toStrictEqual('sup m8');
|
|
23
|
+
expect(cb).toHaveBeenCalledTimes(0);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { executeWithDelay } from '../execute-with-delay';
|
|
2
|
+
|
|
3
|
+
describe('executeWithDelay', () => {
|
|
4
|
+
beforeAll(() => {
|
|
5
|
+
jest.useFakeTimers();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
afterAll(() => {
|
|
9
|
+
jest.useRealTimers();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should execute the promise with a delay', async () => {
|
|
13
|
+
const setTimeoutSpy = jest.spyOn(global, 'setTimeout');
|
|
14
|
+
const res = executeWithDelay(() => Promise.resolve(1), 500);
|
|
15
|
+
|
|
16
|
+
expect(setTimeoutSpy).toHaveBeenCalledWith(expect.toBeFunction(), 500);
|
|
17
|
+
|
|
18
|
+
jest.advanceTimersByTime(501);
|
|
19
|
+
|
|
20
|
+
expect(await res).toStrictEqual(1);
|
|
21
|
+
|
|
22
|
+
setTimeoutSpy.mockRestore();
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type ExecutionConfig<Default> = {
|
|
2
|
+
execute: boolean,
|
|
3
|
+
defaultValue: Default,
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export const executeOrResolveDefault = <T, Default>(callback: () => Promise<T>, config: ExecutionConfig<Default>): Promise<T | Default> => {
|
|
7
|
+
const { execute, defaultValue } = config;
|
|
8
|
+
|
|
9
|
+
if (execute) {
|
|
10
|
+
return callback();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return Promise.resolve(defaultValue);
|
|
14
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { replaceInTemplate } from '../replace-in-template';
|
|
2
|
+
|
|
3
|
+
describe('replaceInTemplate', () => {
|
|
4
|
+
it('should inject the params object into the template with the default config', () => {
|
|
5
|
+
const template = 'You need to wait {{time}} minutes before ordering on {{deliveryService}} again';
|
|
6
|
+
const message = replaceInTemplate(template, {
|
|
7
|
+
time: 5,
|
|
8
|
+
deliveryService: 'Uber Eat',
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
expect(message).toStrictEqual('You need to wait 5 minutes before ordering on Uber Eat again');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should handle if there is a primitive array in params', () => {
|
|
15
|
+
const template = 'Grocery: {{groceries}}';
|
|
16
|
+
const message = replaceInTemplate(template, {
|
|
17
|
+
groceries: [
|
|
18
|
+
'Twix',
|
|
19
|
+
'Oasis',
|
|
20
|
+
'm&ms',
|
|
21
|
+
],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
expect(message).toStrictEqual('Grocery: Twix, Oasis, m&ms');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should ignore non primitive values', () => {
|
|
28
|
+
const template = 'City: {{city}}, population: {{population}}';
|
|
29
|
+
const message = replaceInTemplate(template, {
|
|
30
|
+
city: 'Washington D.C.',
|
|
31
|
+
population: {
|
|
32
|
+
value: 12000000,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(message).toStrictEqual('City: Washington D.C., population: {{population}}');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should handle custom delimiter', () => {
|
|
40
|
+
const template = 'ISO |iso|, |focalLength| mm, f/|aperture|';
|
|
41
|
+
const params = {
|
|
42
|
+
iso: 100,
|
|
43
|
+
focalLength: 50,
|
|
44
|
+
aperture: '2.8',
|
|
45
|
+
};
|
|
46
|
+
const message = replaceInTemplate(template, params, {
|
|
47
|
+
delimiter: '|',
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
expect(message).toStrictEqual('ISO 100, 50 mm, f/2.8');
|
|
51
|
+
});
|
|
52
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './replace-in-template';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { isArrayOfPrimitive, isPrimitive } from '../predicates';
|
|
2
|
+
|
|
3
|
+
export type ReplaceConfig = {
|
|
4
|
+
delimiter: string | {
|
|
5
|
+
left: string,
|
|
6
|
+
right: string,
|
|
7
|
+
},
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const defaultConfig: ReplaceConfig = {
|
|
11
|
+
delimiter: {
|
|
12
|
+
left: '{{',
|
|
13
|
+
right: '}}',
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Replace string inside a template. For now, only works with
|
|
19
|
+
* an object containing promirives or array of primitives. If
|
|
20
|
+
* it contains other objects, they will be ignored.
|
|
21
|
+
*
|
|
22
|
+
* Uses the mustache syntax by default.
|
|
23
|
+
*/
|
|
24
|
+
export const replaceInTemplate = (
|
|
25
|
+
template: string,
|
|
26
|
+
params: Record<string, any>,
|
|
27
|
+
config: ReplaceConfig = defaultConfig,
|
|
28
|
+
) => {
|
|
29
|
+
const { delimiter } = config;
|
|
30
|
+
const leftDelimiter = typeof delimiter === 'string' ? delimiter : delimiter.left;
|
|
31
|
+
const rightDelimiter = typeof delimiter === 'string' ? delimiter : delimiter.right;
|
|
32
|
+
|
|
33
|
+
return Object
|
|
34
|
+
.entries(params)
|
|
35
|
+
.reduce((acc, [key, value]) => {
|
|
36
|
+
if (!isPrimitive(value) && !isArrayOfPrimitive(value)) {
|
|
37
|
+
return acc;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const searchValue = `${leftDelimiter}${key}${rightDelimiter}`;
|
|
41
|
+
const replaceBy = Array.isArray(value) ? value.join(', ') : String(value);
|
|
42
|
+
|
|
43
|
+
return acc.replace(searchValue, replaceBy);
|
|
44
|
+
}, template);
|
|
45
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { msToHour, msToMinute } from '../convert';
|
|
2
|
+
|
|
3
|
+
describe('msToMinute', () => {
|
|
4
|
+
it('should correctly convert milliseconds to minutes', () => {
|
|
5
|
+
expect(msToMinute(2520000)).toStrictEqual(42);
|
|
6
|
+
});
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
describe('msToHour', () => {
|
|
10
|
+
it('should correctly convert milliseconds to hours', () => {
|
|
11
|
+
expect(msToHour(1.08e+7)).toStrictEqual(3);
|
|
12
|
+
expect(msToHour(10)).toStrictEqual(0);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { formatMinutes } from '../format-minutes';
|
|
2
|
+
|
|
3
|
+
describe('formatMinutes', () => {
|
|
4
|
+
it('should format minutes correctly', () => {
|
|
5
|
+
expect(formatMinutes(48)).toBe('48min');
|
|
6
|
+
expect(formatMinutes(65)).toBe('1h5min');
|
|
7
|
+
expect(formatMinutes(150)).toBe('2h30min');
|
|
8
|
+
expect(formatMinutes(355)).toBe('5h55min');
|
|
9
|
+
});
|
|
10
|
+
});
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { getTimeDiffAsString } from '../get-time-diff-as-string';
|
|
2
|
+
import type { MonthLocaleLabels } from '../get-time-diff-as-string';
|
|
3
|
+
|
|
4
|
+
describe('getTimeDiffAsString', () => {
|
|
5
|
+
const recentDate = new Date('2020-10-20 00:00:00.000');
|
|
6
|
+
const locales: MonthLocaleLabels = [
|
|
7
|
+
'January',
|
|
8
|
+
'February',
|
|
9
|
+
'March',
|
|
10
|
+
'April',
|
|
11
|
+
'May',
|
|
12
|
+
'June',
|
|
13
|
+
'July',
|
|
14
|
+
'August',
|
|
15
|
+
'September',
|
|
16
|
+
'October',
|
|
17
|
+
'November',
|
|
18
|
+
'December',
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
it('should correctly handle recent date in first param', () => {
|
|
22
|
+
const shouldBeEmptyString = getTimeDiffAsString(
|
|
23
|
+
new Date('2020-10-20 00:15:00.000'),
|
|
24
|
+
recentDate,
|
|
25
|
+
);
|
|
26
|
+
expect(shouldBeEmptyString).toStrictEqual('');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should correctly return formated minutes', () => {
|
|
30
|
+
const shouldBeFifteenMinAgo = getTimeDiffAsString(
|
|
31
|
+
new Date('2020-10-19 23:45:00.000'),
|
|
32
|
+
recentDate,
|
|
33
|
+
);
|
|
34
|
+
expect(shouldBeFifteenMinAgo).toStrictEqual('15 min ago');
|
|
35
|
+
|
|
36
|
+
const shouldbeFiftyNineMinAgo = getTimeDiffAsString(
|
|
37
|
+
new Date('2020-10-19 23:01:00.000'),
|
|
38
|
+
recentDate,
|
|
39
|
+
);
|
|
40
|
+
expect(shouldbeFiftyNineMinAgo).toStrictEqual('59 min ago');
|
|
41
|
+
|
|
42
|
+
const shouldBeOneMinAgo = getTimeDiffAsString(
|
|
43
|
+
new Date('2020-10-19 23:59:00.000'),
|
|
44
|
+
recentDate,
|
|
45
|
+
);
|
|
46
|
+
expect(shouldBeOneMinAgo).toStrictEqual('1 min ago');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should correctly return formated hours', () => {
|
|
50
|
+
const shouldBeOneHourAgo = getTimeDiffAsString(
|
|
51
|
+
new Date('2020-10-19 23:00:00.000'),
|
|
52
|
+
recentDate,
|
|
53
|
+
);
|
|
54
|
+
expect(shouldBeOneHourAgo).toStrictEqual('1 hour ago');
|
|
55
|
+
|
|
56
|
+
const shouldBeTwelveHoursAgo = getTimeDiffAsString(
|
|
57
|
+
new Date('2020-10-19 12:00:00.000'),
|
|
58
|
+
recentDate,
|
|
59
|
+
);
|
|
60
|
+
expect(shouldBeTwelveHoursAgo).toStrictEqual('12 hours ago');
|
|
61
|
+
|
|
62
|
+
const shouldBeTwentyThreeHoursAgo = getTimeDiffAsString(
|
|
63
|
+
new Date('2020-10-19 01:00:00.000'),
|
|
64
|
+
recentDate,
|
|
65
|
+
);
|
|
66
|
+
expect(shouldBeTwentyThreeHoursAgo).toStrictEqual('23 hours ago');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should correctly return formated date', () => {
|
|
70
|
+
const shouldBeOneDayAgo = getTimeDiffAsString(
|
|
71
|
+
new Date('2020-10-19 00:00:00.000'),
|
|
72
|
+
recentDate,
|
|
73
|
+
);
|
|
74
|
+
expect(shouldBeOneDayAgo).toStrictEqual('on October 19, 12:00 am');
|
|
75
|
+
|
|
76
|
+
const shouldBeTenMonthAgo = getTimeDiffAsString(
|
|
77
|
+
new Date('2020-01-20 12:30:00.000'),
|
|
78
|
+
recentDate,
|
|
79
|
+
);
|
|
80
|
+
expect(shouldBeTenMonthAgo).toStrictEqual('on January 20, 12:30 pm');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should correctly return according to template', () => {
|
|
84
|
+
const template = {
|
|
85
|
+
fullDateTemplate: 'hello %date% darkness',
|
|
86
|
+
timeTemplate: '%time% %timeLabel% yeet',
|
|
87
|
+
monthLocaleLabels: locales,
|
|
88
|
+
timeLabel: {
|
|
89
|
+
hour: { plural: 'a', singular: 'b' },
|
|
90
|
+
minute: { plural: 'c', singular: 'd' },
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
const shouldBeEmptyString = getTimeDiffAsString(
|
|
94
|
+
new Date('2020-10-19 00:00:00.000'),
|
|
95
|
+
recentDate,
|
|
96
|
+
template,
|
|
97
|
+
);
|
|
98
|
+
expect(shouldBeEmptyString).toStrictEqual('hello October 19, 12:00 am darkness');
|
|
99
|
+
|
|
100
|
+
const shouldBeTwoHoursAgo = getTimeDiffAsString(
|
|
101
|
+
new Date('2020-10-19 22:00:00.000'),
|
|
102
|
+
recentDate,
|
|
103
|
+
template,
|
|
104
|
+
);
|
|
105
|
+
expect(shouldBeTwoHoursAgo).toStrictEqual('2 a yeet');
|
|
106
|
+
|
|
107
|
+
const shouldBeOneHourAgo = getTimeDiffAsString(
|
|
108
|
+
new Date('2020-10-19 23:00:00.000'),
|
|
109
|
+
recentDate,
|
|
110
|
+
template,
|
|
111
|
+
);
|
|
112
|
+
expect(shouldBeOneHourAgo).toStrictEqual('1 b yeet');
|
|
113
|
+
|
|
114
|
+
const shouldbeFiftyNineMinAgo = getTimeDiffAsString(
|
|
115
|
+
new Date('2020-10-19 23:01:00.000'),
|
|
116
|
+
recentDate,
|
|
117
|
+
template,
|
|
118
|
+
);
|
|
119
|
+
expect(shouldbeFiftyNineMinAgo).toStrictEqual('59 c yeet');
|
|
120
|
+
|
|
121
|
+
const shouldBeOneMinAgo = getTimeDiffAsString(
|
|
122
|
+
new Date('2020-10-19 23:59:00.000'),
|
|
123
|
+
recentDate,
|
|
124
|
+
template,
|
|
125
|
+
);
|
|
126
|
+
expect(shouldBeOneMinAgo).toStrictEqual('1 d yeet');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export const formatMinutes = (timeInMin: number): string => {
|
|
2
|
+
const hours = Math.floor(timeInMin / 60);
|
|
3
|
+
const mins = Math.round(timeInMin % 60);
|
|
4
|
+
|
|
5
|
+
if (hours === 0) return `${mins}min`;
|
|
6
|
+
if (mins === 0) return `${hours}h`;
|
|
7
|
+
|
|
8
|
+
return `${hours}h${mins}min`;
|
|
9
|
+
};
|