inferred-types 0.35.0 → 0.36.1
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 -34
- package/dist/index.d.ts +1812 -1656
- package/dist/index.mjs +95 -26
- package/package.json +12 -11
- package/src/runtime/combinators/filter.ts +0 -1
- package/src/runtime/lists/asArray.ts +8 -4
- package/src/runtime/lists/createConverter.ts +62 -0
- package/src/runtime/lists/index.ts +1 -0
- package/src/runtime/literals/box.ts +41 -20
- package/src/runtime/literals/ensureLeading.ts +17 -0
- package/src/runtime/literals/ensureTrailing.ts +17 -0
- package/src/runtime/literals/index.ts +4 -2
- package/src/runtime/literals/pathJoin.ts +22 -7
- package/src/runtime/literals/{stripStarting.ts → stripLeading.ts} +4 -4
- package/src/runtime/literals/stripTrailing.ts +15 -0
- package/src/runtime/literals/wide.ts +13 -0
- package/src/runtime/type-checks/ifSameType.ts +20 -0
- package/src/runtime/type-checks/index.ts +1 -0
- package/src/runtime/type-checks/isBoolean.ts +2 -1
- package/src/runtime/type-checks/isFunction.ts +2 -4
- package/src/runtime/type-checks/isObject.ts +10 -2
- package/src/runtime/type-checks/isString.ts +1 -1
- package/src/runtime/type-checks/isUndefined.ts +8 -0
- package/src/types/alphabetic/EnsureLeading.ts +24 -0
- package/src/types/alphabetic/EnsureTrailing.ts +24 -0
- package/src/types/alphabetic/PathJoin.ts +43 -31
- package/src/types/alphabetic/{StripStarting.ts → StripLeading.ts} +1 -1
- package/src/types/alphabetic/{StripEnding.ts → StripTrailing.ts} +1 -1
- package/src/types/alphabetic/index.ts +5 -2
- package/src/types/boolean-logic/HasParameters.ts +21 -0
- package/src/types/boolean-logic/array.ts +2 -2
- package/src/types/boolean-logic/boolean.ts +1 -1
- package/src/types/boolean-logic/equivalency.ts +2 -2
- package/src/types/boolean-logic/index.ts +1 -0
- package/src/types/dictionary/props.ts +5 -0
- package/src/types/lists/ConvertAndMap.ts +151 -0
- package/src/types/type-conversion/Widen.ts +15 -0
- package/tests/boolean-logic/HasParameters.ts +29 -0
- package/tests/lists/asArray.test.ts +19 -1
- package/tests/literals/EnsureStripLeadingTrailing.test.ts +79 -0
- package/tests/literals/PathJoin.test.ts +44 -37
- package/tests/literals/box.test.ts +31 -23
- package/tests/runtime/if-is.spec.ts +66 -5
- package/tests/runtime/map-and-convert.test.ts +31 -0
- package/dist/index.js +0 -868
- package/src/runtime/literals/stripEnding.ts +0 -9
package/dist/index.mjs
CHANGED
|
@@ -75,6 +75,11 @@ var condition = (c, input) => {
|
|
|
75
75
|
return c(input);
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
+
// src/runtime/type-checks/ifSameType.ts
|
|
79
|
+
function ifSameType(value, comparisonType, ifExtends, doesNotExtend) {
|
|
80
|
+
return typeof value === typeof comparisonType ? ifExtends(value) : doesNotExtend(value);
|
|
81
|
+
}
|
|
82
|
+
|
|
78
83
|
// src/runtime/type-checks/isArray.ts
|
|
79
84
|
function isArray(i) {
|
|
80
85
|
return Array.isArray(i) === true;
|
|
@@ -129,6 +134,9 @@ function ifNumber(val, ifVal, elseVal) {
|
|
|
129
134
|
function isObject(i) {
|
|
130
135
|
return typeof i === "object" && i !== null && Array.isArray(i) === false;
|
|
131
136
|
}
|
|
137
|
+
function ifObject(val, ifObj, notObj) {
|
|
138
|
+
return isObject(val) ? ifObj : notObj;
|
|
139
|
+
}
|
|
132
140
|
|
|
133
141
|
// src/runtime/type-checks/isString.ts
|
|
134
142
|
function isString(i) {
|
|
@@ -158,6 +166,9 @@ function isUndefined(i) {
|
|
|
158
166
|
function ifUndefined(val, ifVal, elseVal) {
|
|
159
167
|
return isUndefined(val) ? ifVal : elseVal;
|
|
160
168
|
}
|
|
169
|
+
function ifDefined(val, ifVal, elseVal) {
|
|
170
|
+
return isUndefined(val) ? ifVal : elseVal;
|
|
171
|
+
}
|
|
161
172
|
|
|
162
173
|
// src/runtime/runtime/type.ts
|
|
163
174
|
var typeApi = () => ({
|
|
@@ -621,6 +632,69 @@ function groupBy(_data) {
|
|
|
621
632
|
throw new Error("not implemented");
|
|
622
633
|
}
|
|
623
634
|
|
|
635
|
+
// src/runtime/literals/box.ts
|
|
636
|
+
function box(value) {
|
|
637
|
+
const rtn = {
|
|
638
|
+
__kind: "box",
|
|
639
|
+
value,
|
|
640
|
+
unbox: (...p) => {
|
|
641
|
+
return typeof value === "function" ? value(...p) : value;
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
return rtn;
|
|
645
|
+
}
|
|
646
|
+
function isBox(thing) {
|
|
647
|
+
return typeof thing === "object" && "__kind" in thing && thing.__kind === "box";
|
|
648
|
+
}
|
|
649
|
+
function boxDictionaryValues(dict) {
|
|
650
|
+
return keys(dict).reduce(
|
|
651
|
+
(acc, key) => ({ ...acc, [key]: box(dict[key]) }),
|
|
652
|
+
{}
|
|
653
|
+
);
|
|
654
|
+
}
|
|
655
|
+
function unbox(val) {
|
|
656
|
+
return isBox(val) ? val.value : val;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// src/runtime/literals/wide.ts
|
|
660
|
+
var wide = {
|
|
661
|
+
boolean: false,
|
|
662
|
+
string: "",
|
|
663
|
+
number: 0,
|
|
664
|
+
symbol: Symbol(),
|
|
665
|
+
null: null,
|
|
666
|
+
undefined: void 0
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
// src/runtime/lists/createConverter.ts
|
|
670
|
+
function createConverter(mapper2) {
|
|
671
|
+
const converter = boxDictionaryValues(mapper2);
|
|
672
|
+
return (input) => {
|
|
673
|
+
const v = ifSameType(
|
|
674
|
+
input,
|
|
675
|
+
wide.string,
|
|
676
|
+
(i) => converter.string.unbox(i),
|
|
677
|
+
(i) => ifSameType(
|
|
678
|
+
i,
|
|
679
|
+
wide.number,
|
|
680
|
+
(i2) => converter.number.unbox(i2),
|
|
681
|
+
(i2) => ifSameType(
|
|
682
|
+
i2,
|
|
683
|
+
wide.boolean,
|
|
684
|
+
(i3) => converter.boolean.unbox(i3),
|
|
685
|
+
(i3) => ifSameType(
|
|
686
|
+
i3,
|
|
687
|
+
{},
|
|
688
|
+
(i4) => converter.object.unbox(i4),
|
|
689
|
+
(i4) => i4
|
|
690
|
+
)
|
|
691
|
+
)
|
|
692
|
+
)
|
|
693
|
+
);
|
|
694
|
+
return v;
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
|
|
624
698
|
// src/runtime/literals/ExplicitFunction.ts
|
|
625
699
|
function ExplicitFunction(fn) {
|
|
626
700
|
return fn;
|
|
@@ -638,26 +712,10 @@ function arrayToObject(prop, unique) {
|
|
|
638
712
|
return transform;
|
|
639
713
|
}
|
|
640
714
|
|
|
641
|
-
// src/runtime/literals/box.ts
|
|
642
|
-
function box(value) {
|
|
643
|
-
const rtn = {
|
|
644
|
-
__kind: "box",
|
|
645
|
-
value,
|
|
646
|
-
unbox: () => value
|
|
647
|
-
};
|
|
648
|
-
return rtn;
|
|
649
|
-
}
|
|
650
|
-
function isBox(thing) {
|
|
651
|
-
return typeof thing === "object" && "__kind" in thing && thing.__kind === "box";
|
|
652
|
-
}
|
|
653
|
-
function unbox(thing) {
|
|
654
|
-
return isBox(thing) ? thing.unbox() : thing;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
715
|
// src/runtime/literals/defineType.ts
|
|
658
716
|
function defineType(literal2 = {}) {
|
|
659
|
-
return (
|
|
660
|
-
return literal2 ? { ...
|
|
717
|
+
return (wide2 = {}) => {
|
|
718
|
+
return literal2 ? { ...wide2, ...literal2 } : wide2;
|
|
661
719
|
};
|
|
662
720
|
}
|
|
663
721
|
|
|
@@ -681,16 +739,20 @@ function literal(obj) {
|
|
|
681
739
|
return obj;
|
|
682
740
|
}
|
|
683
741
|
|
|
684
|
-
// src/runtime/literals/
|
|
685
|
-
function
|
|
742
|
+
// src/runtime/literals/stripTrailing.ts
|
|
743
|
+
function stripTrailing(content, strip) {
|
|
686
744
|
const re = new RegExp(`(.*)${strip}$`);
|
|
687
745
|
return content.endsWith(strip) ? content.replace(re, "$1") : content;
|
|
688
746
|
}
|
|
689
747
|
|
|
690
|
-
// src/runtime/literals/
|
|
691
|
-
function
|
|
692
|
-
|
|
693
|
-
|
|
748
|
+
// src/runtime/literals/ensureTrailing.ts
|
|
749
|
+
function ensureTrailing(content, ensure) {
|
|
750
|
+
return content.endsWith(ensure) ? content : `${content}${ensure}`;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// src/runtime/literals/ensureLeading.ts
|
|
754
|
+
function ensureLeading(content, ensure) {
|
|
755
|
+
return content.startsWith(ensure) ? content : `${ensure}${content}`;
|
|
694
756
|
}
|
|
695
757
|
export {
|
|
696
758
|
Configurator,
|
|
@@ -706,13 +768,17 @@ export {
|
|
|
706
768
|
arrayToObject,
|
|
707
769
|
asArray,
|
|
708
770
|
box,
|
|
771
|
+
boxDictionaryValues,
|
|
709
772
|
condition,
|
|
773
|
+
createConverter,
|
|
710
774
|
createFnWithProps,
|
|
711
775
|
defineProperties,
|
|
712
776
|
defineType,
|
|
713
777
|
dictArr,
|
|
714
778
|
dictToKv,
|
|
715
779
|
dictionaryTransform,
|
|
780
|
+
ensureLeading,
|
|
781
|
+
ensureTrailing,
|
|
716
782
|
entries,
|
|
717
783
|
filter,
|
|
718
784
|
filterDictArray,
|
|
@@ -724,9 +790,12 @@ export {
|
|
|
724
790
|
ifArray,
|
|
725
791
|
ifArrayPartial,
|
|
726
792
|
ifBoolean,
|
|
793
|
+
ifDefined,
|
|
727
794
|
ifFalse,
|
|
728
795
|
ifNull,
|
|
729
796
|
ifNumber,
|
|
797
|
+
ifObject,
|
|
798
|
+
ifSameType,
|
|
730
799
|
ifString,
|
|
731
800
|
ifTrue,
|
|
732
801
|
ifUndefined,
|
|
@@ -760,10 +829,10 @@ export {
|
|
|
760
829
|
readonlyFnWithProps,
|
|
761
830
|
ruleSet,
|
|
762
831
|
strArrayToDict,
|
|
763
|
-
|
|
764
|
-
stripStarting,
|
|
832
|
+
stripTrailing,
|
|
765
833
|
type,
|
|
766
834
|
typeApi,
|
|
767
835
|
unbox,
|
|
836
|
+
wide,
|
|
768
837
|
withValue
|
|
769
838
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "inferred-types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.1",
|
|
4
4
|
"description": "Functions which provide useful type inference on TS projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ken Snyder<ken@ken.net>",
|
|
@@ -16,14 +16,15 @@
|
|
|
16
16
|
"autoindex": "npx dd autoindex",
|
|
17
17
|
"build": "run-s clean autoindex lint build:bundle",
|
|
18
18
|
"build:force": "run-s clean autoindex build:bundle",
|
|
19
|
-
"build:bundle": "npx tsup src/index.ts --dts --format=esm
|
|
19
|
+
"build:bundle": "npx tsup src/index.ts --dts --format=esm --clean",
|
|
20
20
|
"watch": "run-p watch:*",
|
|
21
21
|
"watch:autoindex": "npx dd autoindex --watch",
|
|
22
|
-
"watch:bundle": "npx tsup src/index.ts --dts --format=esm
|
|
22
|
+
"watch:bundle": "npx tsup src/index.ts --dts --format=esm --watch",
|
|
23
23
|
"clean": "rimraf dist/**/*",
|
|
24
24
|
"lint": "eslint src/**/*.ts --fix && tsc --noEmit ",
|
|
25
25
|
"lint:full": "eslint src/**/*.ts && eslint tests/**/*.ts && tsc --noEmit",
|
|
26
26
|
"test": "vitest",
|
|
27
|
+
"test:ui": "vitest --ui",
|
|
27
28
|
"test:ci": "vitest run",
|
|
28
29
|
"audit:fix": "pnpm audit --fix",
|
|
29
30
|
"release": "run-s lint:full release:latest test:ci audit:fix release:bump",
|
|
@@ -32,10 +33,10 @@
|
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"@type-challenges/utils": "~0.1.1",
|
|
35
|
-
"@types/node": "^16.18.
|
|
36
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
37
|
-
"@typescript-eslint/parser": "^5.
|
|
38
|
-
"@vitest/ui": "^0.25.
|
|
36
|
+
"@types/node": "^16.18.7",
|
|
37
|
+
"@typescript-eslint/eslint-plugin": "^5.46.0",
|
|
38
|
+
"@typescript-eslint/parser": "^5.46.0",
|
|
39
|
+
"@vitest/ui": "^0.25.6",
|
|
39
40
|
"bumpp": "^8.2.1",
|
|
40
41
|
"common-types": "^1.33.2",
|
|
41
42
|
"cross-env": "^7.0.3",
|
|
@@ -48,16 +49,16 @@
|
|
|
48
49
|
"eslint-plugin-promise": "^6.1.1",
|
|
49
50
|
"npm-run-all": "~4.1.5",
|
|
50
51
|
"pathe": "^1.0.0",
|
|
51
|
-
"prettier": "~2.8.
|
|
52
|
+
"prettier": "~2.8.1",
|
|
52
53
|
"rimraf": "^3.0.2",
|
|
53
54
|
"sharp": "^0.31.2",
|
|
54
55
|
"tsup": "^6.5.0",
|
|
55
|
-
"typescript": "^4.9.
|
|
56
|
+
"typescript": "^4.9.4",
|
|
56
57
|
"vite": "^3.2.5",
|
|
57
|
-
"vitest": "^0.25.
|
|
58
|
+
"vitest": "^0.25.6"
|
|
58
59
|
},
|
|
59
60
|
"dependencies": {
|
|
60
|
-
"brilliant-errors": "^0.
|
|
61
|
+
"brilliant-errors": "^0.7.1"
|
|
61
62
|
},
|
|
62
63
|
"pnpm": {
|
|
63
64
|
"overrides": {
|
|
@@ -109,7 +109,6 @@ export type LogicalCombinator = "AND" | "OR";
|
|
|
109
109
|
* const onlyPrivate = filter({ startsWith: "_" });
|
|
110
110
|
* const privateFiles = files.filter(onlyPrivate);
|
|
111
111
|
* ```
|
|
112
|
-
*
|
|
113
112
|
*/
|
|
114
113
|
export type FilterFn<T extends StringFilter | NumericFilter> = T extends StringFilter
|
|
115
114
|
? <V extends string | undefined>(input: V) => boolean
|
|
@@ -27,8 +27,12 @@ export type AsArray<T, W extends boolean = false> = T extends any[]
|
|
|
27
27
|
*/
|
|
28
28
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
29
29
|
export const asArray = <T extends Narrowable, W extends boolean = true>(thing: T, _widen?: W) => {
|
|
30
|
-
return (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
return (
|
|
31
|
+
isArray(thing)
|
|
32
|
+
? // proxy thing back as it's already an array
|
|
33
|
+
thing
|
|
34
|
+
: typeof thing === "undefined"
|
|
35
|
+
? ([] as T[])
|
|
36
|
+
: [thing]
|
|
37
|
+
) as AsArray<T, W>;
|
|
34
38
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Narrowable } from "src/types";
|
|
2
|
+
import { ConverterShape, AvailableConverters } from "src/types/lists/ConvertAndMap";
|
|
3
|
+
import { boxDictionaryValues } from "../literals/box";
|
|
4
|
+
import { wide } from "../literals/wide";
|
|
5
|
+
import { ifSameType } from "../type-checks";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* **createConverter**(mapper)
|
|
9
|
+
*
|
|
10
|
+
* A runtime utility which allows for the creation of a function which
|
|
11
|
+
* receives multiple wide types (string, number, boolean, object) and then transform it
|
|
12
|
+
* based on the "wide type" but while retaining the potentially narrow values passed in.
|
|
13
|
+
*
|
|
14
|
+
* The number of wide types which the converter will accept is based on how it configured
|
|
15
|
+
* as there are discrete functions which must be passed in for handling: strings, numbers,
|
|
16
|
+
* booleans, and "objects" (aka, Record<string,any>).
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* // handles strings and numbers
|
|
20
|
+
* const convert = createConverter({
|
|
21
|
+
* string: s => `the string was ${s}`,
|
|
22
|
+
* number: n => `the number was ${n}`,
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function createConverter<
|
|
27
|
+
S extends Narrowable = undefined,
|
|
28
|
+
N extends Narrowable = undefined,
|
|
29
|
+
B extends Narrowable = undefined,
|
|
30
|
+
O extends Narrowable = undefined
|
|
31
|
+
>(mapper: Partial<ConverterShape<S, N, B, O>>) {
|
|
32
|
+
type Mapper = Required<typeof mapper>;
|
|
33
|
+
const converter = boxDictionaryValues(mapper as Mapper);
|
|
34
|
+
|
|
35
|
+
return <T extends AvailableConverters<S, N, B, O>>(input: T) => {
|
|
36
|
+
const v = ifSameType(
|
|
37
|
+
input,
|
|
38
|
+
wide.string,
|
|
39
|
+
<T extends string>(i: T) => converter.string.unbox(i),
|
|
40
|
+
(i) =>
|
|
41
|
+
ifSameType(
|
|
42
|
+
i,
|
|
43
|
+
wide.number,
|
|
44
|
+
(i) => converter.number.unbox(i),
|
|
45
|
+
(i) =>
|
|
46
|
+
ifSameType(
|
|
47
|
+
i,
|
|
48
|
+
wide.boolean,
|
|
49
|
+
(i) => converter.boolean.unbox(i),
|
|
50
|
+
(i) =>
|
|
51
|
+
ifSameType(
|
|
52
|
+
i,
|
|
53
|
+
{} as Record<string, any>,
|
|
54
|
+
(i) => converter.object.unbox(i),
|
|
55
|
+
(i) => i as unknown
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
);
|
|
60
|
+
return v;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { AfterFirst, Narrowable } from "src/types";
|
|
1
|
+
import { AfterFirst, HasParameters, Narrowable } from "src/types";
|
|
2
2
|
import { First } from "src/types/lists/First";
|
|
3
|
+
import { keys } from "../keys";
|
|
4
|
+
import { AnyFunction } from "../type-checks";
|
|
3
5
|
|
|
4
6
|
export interface Box<T> {
|
|
5
7
|
__kind: "box";
|
|
@@ -7,22 +9,16 @@ export interface Box<T> {
|
|
|
7
9
|
/**
|
|
8
10
|
* Unbox the boxed value in the narrowest possible type.
|
|
9
11
|
*
|
|
10
|
-
* **
|
|
11
|
-
*
|
|
12
|
+
* **note:** if the boxed value is a function with parameters you
|
|
13
|
+
* can pass the parameters directly into the `b.unbox(params)` call.
|
|
12
14
|
*/
|
|
13
|
-
unbox
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
// * const b = box(fn);
|
|
21
|
-
// * // later
|
|
22
|
-
// * const b2 = b.narrow<"foo" | "bar">();
|
|
23
|
-
// * ```
|
|
24
|
-
// */
|
|
25
|
-
// narrow: NarrowBox<T>;
|
|
15
|
+
unbox: HasParameters<Box<T>["value"]> extends true
|
|
16
|
+
? Box<T>["value"] extends AnyFunction
|
|
17
|
+
? Box<T>["value"] extends (...args: infer A) => infer R
|
|
18
|
+
? <N extends A>(...args: N) => R
|
|
19
|
+
: () => ReturnType<T>
|
|
20
|
+
: () => T
|
|
21
|
+
: () => T;
|
|
26
22
|
}
|
|
27
23
|
|
|
28
24
|
export type BoxValue<T extends Box<any>> = T extends Box<infer V> ? V : never;
|
|
@@ -58,20 +54,45 @@ export function box<T extends Narrowable>(value: T): Box<T> {
|
|
|
58
54
|
const rtn: Box<T> = {
|
|
59
55
|
__kind: "box",
|
|
60
56
|
value,
|
|
61
|
-
unbox: () =>
|
|
57
|
+
unbox: (<P extends any[], R extends Narrowable>(...p: P): R => {
|
|
58
|
+
return typeof value === "function" ? value(...p) : value;
|
|
59
|
+
}) as Box<T>["unbox"],
|
|
62
60
|
};
|
|
63
61
|
|
|
64
62
|
return rtn;
|
|
65
63
|
}
|
|
66
64
|
|
|
67
|
-
export function isBox(thing:
|
|
65
|
+
export function isBox(thing: Narrowable): thing is Box<any> {
|
|
68
66
|
return (
|
|
69
67
|
typeof thing === "object" && "__kind" in (thing as object) && (thing as any).__kind === "box"
|
|
70
68
|
);
|
|
71
69
|
}
|
|
72
70
|
|
|
71
|
+
/**
|
|
72
|
+
* **boxDictionaryValues**(dict)
|
|
73
|
+
*
|
|
74
|
+
* Runtime utility which boxes each value in a dictionary
|
|
75
|
+
*/
|
|
76
|
+
export function boxDictionaryValues<T extends {}>(dict: T) {
|
|
77
|
+
return keys(dict).reduce(
|
|
78
|
+
(acc, key) => ({ ...acc, [key]: box(dict[key]) }),
|
|
79
|
+
{} as {
|
|
80
|
+
[K in keyof T]: Box<T[K]>;
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
73
85
|
export type Unbox<T> = T extends Box<infer U> ? U : T;
|
|
74
86
|
|
|
75
|
-
|
|
76
|
-
|
|
87
|
+
//TODO: it would make sense in the future to use `b.unbox` instead
|
|
88
|
+
// of `b.value` to keep consistent but currently value behaves more
|
|
89
|
+
// consistently and with somewhat stronger typing
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* **unbox**(maybeBox)
|
|
93
|
+
*
|
|
94
|
+
* Unboxes a value if it was a box; otherwise it leaves _as is_.
|
|
95
|
+
*/
|
|
96
|
+
export function unbox<T>(val: T): Unbox<T> {
|
|
97
|
+
return isBox(val) ? val.value : val;
|
|
77
98
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { EnsureLeading } from "src/types/alphabetic";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* **ensureLeading**(content, strip)
|
|
5
|
+
*
|
|
6
|
+
* Runtime utility which ensures that last part of a string -- `content` -- has the
|
|
7
|
+
* substring `ensure` at the end and adds it if not present.
|
|
8
|
+
*/
|
|
9
|
+
export function ensureLeading<T extends string, U extends string>(
|
|
10
|
+
content: T,
|
|
11
|
+
ensure: U
|
|
12
|
+
): EnsureLeading<T, U> {
|
|
13
|
+
return (
|
|
14
|
+
//
|
|
15
|
+
(content.startsWith(ensure) ? content : `${ensure}${content}`) as EnsureLeading<T, U>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { EnsureTrailing } from "../../types/alphabetic/EnsureTrailing";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* **ensureTrailing**(content, strip)
|
|
5
|
+
*
|
|
6
|
+
* Runtime utility which ensures that last part of a string -- `content` -- has the
|
|
7
|
+
* substring `ensure` at the end and adds it if not present.
|
|
8
|
+
*/
|
|
9
|
+
export function ensureTrailing<T extends string, U extends string>(
|
|
10
|
+
content: T,
|
|
11
|
+
ensure: U
|
|
12
|
+
): EnsureTrailing<T, U> {
|
|
13
|
+
return (
|
|
14
|
+
//
|
|
15
|
+
(content.endsWith(ensure) ? content : `${content}${ensure}`) as EnsureTrailing<T, U>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -10,9 +10,11 @@ export * from "./box";
|
|
|
10
10
|
export * from "./defineType";
|
|
11
11
|
export * from "./identity";
|
|
12
12
|
export * from "./literal";
|
|
13
|
-
export * from "./
|
|
14
|
-
export * from "./
|
|
13
|
+
export * from "./stripTrailing";
|
|
14
|
+
export * from "./ensureTrailing";
|
|
15
|
+
export * from "./ensureLeading";
|
|
15
16
|
export * from "./Suggest";
|
|
17
|
+
export * from "./wide";
|
|
16
18
|
|
|
17
19
|
// #endregion auto-indexed files
|
|
18
20
|
|
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
import { PathJoin } from "src/types/alphabetic/PathJoin";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ensureLeading } from "./ensureLeading";
|
|
3
|
+
import { ensureTrailing } from "./ensureTrailing";
|
|
4
|
+
import { stripLeading } from "./stripLeading";
|
|
5
|
+
import { stripTrailing } from "./stripTrailing";
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
|
-
* **pathJoin**`<T,U>()`
|
|
8
|
+
* **pathJoin**`<T,U>(begin, ...rest)`
|
|
7
9
|
*
|
|
8
10
|
* Run time utility which joins two strings together with
|
|
9
11
|
* the intent to have them be divided by a Posix `/` character
|
|
10
12
|
* appropriate for Unix file paths and URLs.
|
|
13
|
+
*
|
|
14
|
+
* **note:** to support more than two paths being joined there
|
|
15
|
+
* is now the ability to add a tuple of paths into the _rest_
|
|
16
|
+
* parameter
|
|
11
17
|
*/
|
|
12
|
-
export function pathJoin<T extends string, U extends string>(
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
export function pathJoin<T extends string, U extends readonly string[]>(
|
|
19
|
+
begin: T,
|
|
20
|
+
...rest: U
|
|
21
|
+
): PathJoin<T, U> {
|
|
22
|
+
const start = ensureTrailing(begin, "/");
|
|
23
|
+
const end = ensureLeading(rest.slice(-1)[0], "/");
|
|
24
|
+
const middle = rest
|
|
25
|
+
.slice(0, rest.length - 1)
|
|
26
|
+
.map((i) => stripLeading(stripTrailing(i, "/"), '"'));
|
|
27
|
+
const midString = stripTrailing(stripLeading(middle.join("/"), "/"), "/");
|
|
15
28
|
|
|
16
|
-
return
|
|
29
|
+
return (
|
|
30
|
+
rest.length > 1 ? `${start}${midString}${end}` : `${start}${stripLeading(end, "/")}`
|
|
31
|
+
) as PathJoin<T, U>;
|
|
17
32
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StripLeading } from "src/types/alphabetic/StripLeading";
|
|
2
2
|
|
|
3
|
-
export function
|
|
3
|
+
export function stripLeading<T extends string, U extends string>(
|
|
4
4
|
content: T,
|
|
5
5
|
strip: U
|
|
6
|
-
):
|
|
6
|
+
): StripLeading<T, U> {
|
|
7
7
|
const re = new RegExp(`^${strip}(.*)`);
|
|
8
8
|
return (
|
|
9
9
|
content.startsWith(strip)
|
|
@@ -11,5 +11,5 @@ export function stripStarting<T extends string, U extends string>(
|
|
|
11
11
|
content.replace(re, "$1")
|
|
12
12
|
: // does not
|
|
13
13
|
content
|
|
14
|
-
) as
|
|
14
|
+
) as StripLeading<T, U>;
|
|
15
15
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { StripTrailing } from "src/types/alphabetic/StripTrailing";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* **stripTrailing**(content, strip)
|
|
5
|
+
*
|
|
6
|
+
* Runtime utility which ensures that last part of a string has substring
|
|
7
|
+
* removed if it exists and that strong typing is preserved.
|
|
8
|
+
*/
|
|
9
|
+
export function stripTrailing<T extends string, U extends string>(
|
|
10
|
+
content: T,
|
|
11
|
+
strip: U
|
|
12
|
+
): StripTrailing<T, U> {
|
|
13
|
+
const re = new RegExp(`(.*)${strip}$`);
|
|
14
|
+
return (content.endsWith(strip) ? content.replace(re, "$1") : content) as StripTrailing<T, U>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Narrowable, Not, Widen } from "src/types";
|
|
2
|
+
|
|
3
|
+
export function ifSameType<
|
|
4
|
+
TValue extends Narrowable,
|
|
5
|
+
TType extends string | number | boolean | object,
|
|
6
|
+
IF extends Narrowable,
|
|
7
|
+
ELSE extends Narrowable
|
|
8
|
+
>(
|
|
9
|
+
value: TValue,
|
|
10
|
+
comparisonType: TType,
|
|
11
|
+
ifExtends: <T extends TType & TValue>(v: T) => IF,
|
|
12
|
+
doesNotExtend: (v: Not<TValue, TType>) => ELSE
|
|
13
|
+
) {
|
|
14
|
+
return (
|
|
15
|
+
// runtime values match
|
|
16
|
+
(
|
|
17
|
+
typeof value === typeof comparisonType ? ifExtends(value as any) : doesNotExtend(value as any)
|
|
18
|
+
) as Widen<TValue> extends Widen<TType> ? IF : ELSE
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { Narrowable } from "src/types";
|
|
1
2
|
import { IsBoolean } from "src/types/boolean-logic";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Runtime and type checks whether a variable is a boolean value.
|
|
5
6
|
*/
|
|
6
|
-
export function isBoolean<T extends
|
|
7
|
+
export function isBoolean<T extends Narrowable>(i: T): IsBoolean<T> {
|
|
7
8
|
return (typeof i === "boolean") as IsBoolean<T>;
|
|
8
9
|
}
|
|
9
10
|
|
|
@@ -5,11 +5,9 @@ export type IsFunction<T> = T extends FunctionType ? true : false;
|
|
|
5
5
|
export type HybridFunction<TProps extends {}> = (<TArgs extends any[]>(...args: TArgs) => any) &
|
|
6
6
|
TProps;
|
|
7
7
|
|
|
8
|
-
export type SimpleFunction =
|
|
8
|
+
export type SimpleFunction = (...args: any[]) => any;
|
|
9
9
|
|
|
10
|
-
export type AnyFunction<TProps extends {}
|
|
11
|
-
? HybridFunction<TProps>
|
|
12
|
-
: SimpleFunction;
|
|
10
|
+
export type AnyFunction<TProps extends {} = {}> = SimpleFunction | HybridFunction<TProps>;
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* Checks whether a passed in value is a function and ensures run-time and types
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FunctionType, Narrowable, Not } from "src/types";
|
|
2
|
-
import { IsObject } from "src/types/boolean-logic";
|
|
2
|
+
import { IfObject, IsObject } from "src/types/boolean-logic";
|
|
3
3
|
|
|
4
4
|
export type ObjectType = Not<Record<string, Narrowable>, FunctionType>;
|
|
5
5
|
|
|
@@ -9,6 +9,14 @@ export type ObjectType = Not<Record<string, Narrowable>, FunctionType>;
|
|
|
9
9
|
* arrays are excluded, as well as functions which also have properties hanging
|
|
10
10
|
* off of them.
|
|
11
11
|
*/
|
|
12
|
-
export function isObject<T extends
|
|
12
|
+
export function isObject<T extends Narrowable>(i: T) {
|
|
13
13
|
return (typeof i === "object" && i !== null && Array.isArray(i) === false) as IsObject<T>;
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
export function ifObject<T extends Narrowable, IF extends Narrowable, ELSE extends Narrowable>(
|
|
17
|
+
val: T,
|
|
18
|
+
ifObj: IF,
|
|
19
|
+
notObj: ELSE
|
|
20
|
+
): IfObject<T, IF, ELSE> {
|
|
21
|
+
return (isObject(val) ? ifObj : notObj) as IfObject<T, IF, ELSE>;
|
|
22
|
+
}
|