inferred-types 0.34.2 → 0.35.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/dist/index.d.ts CHANGED
@@ -1257,6 +1257,34 @@ type SpaceToDash<T extends string> = T extends `${infer Begin}${" "}${infer Rest
1257
1257
  * ``` */
1258
1258
  type SnakeCase<S extends string> = string extends S ? string : DashUppercase<Uncapitalize<SpaceToDash<Trim<LowerAllCaps<S>>>>> extends `${infer Begin}${"-"}${infer Rest}` ? SnakeCase<`${Lowercase<Begin>}_${Rest}`> : Lowercase<DashUppercase<Uncapitalize<Trim<LowerAllCaps<S>>>>>;
1259
1259
 
1260
+ /**
1261
+ * **StripStarting**`<T, U>`
1262
+ *
1263
+ * Will strip off of `T` the starting string defined by `U` when
1264
+ * both are string literals.
1265
+ * ```ts
1266
+ * type T = "Hello World";
1267
+ * type U = "Hello ";
1268
+ * // "World"
1269
+ * type R = StripStarting<T,U>;
1270
+ * ```
1271
+ */
1272
+ type StripStarting<T extends string, U extends string> = IfLiteral<T, string extends U ? never : T extends `${U}${infer After}` ? After : T, string>;
1273
+
1274
+ /**
1275
+ * **StripEnding**`<T, U>`
1276
+ *
1277
+ * Will strip off of `T` the ending defined by `U` when
1278
+ * both are string literals.
1279
+ * ```ts
1280
+ * type T = "Hello World";
1281
+ * type U = " World";
1282
+ * // "Hello"
1283
+ * type R = StripEnding<T,U>;
1284
+ * ```
1285
+ */
1286
+ type StripEnding<T extends string, U extends string> = IfLiteral<T, string extends U ? never : T extends `${infer Before}${U}` ? Before : T, string>;
1287
+
1260
1288
  type NetworkProtocol = "http" | "https" | "file" | "ws" | "wss";
1261
1289
  /**
1262
1290
  * A literal variant of _string_ which is meant to represent a domain name
@@ -2235,6 +2263,10 @@ declare function idTypeGuard<T extends {
2235
2263
  */
2236
2264
  declare function literal<N extends Narrowable, T extends Record<keyof T, N>>(obj: T): T;
2237
2265
 
2266
+ declare function stripEnding<T extends string, U extends string>(content: T, strip: U): StripEnding<T, U>;
2267
+
2268
+ declare function stripStarting<T extends string, U extends string>(content: T, strip: U): StripStarting<T, U>;
2269
+
2238
2270
  /**
2239
2271
  * **Suggest**
2240
2272
  *
@@ -2541,4 +2573,4 @@ interface IFluentConfigurator<C> {
2541
2573
  */
2542
2574
  declare function FluentConfigurator<I>(initial?: I): IFluentConfigurator<{}>;
2543
2575
 
2544
- export { AfterFirst, AllCaps, Alpha, AlphaNumeric, AnyFunction, Api, ApiFunction, ApiValue, AppendToDictionary, AppendToObject, ArrConcat, Array$1 as Array, ArrayConverter, AsArray, AsFinalizedConfig, AssertExtends, Box, BoxValue, BoxedFnParams, BoxedReturn, Bracket, Break, CamelCase, CapitalizeWords, Cardinality, Cardinality0, Cardinality1, CardinalityExplicit, CardinalityFilter0, CardinalityFilter1, CardinalityIn, CardinalityInput, CardinalityNode, CardinalityOut, CardinalityTuple, ClosingBracket, Condition, ConditionFilter, Configurator, ConfiguredMap, Constructor, Contains, DEFAULT_MANY_TO_ONE_MAPPING, DEFAULT_ONE_TO_MANY_MAPPING, DEFAULT_ONE_TO_ONE_MAPPING, DashToSnake, DashUppercase, Dasherize, DecomposeMapConfig, DefaultManyToOneMapping, DefaultOneToManyMapping, DefaultOneToOneMapping, DefinePropertiesApi, DictArrApi, DictArray, DictArrayFilterCallback, DictArrayKv, DictChangeValue, DictFromKv, DictKvTuple, DictPartialApplication, DictPrependWithFn, DictReturnValues, DomainName, DynamicRule, DynamicRuleSet, Email, EndsWith, EnumValues, Equal, ExpandRecursively, ExpectExtends, ExplicitFunction, Extends, FilterContains, FilterDefn, FilterEnds, FilterEquals, FilterFn, FilterGreaterThan, FilterIs, FilterLessThan, FilterNotEqual, FilterStarts, FilterTuple, FinalReturn, FinalizedMapConfig, First, FirstKey, FirstKeyValue, FirstOfEach, FirstOrUndefined, FirstString, FluentConfigurator, FluentFunction, FnShape, FromDictArray, FullyQualifiedUrl, FunctionType, GeneralDictionary, Get, HasUppercase, HybridFunction, IConfigurator, IFluentConfigurator, If, IfArray, IfBooleanLiteral, IfEndsWith, IfExtends, IfExtendsThen, IfFalse, IfLiteral, IfNumericLiteral, IfObject, IfOptionalLiteral, IfReadonlyArray, IfScalar, IfStartsWith, IfStringLiteral, IfTrue, IfUndefined, Include, Includes, IntersectingKeys, Ipv4, IsArray, IsBoolean, IsBooleanLiteral, IsCapitalized, IsFalse, IsFunction, IsLiteral, IsNull, IsNumber, IsNumericLiteral, IsObject, IsOptionalLiteral, IsReadonlyArray, IsScalar, IsStringLiteral, IsTrue, IsUndefined, KebabCase, KeyValue, KeyedRecord, Keys, KeysWithValue, KvFrom, KvTuple, LastInUnion, LeftWhitespace, Length, LogicFunction, LogicalCombinator, LowerAllCaps, LowerAlpha, ManyToMany, ManyToOne, ManyToZero, MapCard, MapCardinality, MapCardinalityFrom, MapCardinalityIllustrated, MapConfig, MapFn, MapFnInput, MapFnOutput, MapIR, MapInput, MapInputFrom, MapOR, MapOutput, MapOutputFrom, MapTo, Mapper, MapperApi, MaybeFalse, MaybeTrue, Mutable, MutableProps, NarrowBox, Narrowable, NarrowlyContains, NetworkProtocol, NonAlpha, NonNumericKeys, NonStringKeys, Not, NotEqual, NotFilter, Numeric, NumericFilter, NumericKeys, NumericString, ObjectType, OneToMany, OneToOne, OneToZero, Opaque, OpeningBracket, OptRequired, OptionalKeys, OptionalProps, Or, Parenthesis, PascalCase, Pluralize, PrivateKey, PrivateKeys, PublicKeys, Punctuation, PureFluentApi, RelativeUrl, Replace, RequireProps, RequiredKeys, RequiredProps, Retain, RightWhitespace, RuleDefinition, RuntimeProp, RuntimeType, SameKeys, SecondOfEach, SimpleFunction, SimplifyObject, SnakeCase, SpecialCharacters, Split, StartsWith, StringDelimiter, StringFilter, StringKeys, StringLength, Suggest, SuggestNumeric, ToFluent, Transformer, Trim, TrimLeft, TrimRight, TupleToUnion, Type, TypeApi, TypeDefault, TypeDefinition, TypeGuard, TypeOptions, Unbox, UndefinedArrayIsUnknown, UndefinedTreatment, UndefinedValue, UnionToIntersection, UnionToTuple, UniqueDictionary, UniqueForProp, Uniqueness, UnwrapNot, UpperAlpha, UrlBuilder, VariableName, Where, WhereNot, Whitespace, Widen, WithNumericKeys, WithStringKeys, WithValue, ZeroToMany, ZeroToOne, ZeroToZero, ZipCode, and, api, arrayToKeyLookup, arrayToObject, asArray, box, condition, createFnWithProps, defineProperties, defineType, dictArr, dictToKv, dictionaryTransform, entries, filter, filterDictArray, fnWithProps, groupBy, idLiteral, idTypeGuard, identity, ifArray, ifArrayPartial, ifBoolean, ifFalse, ifNull, ifNumber, ifString, ifTrue, ifUndefined, isArray, isBoolean, isBox, isFalse, isFunction, isNotFilter, isNull, isNumber, isNumericFilter, isObject, isString, isSymbol, isTrue, isType, isUndefined, keys, kindLiteral, kv, kvToDict, literal, mapTo, mapToDict, mapToFn, mapValues, nameLiteral, not, or, readonlyFnWithProps, ruleSet, strArrayToDict, type, typeApi, unbox, withValue };
2576
+ export { AfterFirst, AllCaps, Alpha, AlphaNumeric, AnyFunction, Api, ApiFunction, ApiValue, AppendToDictionary, AppendToObject, ArrConcat, Array$1 as Array, ArrayConverter, AsArray, AsFinalizedConfig, AssertExtends, Box, BoxValue, BoxedFnParams, BoxedReturn, Bracket, Break, CamelCase, CapitalizeWords, Cardinality, Cardinality0, Cardinality1, CardinalityExplicit, CardinalityFilter0, CardinalityFilter1, CardinalityIn, CardinalityInput, CardinalityNode, CardinalityOut, CardinalityTuple, ClosingBracket, Condition, ConditionFilter, Configurator, ConfiguredMap, Constructor, Contains, DEFAULT_MANY_TO_ONE_MAPPING, DEFAULT_ONE_TO_MANY_MAPPING, DEFAULT_ONE_TO_ONE_MAPPING, DashToSnake, DashUppercase, Dasherize, DecomposeMapConfig, DefaultManyToOneMapping, DefaultOneToManyMapping, DefaultOneToOneMapping, DefinePropertiesApi, DictArrApi, DictArray, DictArrayFilterCallback, DictArrayKv, DictChangeValue, DictFromKv, DictKvTuple, DictPartialApplication, DictPrependWithFn, DictReturnValues, DomainName, DynamicRule, DynamicRuleSet, Email, EndsWith, EnumValues, Equal, ExpandRecursively, ExpectExtends, ExplicitFunction, Extends, FilterContains, FilterDefn, FilterEnds, FilterEquals, FilterFn, FilterGreaterThan, FilterIs, FilterLessThan, FilterNotEqual, FilterStarts, FilterTuple, FinalReturn, FinalizedMapConfig, First, FirstKey, FirstKeyValue, FirstOfEach, FirstOrUndefined, FirstString, FluentConfigurator, FluentFunction, FnShape, FromDictArray, FullyQualifiedUrl, FunctionType, GeneralDictionary, Get, HasUppercase, HybridFunction, IConfigurator, IFluentConfigurator, If, IfArray, IfBooleanLiteral, IfEndsWith, IfExtends, IfExtendsThen, IfFalse, IfLiteral, IfNumericLiteral, IfObject, IfOptionalLiteral, IfReadonlyArray, IfScalar, IfStartsWith, IfStringLiteral, IfTrue, IfUndefined, Include, Includes, IntersectingKeys, Ipv4, IsArray, IsBoolean, IsBooleanLiteral, IsCapitalized, IsFalse, IsFunction, IsLiteral, IsNull, IsNumber, IsNumericLiteral, IsObject, IsOptionalLiteral, IsReadonlyArray, IsScalar, IsStringLiteral, IsTrue, IsUndefined, KebabCase, KeyValue, KeyedRecord, Keys, KeysWithValue, KvFrom, KvTuple, LastInUnion, LeftWhitespace, Length, LogicFunction, LogicalCombinator, LowerAllCaps, LowerAlpha, ManyToMany, ManyToOne, ManyToZero, MapCard, MapCardinality, MapCardinalityFrom, MapCardinalityIllustrated, MapConfig, MapFn, MapFnInput, MapFnOutput, MapIR, MapInput, MapInputFrom, MapOR, MapOutput, MapOutputFrom, MapTo, Mapper, MapperApi, MaybeFalse, MaybeTrue, Mutable, MutableProps, NarrowBox, Narrowable, NarrowlyContains, NetworkProtocol, NonAlpha, NonNumericKeys, NonStringKeys, Not, NotEqual, NotFilter, Numeric, NumericFilter, NumericKeys, NumericString, ObjectType, OneToMany, OneToOne, OneToZero, Opaque, OpeningBracket, OptRequired, OptionalKeys, OptionalProps, Or, Parenthesis, PascalCase, Pluralize, PrivateKey, PrivateKeys, PublicKeys, Punctuation, PureFluentApi, RelativeUrl, Replace, RequireProps, RequiredKeys, RequiredProps, Retain, RightWhitespace, RuleDefinition, RuntimeProp, RuntimeType, SameKeys, SecondOfEach, SimpleFunction, SimplifyObject, SnakeCase, SpecialCharacters, Split, StartsWith, StringDelimiter, StringFilter, StringKeys, StringLength, StripEnding, StripStarting, Suggest, SuggestNumeric, ToFluent, Transformer, Trim, TrimLeft, TrimRight, TupleToUnion, Type, TypeApi, TypeDefault, TypeDefinition, TypeGuard, TypeOptions, Unbox, UndefinedArrayIsUnknown, UndefinedTreatment, UndefinedValue, UnionToIntersection, UnionToTuple, UniqueDictionary, UniqueForProp, Uniqueness, UnwrapNot, UpperAlpha, UrlBuilder, VariableName, Where, WhereNot, Whitespace, Widen, WithNumericKeys, WithStringKeys, WithValue, ZeroToMany, ZeroToOne, ZeroToZero, ZipCode, and, api, arrayToKeyLookup, arrayToObject, asArray, box, condition, createFnWithProps, defineProperties, defineType, dictArr, dictToKv, dictionaryTransform, entries, filter, filterDictArray, fnWithProps, groupBy, idLiteral, idTypeGuard, identity, ifArray, ifArrayPartial, ifBoolean, ifFalse, ifNull, ifNumber, ifString, ifTrue, ifUndefined, isArray, isBoolean, isBox, isFalse, isFunction, isNotFilter, isNull, isNumber, isNumericFilter, isObject, isString, isSymbol, isTrue, isType, isUndefined, keys, kindLiteral, kv, kvToDict, literal, mapTo, mapToDict, mapToFn, mapValues, nameLiteral, not, or, readonlyFnWithProps, ruleSet, strArrayToDict, stripEnding, stripStarting, type, typeApi, unbox, withValue };
package/dist/index.js CHANGED
@@ -87,6 +87,8 @@ __export(src_exports, {
87
87
  readonlyFnWithProps: () => readonlyFnWithProps,
88
88
  ruleSet: () => ruleSet,
89
89
  strArrayToDict: () => strArrayToDict,
90
+ stripEnding: () => stripEnding,
91
+ stripStarting: () => stripStarting,
90
92
  type: () => type,
91
93
  typeApi: () => typeApi,
92
94
  unbox: () => unbox,
@@ -776,6 +778,18 @@ function idTypeGuard(_o) {
776
778
  function literal(obj) {
777
779
  return obj;
778
780
  }
781
+
782
+ // src/runtime/literals/stripEnding.ts
783
+ function stripEnding(content, strip) {
784
+ const re = new RegExp(`(.*)${strip}$`);
785
+ return content.endsWith(strip) ? content.replace(re, "$1") : content;
786
+ }
787
+
788
+ // src/runtime/literals/stripStarting.ts
789
+ function stripStarting(content, strip) {
790
+ const re = new RegExp(`^${strip}(.*)`);
791
+ return content.startsWith(strip) ? content.replace(re, "$1") : content;
792
+ }
779
793
  // Annotate the CommonJS export names for ESM import in node:
780
794
  0 && (module.exports = {
781
795
  Configurator,
@@ -845,6 +859,8 @@ function literal(obj) {
845
859
  readonlyFnWithProps,
846
860
  ruleSet,
847
861
  strArrayToDict,
862
+ stripEnding,
863
+ stripStarting,
848
864
  type,
849
865
  typeApi,
850
866
  unbox,
package/dist/index.mjs CHANGED
@@ -680,6 +680,18 @@ function idTypeGuard(_o) {
680
680
  function literal(obj) {
681
681
  return obj;
682
682
  }
683
+
684
+ // src/runtime/literals/stripEnding.ts
685
+ function stripEnding(content, strip) {
686
+ const re = new RegExp(`(.*)${strip}$`);
687
+ return content.endsWith(strip) ? content.replace(re, "$1") : content;
688
+ }
689
+
690
+ // src/runtime/literals/stripStarting.ts
691
+ function stripStarting(content, strip) {
692
+ const re = new RegExp(`^${strip}(.*)`);
693
+ return content.startsWith(strip) ? content.replace(re, "$1") : content;
694
+ }
683
695
  export {
684
696
  Configurator,
685
697
  DEFAULT_MANY_TO_ONE_MAPPING,
@@ -748,6 +760,8 @@ export {
748
760
  readonlyFnWithProps,
749
761
  ruleSet,
750
762
  strArrayToDict,
763
+ stripEnding,
764
+ stripStarting,
751
765
  type,
752
766
  typeApi,
753
767
  unbox,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inferred-types",
3
- "version": "0.34.2",
3
+ "version": "0.35.0",
4
4
  "description": "Functions which provide useful type inference on TS projects",
5
5
  "license": "MIT",
6
6
  "author": "Ken Snyder<ken@ken.net>",
@@ -32,16 +32,16 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@type-challenges/utils": "~0.1.1",
35
- "@types/node": "^16.18.3",
36
- "@typescript-eslint/eslint-plugin": "^5.45.0",
37
- "@typescript-eslint/parser": "^5.45.0",
38
- "@vitest/ui": "^0.25.3",
35
+ "@types/node": "^16.18.4",
36
+ "@typescript-eslint/eslint-plugin": "^5.45.1",
37
+ "@typescript-eslint/parser": "^5.45.1",
38
+ "@vitest/ui": "^0.25.4",
39
39
  "bumpp": "^8.2.1",
40
40
  "common-types": "^1.33.2",
41
41
  "cross-env": "^7.0.3",
42
42
  "dd": "^0.25.4",
43
43
  "dotenv": "^16.0.3",
44
- "eslint": "^8.28.0",
44
+ "eslint": "^8.29.0",
45
45
  "eslint-config-prettier": "^8.5.0",
46
46
  "eslint-plugin-import": "^2.26.0",
47
47
  "eslint-plugin-prettier": "^4.2.1",
@@ -53,8 +53,8 @@
53
53
  "sharp": "^0.31.2",
54
54
  "tsup": "^6.5.0",
55
55
  "typescript": "^4.9.3",
56
- "vite": "^3.2.4",
57
- "vitest": "^0.25.3"
56
+ "vite": "^3.2.5",
57
+ "vitest": "^0.25.4"
58
58
  },
59
59
  "dependencies": {
60
60
  "brilliant-errors": "^0.6.1"
@@ -10,6 +10,8 @@ export * from "./box";
10
10
  export * from "./defineType";
11
11
  export * from "./identity";
12
12
  export * from "./literal";
13
+ export * from "./stripEnding";
14
+ export * from "./stripStarting";
13
15
  export * from "./Suggest";
14
16
 
15
17
  // #endregion auto-indexed files
@@ -0,0 +1,17 @@
1
+ import { PathJoin } from "src/types/alphabetic/PathJoin";
2
+ import { stripStarting } from "./stripStarting";
3
+ import { stripEnding } from "./stripEnding";
4
+
5
+ /**
6
+ * **pathJoin**`<T,U>()`
7
+ *
8
+ * Run time utility which joins two strings together with
9
+ * the intent to have them be divided by a Posix `/` character
10
+ * appropriate for Unix file paths and URLs.
11
+ */
12
+ export function pathJoin<T extends string, U extends string>(begin: T, finish: U): PathJoin<T, U> {
13
+ const start = stripEnding(begin, "/");
14
+ const end = stripStarting(finish, "/");
15
+
16
+ return `${start}/${end}` as PathJoin<T, U>;
17
+ }
@@ -0,0 +1,9 @@
1
+ import { StripEnding } from "src/types/alphabetic/StripEnding";
2
+
3
+ export function stripEnding<T extends string, U extends string>(
4
+ content: T,
5
+ strip: U
6
+ ): StripEnding<T, U> {
7
+ const re = new RegExp(`(.*)${strip}$`);
8
+ return (content.endsWith(strip) ? content.replace(re, "$1") : content) as StripEnding<T, U>;
9
+ }
@@ -0,0 +1,15 @@
1
+ import { StripStarting } from "src/types/alphabetic/StripStarting";
2
+
3
+ export function stripStarting<T extends string, U extends string>(
4
+ content: T,
5
+ strip: U
6
+ ): StripStarting<T, U> {
7
+ const re = new RegExp(`^${strip}(.*)`);
8
+ return (
9
+ content.startsWith(strip)
10
+ ? // starts with
11
+ content.replace(re, "$1")
12
+ : // does not
13
+ content
14
+ ) as StripStarting<T, U>;
15
+ }
@@ -0,0 +1,40 @@
1
+ import { IfLiteral } from "../boolean-logic";
2
+ import { StripEnding } from "./StripEnding";
3
+ import { StripStarting } from "./StripStarting";
4
+ /**
5
+ * **PathJoin**`<T,U>`
6
+ *
7
+ * Type utility which joins two strings together with the
8
+ * goal of making it a valid file or URI path (based on the
9
+ * Posix standard for file paths).
10
+ *
11
+ * Primarily, this means that it ensures that both `T` and `U`
12
+ * are separated by a single `/` character. Of course if either
13
+ * `T` or `U` are _wide_ string types then the resulting type
14
+ * will be more limited.
15
+ *
16
+ * **Note:** that in the case that both `T` and `U` are wide,
17
+ * we opt to type the result as just a _string_ rather than
18
+ * `${string}/${string}` which might be more precise 99% of
19
+ * the time but where `T` is an empty string there actually
20
+ * is no guarantee of a `/` character. Similarly we must
21
+ * type the case where `U` is narrow but `T` is wide as
22
+ * being `${string}${U}` instead of `${string}/${U}`.
23
+ */
24
+ export type PathJoin<
25
+ // leading string
26
+ T extends string,
27
+ // trailing string
28
+ U extends string
29
+ > = IfLiteral<
30
+ T,
31
+ // Literal T guaranteed
32
+ IfLiteral<
33
+ // conditional
34
+ U,
35
+ `${StripEnding<T, "/">}/${StripStarting<U, "/">}`,
36
+ `${StripEnding<T, "/">}/${string}`
37
+ >,
38
+ // wide `T` encountered
39
+ IfLiteral<U, `${string}${U}`, string>
40
+ >;
@@ -0,0 +1,23 @@
1
+ import { IfLiteral } from "../boolean-logic/IsLiteral";
2
+
3
+ /**
4
+ * **StripEnding**`<T, U>`
5
+ *
6
+ * Will strip off of `T` the ending defined by `U` when
7
+ * both are string literals.
8
+ * ```ts
9
+ * type T = "Hello World";
10
+ * type U = " World";
11
+ * // "Hello"
12
+ * type R = StripEnding<T,U>;
13
+ * ```
14
+ */
15
+ export type StripEnding<T extends string, U extends string> = IfLiteral<
16
+ // can only operate on literal strings
17
+ T,
18
+ // this path represents successful strip opp
19
+ // but we must never accept `U` being wide
20
+ string extends U ? never : T extends `${infer Before}${U}` ? Before : T,
21
+ // here we must stay wide
22
+ string
23
+ >;
@@ -0,0 +1,23 @@
1
+ import { IfLiteral } from "../boolean-logic/IsLiteral";
2
+
3
+ /**
4
+ * **StripStarting**`<T, U>`
5
+ *
6
+ * Will strip off of `T` the starting string defined by `U` when
7
+ * both are string literals.
8
+ * ```ts
9
+ * type T = "Hello World";
10
+ * type U = "Hello ";
11
+ * // "World"
12
+ * type R = StripStarting<T,U>;
13
+ * ```
14
+ */
15
+ export type StripStarting<T extends string, U extends string> = IfLiteral<
16
+ // can only operate on literal strings
17
+ T,
18
+ // this path represents successful strip opp
19
+ // but we must never accept `U` being wide
20
+ string extends U ? never : T extends `${U}${infer After}` ? After : T,
21
+ // here we must stay wide
22
+ string
23
+ >;
@@ -18,6 +18,8 @@ export * from "./LowerAllCaps";
18
18
  export * from "./PascalCase";
19
19
  export * from "./Pluralize";
20
20
  export * from "./SnakeCase";
21
+ export * from "./StripStarting";
22
+ export * from "./StripEnding";
21
23
  export * from "./alpha-characters";
22
24
  export * from "./Url";
23
25
 
@@ -0,0 +1,87 @@
1
+ import { Equal, Expect } from "@type-challenges/utils";
2
+ import { pathJoin } from "src/runtime/literals/pathJoin";
3
+ import { PathJoin } from "src/types/alphabetic/PathJoin";
4
+ import { describe, expect, it } from "vitest";
5
+
6
+ // Note: type tests fail visible inspection but pass from Vitest
7
+ // standpoint so always be sure to run `tsc --noEmit` over your test files to
8
+ // gain validation that no new type vulnerabilities have cropped up.
9
+
10
+ describe("PathJoin<T,U>", () => {
11
+ it("only literals / happy path", () => {
12
+ type T1 = PathJoin<"foo", "bar">;
13
+ type T2 = PathJoin<"foo/", "bar">;
14
+ type T3 = PathJoin<"foo", "/bar">;
15
+ type T4 = PathJoin<"foo/", "/bar">;
16
+
17
+ type cases = [
18
+ // neither have divider
19
+ Expect<Equal<T1, "foo/bar">>,
20
+ // one has, one does not
21
+ Expect<Equal<T2, "foo/bar">>,
22
+ Expect<Equal<T3, "foo/bar">>,
23
+ // both have
24
+ Expect<Equal<T4, "foo/bar">>
25
+ ];
26
+ const cases: cases = [true, true, true, true];
27
+ });
28
+
29
+ it("wide types mixed in", () => {
30
+ type T1 = PathJoin<"foo", string>;
31
+ type T2 = PathJoin<"foo/", string>;
32
+ type T3 = PathJoin<string, "/bar">;
33
+ type T4 = PathJoin<string, "bar">;
34
+
35
+ type cases = [
36
+ Expect<Equal<T1, `foo/${string}`>>,
37
+ Expect<Equal<T2, `foo/${string}`>>,
38
+ Expect<Equal<T3, `${string}/bar`>>,
39
+ Expect<Equal<T4, `${string}bar`>>
40
+ ];
41
+ const cases: cases = [true, true, true, true];
42
+ });
43
+ });
44
+
45
+ describe("pathJoin() runtime util", () => {
46
+ it("happy path", () => {
47
+ const t1 = pathJoin("foo", "bar" as string);
48
+ const t2 = pathJoin("foo/", "bar" as string);
49
+ const t3 = pathJoin("foo" as string, "/bar");
50
+ const t4 = pathJoin("foo/" as string, "/bar");
51
+ const t5 = pathJoin("foo/" as string, "bar");
52
+
53
+ // runtime tests
54
+ [t1, t2, t3, t4].forEach((test) => expect(test).toBe("foo/bar"));
55
+
56
+ // type tests
57
+ type cases = [
58
+ Expect<Equal<typeof t1, `foo/${string}`>>,
59
+ Expect<Equal<typeof t2, `foo/${string}`>>,
60
+ Expect<Equal<typeof t3, `${string}/bar`>>,
61
+ Expect<Equal<typeof t4, `${string}/bar`>>,
62
+ Expect<Equal<typeof t5, `${string}bar`>>
63
+ ];
64
+ const cases: cases = [true, true, true, true, true];
65
+ });
66
+
67
+ it("with wide types", () => {
68
+ const t1 = pathJoin("foo", "bar");
69
+ const t2 = pathJoin("foo/", "bar");
70
+ const t3 = pathJoin("foo", "/bar");
71
+ const t4 = pathJoin("foo/", "/bar");
72
+ // runtime tests
73
+ [t1, t2, t3, t4].forEach((test) => expect(test, "runtime failure").toBe("foo/bar"));
74
+
75
+ // type tests
76
+ type cases = [
77
+ // neither have divider
78
+ Expect<Equal<typeof t1, "foo/bar">>,
79
+ // one has, one does not
80
+ Expect<Equal<typeof t2, "foo/bar">>,
81
+ Expect<Equal<typeof t3, "foo/bar">>,
82
+ // both have
83
+ Expect<Equal<typeof t4, "foo/bar">>
84
+ ];
85
+ const cases: cases = [true, true, true, true];
86
+ });
87
+ });