@@ -15,54 +15,73 @@ type StringInterpolationReturn<VariableValue extends any, OptionRaw> = Exclude<
1515
1616/**
1717 * Takes in a string containing variables and an object containing variables for interpolation. Accepts options.
18+ *
19+ * @example
20+ *
21+ * stringInterpolation("You have {{n}} messages", {
22+ n: 3,
23+ })
24+
25+ stringInterpolation("You have {{n}} messages from {{person}}", {
26+ n: <strong>3</strong>,
27+ person: "John",
28+ })
1829 */
1930export function stringInterpolation <
2031 VariableValue extends any ,
2132 OptionRaw extends boolean | undefined
2233> (
23- s : string ,
24- v : Record < PropertyKey , VariableValue > ,
34+ string : string ,
35+ variables : Record < PropertyKey , VariableValue > ,
2536 {
26- pattern : p = new RegExp ( / \{ { ( [ ^ { ] + ) } } / g) ,
27- sanity : S = true ,
28- raw : r = false ,
37+ pattern = new RegExp ( / \{ { ( [ ^ { ] + ) } } / g) ,
38+ sanity = true ,
39+ raw : rawOutput = false ,
2940 } : StringInterpolationOptions < OptionRaw > = { }
3041) : StringInterpolationReturn < VariableValue , OptionRaw > {
31- if ( ! s && S ) throw "Empty string"
42+ if ( ! string && sanity ) throw "Empty string"
3243
3344 // Find all variables within string
34- const sV = [ ...s . matchAll ( p ) ]
45+ const stringVariables = [ ...string . matchAll ( pattern ) ]
3546
3647 // No variables => no need to interpolate
37- if ( ! sV [ 0 ] ) return s as StringInterpolationReturn < VariableValue , OptionRaw >
48+ if ( ! stringVariables [ 0 ] )
49+ return string as StringInterpolationReturn < VariableValue , OptionRaw >
3850
39- if ( S ) {
51+ if ( sanity ) {
4052 // Sanity check string variables <-> passed in variables count
41- const k = Object . keys ( v )
53+ const variableKeys = Object . keys ( variables )
4254 // Checks whether variables parsed from string exist in passed argument
43- if ( sV . length !== k . length ) throw "Variable count mismatch"
44- for ( const _v of sV ) {
45- const vIs = _v [ 1 ] // Variable in string
46- if ( vIs && ! k . includes ( vIs ) ) throw `Variable '${ vIs } ' not found`
55+ if ( stringVariables . length !== variableKeys . length )
56+ throw "Variable count mismatch"
57+ for ( const regExpMatchArray of stringVariables ) {
58+ const variable = regExpMatchArray [ 1 ]
59+ if ( variable && ! variableKeys . includes ( variable ) )
60+ throw `Variable '${ variable } ' not found`
4761 }
4862 }
4963
50- const raw = s
51- . split ( p )
64+ // Create raw interpolation result
65+ const rawInterpolation = string
66+ . split ( pattern )
5267 // Trim empty string from array end (Could propably be done with regex as well)
5368 . filter ( Boolean )
54- . map ( ( _v ) => {
55- return v [ _v ] ? v [ _v ] : _v
69+ // Match parsed variables with passed in variables
70+ . map ( ( splitItem ) => {
71+ return variables [ splitItem ] ? variables [ splitItem ] : splitItem
5672 } )
5773
5874 // Checks if raw interpolation can be joined or not.
5975 // i.e. avoid printing [object Object | Array | Function | ...] within returned string.
60- const j = ! raw . filter (
76+ const canJoin = ! rawInterpolation . filter (
6177 ( i ) => typeof i !== "string" && typeof i !== "number"
6278 ) [ 0 ]
6379
64- if ( j && ! r )
65- return raw . join ( "" ) as StringInterpolationReturn < VariableValue , OptionRaw >
80+ if ( canJoin && ! rawOutput )
81+ return rawInterpolation . join ( "" ) as StringInterpolationReturn <
82+ VariableValue ,
83+ OptionRaw
84+ >
6685
67- return raw as StringInterpolationReturn < VariableValue , OptionRaw >
86+ return rawInterpolation as StringInterpolationReturn < VariableValue , OptionRaw >
6887}
0 commit comments