diff --git a/scripts/index.ts b/scripts/index.ts index 0c72b65..6ebd4fb 100644 --- a/scripts/index.ts +++ b/scripts/index.ts @@ -9,6 +9,7 @@ export * from "./getTypedEntries"; export * from "./getTypedKeys"; export * from "./hasKey"; export * from "./incremente"; +export * from "./interpolation"; export * from "./isEqual"; export * from "./overrideInterface"; export * from "./partialKeys"; diff --git a/scripts/interpolation.test.ts b/scripts/interpolation.test.ts new file mode 100644 index 0000000..6e1320e --- /dev/null +++ b/scripts/interpolation.test.ts @@ -0,0 +1,96 @@ +import { type ExpectType } from "./expectType"; +import { createInterpolation, type CreateInterpolationContract } from "./interpolation"; + +describe("interpolation", () => { + it("simple replace", () => { + const interpolation = createInterpolation("query-{id}"); + + type check1 = ExpectType< + CreateInterpolationContract, + `query-${string}`, + "strict" + >; + + const result = interpolation({ + id: "aa", + }); + + type check = ExpectType; + + expect(result).toBe("query-aa"); + }); + + it("multi replace", () => { + const interpolation = createInterpolation("query-{id}-{test}"); + + type check1 = ExpectType< + CreateInterpolationContract, + `query-${string}-${string}`, + "strict" + >; + + const result = interpolation({ + id: "aa", + test: "vol", + }); + + type check = ExpectType; + + expect(result).toBe("query-aa-vol"); + }); + + it("no interpolation", () => { + const interpolation = createInterpolation("query"); + + type check1 = ExpectType< + CreateInterpolationContract, + "query", + "strict" + >; + + const result = interpolation(); + + type check = ExpectType; + + expect(result).toBe("query"); + }); + + it("complex interpolation", () => { + const interpolation = createInterpolation("{id1}{id2}{id3}{id4}"); + + type check1 = ExpectType< + CreateInterpolationContract, + string, + "strict" + >; + + const result = interpolation({ + id1: "1", + id2: "2", + id3: "3", + id4: "4", + }); + + type check = ExpectType; + + expect(result).toBe("1234"); + }); + + it("replace multi", () => { + const interpolation = createInterpolation("{id}{id}"); + + type check1 = ExpectType< + CreateInterpolationContract, + string, + "strict" + >; + + const result = interpolation({ + id: "1", + }); + + type check = ExpectType; + + expect(result).toBe("11"); + }); +}); diff --git a/scripts/interpolation.ts b/scripts/interpolation.ts new file mode 100644 index 0000000..5d01c2f --- /dev/null +++ b/scripts/interpolation.ts @@ -0,0 +1,44 @@ +import { type IsEqual } from "./isEqual"; + +export type ExtractInterpolationId< + GenericValue extends string, +> = GenericValue extends `${string}{${infer InferedInterpolationId}}${infer InferedEndValue}` + ? InferedInterpolationId | ExtractInterpolationId + : never; + +export type ReplaceInterpolationIdByValues< + GenericValue extends string, + GenericInterpolationValues extends Record, +> = GenericValue extends `${infer InferedStartValue}{${infer InferedInterpolationId}}${infer InferedEndValue}` + ? InferedInterpolationId extends keyof GenericInterpolationValues + ? `${InferedStartValue}${GenericInterpolationValues[InferedInterpolationId]}${ReplaceInterpolationIdByValues}` + : `${InferedStartValue}${string}${ReplaceInterpolationIdByValues}` + : GenericValue; + +export type CreateInterpolationContract< + GenericInterpolationFunction extends ((value: Record) => string), +> = ReplaceInterpolationIdByValues< + ReturnType, + {} +>; + +export function createInterpolation< + GenericValue extends string, + GenericInterpolationId extends ExtractInterpolationId, +>(value: GenericValue) { + return < + GenericInterpolationMapperValue extends string, + GenericInterpolationValues extends Record, + >( + ...[interpolationValues]: IsEqual extends true + ? [] + : [interpolationValues: GenericInterpolationValues] + ): ReplaceInterpolationIdByValues => ( + interpolationValues + ? value.replace( + /\{([^}]*)\}/g, + (match, interpolationId: GenericInterpolationId) => interpolationValues[interpolationId], + ) + : value + ) as never; +} diff --git a/test/integration/index.test.ts b/test/integration/index.test.ts index 6f925ef..7ca4c23 100644 --- a/test/integration/index.test.ts +++ b/test/integration/index.test.ts @@ -6,6 +6,7 @@ it("export all", () => { "InvalidBytesInStringError", "UnPartialError", "clone", + "createInterpolation", "entryUseMapper", "escapeRegExp", "getTypedEntries",