@truto/replace-placeholders 1.0.4 → 1.0.6

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 CHANGED
@@ -101,6 +101,118 @@ You can also combine it with type casting
101
101
  console.log(replacePlaceholders('{{foo?:1:int}}', { foo: '1' })); // Outputs: 1
102
102
  ````
103
103
 
104
+ ### Object Merging with `$truto_merge`
105
+
106
+ The `$truto_merge` special key enables deep merging of objects from placeholder values into the parent object. This is useful for dynamically extending configuration objects or combining data from multiple sources.
107
+
108
+ **Important:** The `$truto_merge` feature requires the `:json` type modifier to properly resolve object values.
109
+
110
+ #### Basic Object Merge
111
+
112
+ Merge a single object into the parent:
113
+
114
+ ```javascript
115
+ const template = {
116
+ query: {
117
+ default_value: 'foo',
118
+ $truto_merge: '{{user_supplied_query:json}}'
119
+ }
120
+ };
121
+
122
+ const result = replacePlaceholders(template, {
123
+ user_supplied_query: { custom_value: 'bar' }
124
+ });
125
+ // Outputs: { query: { default_value: 'foo', custom_value: 'bar' } }
126
+ ```
127
+
128
+ #### Deep Merge
129
+
130
+ The merge is always deep, preserving nested properties:
131
+
132
+ ```javascript
133
+ const template = {
134
+ config: {
135
+ defaults: {
136
+ timeout: 1000,
137
+ retries: 3
138
+ },
139
+ $truto_merge: '{{user_config:json}}'
140
+ }
141
+ };
142
+
143
+ const result = replacePlaceholders(template, {
144
+ user_config: {
145
+ defaults: {
146
+ retries: 5 // Overrides only this nested property
147
+ },
148
+ custom: true
149
+ }
150
+ });
151
+ // Outputs: {
152
+ // config: {
153
+ // defaults: { timeout: 1000, retries: 5 },
154
+ // custom: true
155
+ // }
156
+ // }
157
+ ```
158
+
159
+ #### Multiple Sources
160
+
161
+ Merge multiple objects in sequence by providing an array. Later values override earlier ones:
162
+
163
+ ```javascript
164
+ const template = {
165
+ settings: {
166
+ core: { enabled: true },
167
+ $truto_merge: ['{{base_settings:json}}', '{{user_settings:json}}']
168
+ }
169
+ };
170
+
171
+ const result = replacePlaceholders(template, {
172
+ base_settings: {
173
+ core: { version: '1.0' },
174
+ features: { a: true }
175
+ },
176
+ user_settings: {
177
+ core: { enabled: false }, // Overrides base
178
+ features: { b: true }
179
+ }
180
+ });
181
+ // Outputs: {
182
+ // settings: {
183
+ // core: { enabled: false, version: '1.0' },
184
+ // features: { a: true, b: true }
185
+ // }
186
+ // }
187
+ ```
188
+
189
+ #### Fallback Values
190
+
191
+ Use the pipe operator `|` to specify fallback placeholders:
192
+
193
+ ```javascript
194
+ const template = {
195
+ query: {
196
+ default_value: 'foo',
197
+ $truto_merge: '{{user_query:json|default_query:json}}'
198
+ }
199
+ };
200
+
201
+ const result = replacePlaceholders(template, {
202
+ default_query: { custom_value: 'bar' }
203
+ });
204
+ // Uses default_query since user_query is undefined
205
+ // Outputs: { query: { default_value: 'foo', custom_value: 'bar' } }
206
+ ```
207
+
208
+ #### Behavior Notes
209
+
210
+ - The `$truto_merge` key is automatically removed from the output
211
+ - Undefined or non-object placeholders are skipped (no error thrown)
212
+ - Arrays in placeholders are not merged (only plain objects)
213
+ - Empty objects have no effect on the merge
214
+ - Works with nested `$truto_merge` keys for hierarchical merging
215
+
104
216
  ## License
105
217
 
106
218
  This project is licensed under the MIT License.
package/dist/main.cjs CHANGED
@@ -1,5 +1,6 @@
1
- var $g5Y9E$traverse = require("traverse");
1
+ var $g5Y9E$deepmerge = require("deepmerge");
2
2
  var $g5Y9E$lodashes = require("lodash-es");
3
+ var $g5Y9E$traverse = require("traverse");
3
4
  var $g5Y9E$wildwildpath = require("wild-wild-path");
4
5
 
5
6
  function $parcel$defineInteropFlag(a) {
@@ -19,6 +20,7 @@ $parcel$export(module.exports, "default", () => $80bd448eb6ea085b$export$2e2bcd8
19
20
 
20
21
 
21
22
 
23
+
22
24
  function $a169b0c20575e4d3$var$replace(str = "", obj = {}) {
23
25
  const regex = /{{([\w-./|:?\s]+)}}/gi;
24
26
  const typeSplitRegex = /:(?=[\w\s]+)/gm;
@@ -108,15 +110,38 @@ var $a169b0c20575e4d3$export$2e2bcd8739ae039 = $a169b0c20575e4d3$var$replace;
108
110
  function $72af1098ef591494$export$2e2bcd8739ae039(obj, context) {
109
111
  if ((0, $g5Y9E$lodashes.isString)(obj)) return (0, $a169b0c20575e4d3$export$2e2bcd8739ae039)(obj, context);
110
112
  if ((0, $g5Y9E$lodashes.isArray)(obj)) return obj.map((item)=>$72af1098ef591494$export$2e2bcd8739ae039(item, context));
111
- if ((0, $g5Y9E$lodashes.isPlainObject)(obj)) return (0, ($parcel$interopDefault($g5Y9E$traverse)))(obj).map(function(value) {
112
- if (this.circular) this.remove();
113
- else if ((0, $g5Y9E$lodashes.isString)(value)) this.update((0, $a169b0c20575e4d3$export$2e2bcd8739ae039)(value, context));
114
- else if ((0, $g5Y9E$lodashes.isArrayBuffer)(value) || value instanceof Blob) {
115
- const val = (0, $g5Y9E$lodashes.get)(obj, this.path);
116
- this.update(val);
117
- this.block();
118
- }
119
- });
113
+ if ((0, $g5Y9E$lodashes.isPlainObject)(obj)) {
114
+ // First pass: replace all string placeholders and track if $truto_merge exists
115
+ let hasMergeKey = false;
116
+ const replaced = (0, ($parcel$interopDefault($g5Y9E$traverse)))(obj).map(function(value) {
117
+ if (this.circular) this.remove();
118
+ else if ((0, $g5Y9E$lodashes.isPlainObject)(value) && "$truto_merge" in value) hasMergeKey = true;
119
+ else if ((0, $g5Y9E$lodashes.isString)(value)) this.update((0, $a169b0c20575e4d3$export$2e2bcd8739ae039)(value, context));
120
+ else if ((0, $g5Y9E$lodashes.isArrayBuffer)(value) || value instanceof Blob) {
121
+ const val = (0, $g5Y9E$lodashes.get)(obj, this.path);
122
+ this.update(val);
123
+ this.block();
124
+ }
125
+ });
126
+ // Second pass: handle $truto_merge (only if needed)
127
+ if (!hasMergeKey) return replaced;
128
+ return (0, ($parcel$interopDefault($g5Y9E$traverse)))(replaced).map(function(value) {
129
+ if (this.circular) this.remove();
130
+ else if ((0, $g5Y9E$lodashes.isPlainObject)(value) && "$truto_merge" in value) {
131
+ const mergeValue = value["$truto_merge"];
132
+ const mergeValues = (0, $g5Y9E$lodashes.isArray)(mergeValue) ? mergeValue : [
133
+ mergeValue
134
+ ];
135
+ // Start with the base object (without $truto_merge key)
136
+ let result = {};
137
+ for(const key in value)if (key !== "$truto_merge") result[key] = value[key];
138
+ // Merge each resolved value (already resolved in first pass)
139
+ for (const resolvedValue of mergeValues)// Only merge if it's a plain object
140
+ if ((0, $g5Y9E$lodashes.isPlainObject)(resolvedValue)) result = (0, ($parcel$interopDefault($g5Y9E$deepmerge)))(result, resolvedValue);
141
+ this.update(result);
142
+ }
143
+ });
144
+ }
120
145
  throw new Error("Invalid type");
121
146
  }
122
147
 
package/dist/main.cjs.map CHANGED
@@ -1 +1 @@
1
- {"mappings":"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","sources":["index.ts","replacePlaceholders.ts","replace.ts"],"sourcesContent":["import replacePlaceholders from './replacePlaceholders';\nexport default replacePlaceholders;\n","import traverse from 'traverse'\nimport { isString, isArray, isPlainObject, isArrayBuffer, get } from 'lodash-es'\nimport replace from './replace'\nexport default function replacePlaceholders<T>(\n obj: T extends string | string[] | Record<string, unknown> ? T : never,\n context: Record<string, unknown>\n): T {\n if (isString(obj)) {\n return replace(obj, context) as T\n }\n\n if (isArray(obj)) {\n return obj.map(item => replacePlaceholders(item, context)) as T\n }\n\n if (isPlainObject(obj)) {\n return traverse(obj).map(function (value) {\n if (this.circular) {\n this.remove()\n } else if (isString(value)) {\n this.update(replace(value, context))\n } else if (isArrayBuffer(value) || value instanceof Blob) {\n const val = get(obj, this.path)\n this.update(val)\n this.block()\n }\n })\n }\n\n throw new Error('Invalid type')\n}\n","import { get as getWild } from 'wild-wild-path'\nimport { isArray, isPlainObject, isString, toString, trim } from 'lodash-es'\n\nfunction replace(\n str = '',\n obj: object = {}\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n const regex = /{{([\\w-./|:?\\s]+)}}/gi\n const typeSplitRegex = /:(?=[\\w\\s]+)/gm\n const matches = str.match(regex)\n let result: string | any = str\n\n if (matches) {\n matches.forEach(match => {\n const [matchStr, defaultStr] = match.slice(2, -2).split('?:')\n const parts = matchStr.split('|')\n const isNullAllowed = parts.some(part => part.includes(':null'))\n const ignoreEmptyString = parts.some(part =>\n part.includes(':ignore-empty-str')\n )\n const setUndefined = parts.some(part => part.includes(':undefined'))\n\n const isWholeString = match === str\n\n let value: any = undefined\n for (const part of parts) {\n const [path, ...typeParts] = part.split(typeSplitRegex)\n const type: string = (typeParts[0] || 'str').trim()\n\n const tempValue = getWild(obj, path.trim())\n if (tempValue === '' && ignoreEmptyString) {\n continue\n }\n if (tempValue !== undefined) {\n value = typeCast(tempValue, type, isWholeString)\n break\n }\n }\n\n if (value === undefined && defaultStr) {\n const [defaultValue, defaultType] = defaultStr.split(typeSplitRegex)\n const type = defaultType || 'str'\n value = typeCast(defaultValue, type, isWholeString)\n } else if (value === undefined) {\n if (setUndefined) {\n if (isWholeString) {\n value = undefined\n } else {\n value = ''\n }\n } else if (isNullAllowed) {\n value = null\n } else {\n value = match // Keep the placeholder intact\n }\n }\n\n if (match === str) {\n result = value\n } else {\n result = result.replace(match, value)\n }\n })\n }\n\n return result\n}\n\nfunction typeCast(\n value: unknown,\n type: string,\n isWholeString: boolean\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n if (value === undefined || value === null) return value\n\n let valueToCheck = value\n if (isString(value) && type !== 'str') {\n valueToCheck = trim(value)\n }\n\n if (\n valueToCheck instanceof Blob ||\n valueToCheck instanceof ReadableStream ||\n valueToCheck instanceof WritableStream ||\n valueToCheck instanceof TransformStream\n ) {\n return valueToCheck\n }\n\n let castValue: any\n switch (type) {\n case 'ignore-empty-str':\n return valueToCheck\n case 'undefined':\n return valueToCheck\n case 'null':\n if (valueToCheck === 'null' || valueToCheck === null) return null\n return isWholeString ? valueToCheck : 'null'\n case 'int':\n castValue = parseInt(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'num':\n castValue = parseFloat(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'str':\n return toString(value)\n case 'bool':\n if (valueToCheck === 'true' || valueToCheck === true) return true\n if (valueToCheck === 'false' || valueToCheck === false) return false\n return valueToCheck // Return the original value if it's not 'true' or 'false'\n case 'json':\n if (isWholeString) {\n if (isPlainObject(valueToCheck) || isArray(valueToCheck))\n return valueToCheck\n try {\n return JSON.parse(valueToCheck as string)\n } catch (err) {\n return valueToCheck\n }\n }\n return valueToCheck\n case 'any':\n return valueToCheck\n default:\n throw new Error(`Unsupported type: ${type}`)\n }\n}\n\nexport default replace\n"],"names":[],"version":3,"file":"main.cjs.map"}
1
+ {"mappings":";;;;;;;;;;;;;;;;;;ACAA;;;ACAA;;AAGA,SAAS,8BACP,MAAM,EAAE,EACR,MAAc,CAAC,CAAC,EAQN;IACV,MAAM,QAAQ;IACd,MAAM,iBAAiB;IACvB,MAAM,UAAU,IAAI,KAAK,CAAC;IAC1B,IAAI,SAAuB;IAE3B,IAAI,SACF,QAAQ,OAAO,CAAC,CAAA,QAAS;QACvB,MAAM,CAAC,UAAU,WAAW,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,KAAK,CAAC;QACxD,MAAM,QAAQ,SAAS,KAAK,CAAC;QAC7B,MAAM,gBAAgB,MAAM,IAAI,CAAC,CAAA,OAAQ,KAAK,QAAQ,CAAC;QACvD,MAAM,oBAAoB,MAAM,IAAI,CAAC,CAAA,OACnC,KAAK,QAAQ,CAAC;QAEhB,MAAM,eAAe,MAAM,IAAI,CAAC,CAAA,OAAQ,KAAK,QAAQ,CAAC;QAEtD,MAAM,gBAAgB,UAAU;QAEhC,IAAI,QAAa;QACjB,KAAK,MAAM,QAAQ,MAAO;YACxB,MAAM,CAAC,MAAM,GAAG,UAAU,GAAG,KAAK,KAAK,CAAC;YACxC,MAAM,OAAe,AAAC,CAAA,SAAS,CAAC,EAAE,IAAI,KAAI,EAAG,IAAI;YAEjD,MAAM,YAAY,CAAA,GAAA,uBAAO,AAAD,EAAE,KAAK,KAAK,IAAI;YACxC,IAAI,cAAc,MAAM,mBACtB,QAAQ;YAEV,IAAI,cAAc,WAAW;gBAC3B,QAAQ,+BAAS,WAAW,MAAM;gBAClC,KAAK;YACP,CAAC;QACH;QAEA,IAAI,UAAU,aAAa,YAAY;YACrC,MAAM,CAAC,cAAc,YAAY,GAAG,WAAW,KAAK,CAAC;YACrD,MAAM,OAAO,eAAe;YAC5B,QAAQ,+BAAS,cAAc,MAAM;QACvC,OAAO,IAAI,UAAU,WAAW;YAC9B,IAAI;gBACF,IAAI,eACF,QAAQ;qBAER,QAAQ;mBAEL,IAAI,eACT,QAAQ,IAAI;iBAEZ,QAAQ,MAAM,8BAA8B;;QAEhD,CAAC;QAED,IAAI,UAAU,KACZ,SAAS;aAET,SAAS,OAAO,OAAO,CAAC,OAAO;IAEnC;IAGF,OAAO;AACT;AAEA,SAAS,+BACP,KAAc,EACd,IAAY,EACZ,aAAsB,EAQZ;IACV,IAAI,UAAU,aAAa,UAAU,IAAI,EAAE,OAAO;IAElD,IAAI,eAAe;IACnB,IAAI,CAAA,GAAA,wBAAQ,AAAD,EAAE,UAAU,SAAS,OAC9B,eAAe,CAAA,GAAA,oBAAG,EAAE;IAGtB,IACE,wBAAwB,QACxB,wBAAwB,kBACxB,wBAAwB,kBACxB,wBAAwB,iBAExB,OAAO;IAGT,IAAI;IACJ,OAAQ;QACN,KAAK;YACH,OAAO;QACT,KAAK;YACH,OAAO;QACT,KAAK;YACH,IAAI,iBAAiB,UAAU,iBAAiB,IAAI,EAAE,OAAO,IAAI;YACjE,OAAO,gBAAgB,eAAe,MAAM;QAC9C,KAAK;YACH,YAAY,SAAS;YACrB,OAAO,MAAM,aAAa,eAAe,SAAS;QACpD,KAAK;YACH,YAAY,WAAW;YACvB,OAAO,MAAM,aAAa,eAAe,SAAS;QACpD,KAAK;YACH,OAAO,CAAA,GAAA,wBAAO,EAAE;QAClB,KAAK;YACH,IAAI,iBAAiB,UAAU,iBAAiB,IAAI,EAAE,OAAO,IAAI;YACjE,IAAI,iBAAiB,WAAW,iBAAiB,KAAK,EAAE,OAAO,KAAK;YACpE,OAAO,aAAa,0DAA0D;;QAChF,KAAK;YACH,IAAI,eAAe;gBACjB,IAAI,CAAA,GAAA,6BAAY,EAAE,iBAAiB,CAAA,GAAA,uBAAO,AAAD,EAAE,eACzC,OAAO;gBACT,IAAI;oBACF,OAAO,KAAK,KAAK,CAAC;gBACpB,EAAE,OAAO,KAAK;oBACZ,OAAO;gBACT;YACF,CAAC;YACD,OAAO;QACT,KAAK;YACH,OAAO;QACT;YACE,MAAM,IAAI,MAAM,CAAC,kBAAkB,EAAE,KAAK,CAAC,EAAC;IAChD;AACF;IAEA,2CAAe;;;AD1IA,kDACb,GAAsE,EACtE,OAAgC,EAC7B;IACH,IAAI,CAAA,GAAA,wBAAO,EAAE,MACX,OAAO,CAAA,GAAA,wCAAM,EAAE,KAAK;IAGtB,IAAI,CAAA,GAAA,uBAAO,AAAD,EAAE,MACV,OAAO,IAAI,GAAG,CAAC,CAAA,OAAQ,yCAAoB,MAAM;IAGnD,IAAI,CAAA,GAAA,6BAAa,AAAD,EAAE,MAAM;QACtB,+EAA+E;QAC/E,IAAI,cAAc,KAAK;QACvB,MAAM,WAAW,CAAA,GAAA,yCAAQ,AAAD,EAAE,KAAK,GAAG,CAAC,SAAU,KAAK,EAAE;YAClD,IAAI,IAAI,CAAC,QAAQ,EACf,IAAI,CAAC,MAAM;iBACN,IAAI,CAAA,GAAA,6BAAY,EAAE,UAAU,kBAAkB,OACnD,cAAc,IAAI;iBACb,IAAI,CAAA,GAAA,wBAAQ,AAAD,EAAE,QAClB,IAAI,CAAC,MAAM,CAAC,CAAA,GAAA,wCAAO,AAAD,EAAE,OAAO;iBACtB,IAAI,CAAA,GAAA,6BAAY,EAAE,UAAU,iBAAiB,MAAM;gBACxD,MAAM,MAAM,CAAA,GAAA,mBAAE,EAAE,KAAK,IAAI,CAAC,IAAI;gBAC9B,IAAI,CAAC,MAAM,CAAC;gBACZ,IAAI,CAAC,KAAK;YACZ,CAAC;QACH;QAEA,oDAAoD;QACpD,IAAI,CAAC,aACH,OAAO;QAGT,OAAO,CAAA,GAAA,yCAAO,EAAE,UAAU,GAAG,CAAC,SAAU,KAAK,EAAE;YAC7C,IAAI,IAAI,CAAC,QAAQ,EACf,IAAI,CAAC,MAAM;iBACN,IAAI,CAAA,GAAA,6BAAY,EAAE,UAAU,kBAAkB,OAAO;gBAC1D,MAAM,aAAa,KAAK,CAAC,eAAe;gBACxC,MAAM,cAAc,CAAA,GAAA,uBAAO,AAAD,EAAE,cAAc,aAAa;oBAAC;iBAAW;gBAEnE,wDAAwD;gBACxD,IAAI,SAAkC,CAAC;gBACvC,IAAK,MAAM,OAAO,MAChB,IAAI,QAAQ,gBACV,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI;gBAI5B,6DAA6D;gBAC7D,KAAK,MAAM,iBAAiB,YAC1B,oCAAoC;gBACpC,IAAI,CAAA,GAAA,6BAAY,EAAE,gBAChB,SAAS,CAAA,GAAA,0CAAQ,EAAE,QAAQ;gBAK/B,IAAI,CAAC,MAAM,CAAC;YACd,CAAC;QACH;IACF,CAAC;IAED,MAAM,IAAI,MAAM,gBAAe;AACjC;;ADpEA;IACA,2CAAe,CAAA,GAAA,wCAAkB","sources":["index.ts","replacePlaceholders.ts","replace.ts"],"sourcesContent":["import replacePlaceholders from './replacePlaceholders';\nexport default replacePlaceholders;\n","import deepmerge from 'deepmerge'\nimport { get, isArray, isArrayBuffer, isPlainObject, isString } from 'lodash-es'\nimport traverse from 'traverse'\nimport replace from './replace'\nexport default function replacePlaceholders<T>(\n obj: T extends string | string[] | Record<string, unknown> ? T : never,\n context: Record<string, unknown>\n): T {\n if (isString(obj)) {\n return replace(obj, context) as T\n }\n\n if (isArray(obj)) {\n return obj.map(item => replacePlaceholders(item, context)) as T\n }\n\n if (isPlainObject(obj)) {\n // First pass: replace all string placeholders and track if $truto_merge exists\n let hasMergeKey = false\n const replaced = traverse(obj).map(function (value) {\n if (this.circular) {\n this.remove()\n } else if (isPlainObject(value) && '$truto_merge' in value) {\n hasMergeKey = true\n } else if (isString(value)) {\n this.update(replace(value, context))\n } else if (isArrayBuffer(value) || value instanceof Blob) {\n const val = get(obj, this.path)\n this.update(val)\n this.block()\n }\n })\n\n // Second pass: handle $truto_merge (only if needed)\n if (!hasMergeKey) {\n return replaced as T\n }\n\n return traverse(replaced).map(function (value) {\n if (this.circular) {\n this.remove()\n } else if (isPlainObject(value) && '$truto_merge' in value) {\n const mergeValue = value['$truto_merge']\n const mergeValues = isArray(mergeValue) ? mergeValue : [mergeValue]\n\n // Start with the base object (without $truto_merge key)\n let result: Record<string, unknown> = {}\n for (const key in value) {\n if (key !== '$truto_merge') {\n result[key] = value[key]\n }\n }\n\n // Merge each resolved value (already resolved in first pass)\n for (const resolvedValue of mergeValues) {\n // Only merge if it's a plain object\n if (isPlainObject(resolvedValue)) {\n result = deepmerge(result, resolvedValue as Record<string, unknown>)\n }\n // Skip if it's undefined, null, a string (unresolved placeholder), or any non-object\n }\n\n this.update(result)\n }\n }) as T\n }\n\n throw new Error('Invalid type')\n}\n","import { isArray, isPlainObject, isString, toString, trim } from 'lodash-es'\nimport { get as getWild } from 'wild-wild-path'\n\nfunction replace(\n str = '',\n obj: object = {}\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n const regex = /{{([\\w-./|:?\\s]+)}}/gi\n const typeSplitRegex = /:(?=[\\w\\s]+)/gm\n const matches = str.match(regex)\n let result: string | any = str\n\n if (matches) {\n matches.forEach(match => {\n const [matchStr, defaultStr] = match.slice(2, -2).split('?:')\n const parts = matchStr.split('|')\n const isNullAllowed = parts.some(part => part.includes(':null'))\n const ignoreEmptyString = parts.some(part =>\n part.includes(':ignore-empty-str')\n )\n const setUndefined = parts.some(part => part.includes(':undefined'))\n\n const isWholeString = match === str\n\n let value: any = undefined\n for (const part of parts) {\n const [path, ...typeParts] = part.split(typeSplitRegex)\n const type: string = (typeParts[0] || 'str').trim()\n\n const tempValue = getWild(obj, path.trim())\n if (tempValue === '' && ignoreEmptyString) {\n continue\n }\n if (tempValue !== undefined) {\n value = typeCast(tempValue, type, isWholeString)\n break\n }\n }\n\n if (value === undefined && defaultStr) {\n const [defaultValue, defaultType] = defaultStr.split(typeSplitRegex)\n const type = defaultType || 'str'\n value = typeCast(defaultValue, type, isWholeString)\n } else if (value === undefined) {\n if (setUndefined) {\n if (isWholeString) {\n value = undefined\n } else {\n value = ''\n }\n } else if (isNullAllowed) {\n value = null\n } else {\n value = match // Keep the placeholder intact\n }\n }\n\n if (match === str) {\n result = value\n } else {\n result = result.replace(match, value)\n }\n })\n }\n\n return result\n}\n\nfunction typeCast(\n value: unknown,\n type: string,\n isWholeString: boolean\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n if (value === undefined || value === null) return value\n\n let valueToCheck = value\n if (isString(value) && type !== 'str') {\n valueToCheck = trim(value)\n }\n\n if (\n valueToCheck instanceof Blob ||\n valueToCheck instanceof ReadableStream ||\n valueToCheck instanceof WritableStream ||\n valueToCheck instanceof TransformStream\n ) {\n return valueToCheck\n }\n\n let castValue: any\n switch (type) {\n case 'ignore-empty-str':\n return valueToCheck\n case 'undefined':\n return valueToCheck\n case 'null':\n if (valueToCheck === 'null' || valueToCheck === null) return null\n return isWholeString ? valueToCheck : 'null'\n case 'int':\n castValue = parseInt(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'num':\n castValue = parseFloat(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'str':\n return toString(value)\n case 'bool':\n if (valueToCheck === 'true' || valueToCheck === true) return true\n if (valueToCheck === 'false' || valueToCheck === false) return false\n return valueToCheck // Return the original value if it's not 'true' or 'false'\n case 'json':\n if (isWholeString) {\n if (isPlainObject(valueToCheck) || isArray(valueToCheck))\n return valueToCheck\n try {\n return JSON.parse(valueToCheck as string)\n } catch (err) {\n return valueToCheck\n }\n }\n return valueToCheck\n case 'any':\n return valueToCheck\n default:\n throw new Error(`Unsupported type: ${type}`)\n }\n}\n\nexport default replace\n"],"names":[],"version":3,"file":"main.cjs.map"}
package/dist/module.js CHANGED
@@ -1,11 +1,13 @@
1
- import $hCgyA$traverse from "traverse";
1
+ import $hCgyA$deepmerge from "deepmerge";
2
2
  import {isString as $hCgyA$isString, isArray as $hCgyA$isArray, isPlainObject as $hCgyA$isPlainObject, isArrayBuffer as $hCgyA$isArrayBuffer, get as $hCgyA$get, trim as $hCgyA$trim, toString as $hCgyA$toString} from "lodash-es";
3
+ import $hCgyA$traverse from "traverse";
3
4
  import {get as $hCgyA$get1} from "wild-wild-path";
4
5
 
5
6
 
6
7
 
7
8
 
8
9
 
10
+
9
11
  function $67f2b908c91abfcc$var$replace(str = "", obj = {}) {
10
12
  const regex = /{{([\w-./|:?\s]+)}}/gi;
11
13
  const typeSplitRegex = /:(?=[\w\s]+)/gm;
@@ -95,15 +97,38 @@ var $67f2b908c91abfcc$export$2e2bcd8739ae039 = $67f2b908c91abfcc$var$replace;
95
97
  function $4e62acd4800cacd9$export$2e2bcd8739ae039(obj, context) {
96
98
  if ((0, $hCgyA$isString)(obj)) return (0, $67f2b908c91abfcc$export$2e2bcd8739ae039)(obj, context);
97
99
  if ((0, $hCgyA$isArray)(obj)) return obj.map((item)=>$4e62acd4800cacd9$export$2e2bcd8739ae039(item, context));
98
- if ((0, $hCgyA$isPlainObject)(obj)) return (0, $hCgyA$traverse)(obj).map(function(value) {
99
- if (this.circular) this.remove();
100
- else if ((0, $hCgyA$isString)(value)) this.update((0, $67f2b908c91abfcc$export$2e2bcd8739ae039)(value, context));
101
- else if ((0, $hCgyA$isArrayBuffer)(value) || value instanceof Blob) {
102
- const val = (0, $hCgyA$get)(obj, this.path);
103
- this.update(val);
104
- this.block();
105
- }
106
- });
100
+ if ((0, $hCgyA$isPlainObject)(obj)) {
101
+ // First pass: replace all string placeholders and track if $truto_merge exists
102
+ let hasMergeKey = false;
103
+ const replaced = (0, $hCgyA$traverse)(obj).map(function(value) {
104
+ if (this.circular) this.remove();
105
+ else if ((0, $hCgyA$isPlainObject)(value) && "$truto_merge" in value) hasMergeKey = true;
106
+ else if ((0, $hCgyA$isString)(value)) this.update((0, $67f2b908c91abfcc$export$2e2bcd8739ae039)(value, context));
107
+ else if ((0, $hCgyA$isArrayBuffer)(value) || value instanceof Blob) {
108
+ const val = (0, $hCgyA$get)(obj, this.path);
109
+ this.update(val);
110
+ this.block();
111
+ }
112
+ });
113
+ // Second pass: handle $truto_merge (only if needed)
114
+ if (!hasMergeKey) return replaced;
115
+ return (0, $hCgyA$traverse)(replaced).map(function(value) {
116
+ if (this.circular) this.remove();
117
+ else if ((0, $hCgyA$isPlainObject)(value) && "$truto_merge" in value) {
118
+ const mergeValue = value["$truto_merge"];
119
+ const mergeValues = (0, $hCgyA$isArray)(mergeValue) ? mergeValue : [
120
+ mergeValue
121
+ ];
122
+ // Start with the base object (without $truto_merge key)
123
+ let result = {};
124
+ for(const key in value)if (key !== "$truto_merge") result[key] = value[key];
125
+ // Merge each resolved value (already resolved in first pass)
126
+ for (const resolvedValue of mergeValues)// Only merge if it's a plain object
127
+ if ((0, $hCgyA$isPlainObject)(resolvedValue)) result = (0, $hCgyA$deepmerge)(result, resolvedValue);
128
+ this.update(result);
129
+ }
130
+ });
131
+ }
107
132
  throw new Error("Invalid type");
108
133
  }
109
134
 
@@ -1 +1 @@
1
- {"mappings":"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","sources":["index.ts","replacePlaceholders.ts","replace.ts"],"sourcesContent":["import replacePlaceholders from './replacePlaceholders';\nexport default replacePlaceholders;\n","import traverse from 'traverse'\nimport { isString, isArray, isPlainObject, isArrayBuffer, get } from 'lodash-es'\nimport replace from './replace'\nexport default function replacePlaceholders<T>(\n obj: T extends string | string[] | Record<string, unknown> ? T : never,\n context: Record<string, unknown>\n): T {\n if (isString(obj)) {\n return replace(obj, context) as T\n }\n\n if (isArray(obj)) {\n return obj.map(item => replacePlaceholders(item, context)) as T\n }\n\n if (isPlainObject(obj)) {\n return traverse(obj).map(function (value) {\n if (this.circular) {\n this.remove()\n } else if (isString(value)) {\n this.update(replace(value, context))\n } else if (isArrayBuffer(value) || value instanceof Blob) {\n const val = get(obj, this.path)\n this.update(val)\n this.block()\n }\n })\n }\n\n throw new Error('Invalid type')\n}\n","import { get as getWild } from 'wild-wild-path'\nimport { isArray, isPlainObject, isString, toString, trim } from 'lodash-es'\n\nfunction replace(\n str = '',\n obj: object = {}\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n const regex = /{{([\\w-./|:?\\s]+)}}/gi\n const typeSplitRegex = /:(?=[\\w\\s]+)/gm\n const matches = str.match(regex)\n let result: string | any = str\n\n if (matches) {\n matches.forEach(match => {\n const [matchStr, defaultStr] = match.slice(2, -2).split('?:')\n const parts = matchStr.split('|')\n const isNullAllowed = parts.some(part => part.includes(':null'))\n const ignoreEmptyString = parts.some(part =>\n part.includes(':ignore-empty-str')\n )\n const setUndefined = parts.some(part => part.includes(':undefined'))\n\n const isWholeString = match === str\n\n let value: any = undefined\n for (const part of parts) {\n const [path, ...typeParts] = part.split(typeSplitRegex)\n const type: string = (typeParts[0] || 'str').trim()\n\n const tempValue = getWild(obj, path.trim())\n if (tempValue === '' && ignoreEmptyString) {\n continue\n }\n if (tempValue !== undefined) {\n value = typeCast(tempValue, type, isWholeString)\n break\n }\n }\n\n if (value === undefined && defaultStr) {\n const [defaultValue, defaultType] = defaultStr.split(typeSplitRegex)\n const type = defaultType || 'str'\n value = typeCast(defaultValue, type, isWholeString)\n } else if (value === undefined) {\n if (setUndefined) {\n if (isWholeString) {\n value = undefined\n } else {\n value = ''\n }\n } else if (isNullAllowed) {\n value = null\n } else {\n value = match // Keep the placeholder intact\n }\n }\n\n if (match === str) {\n result = value\n } else {\n result = result.replace(match, value)\n }\n })\n }\n\n return result\n}\n\nfunction typeCast(\n value: unknown,\n type: string,\n isWholeString: boolean\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n if (value === undefined || value === null) return value\n\n let valueToCheck = value\n if (isString(value) && type !== 'str') {\n valueToCheck = trim(value)\n }\n\n if (\n valueToCheck instanceof Blob ||\n valueToCheck instanceof ReadableStream ||\n valueToCheck instanceof WritableStream ||\n valueToCheck instanceof TransformStream\n ) {\n return valueToCheck\n }\n\n let castValue: any\n switch (type) {\n case 'ignore-empty-str':\n return valueToCheck\n case 'undefined':\n return valueToCheck\n case 'null':\n if (valueToCheck === 'null' || valueToCheck === null) return null\n return isWholeString ? valueToCheck : 'null'\n case 'int':\n castValue = parseInt(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'num':\n castValue = parseFloat(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'str':\n return toString(value)\n case 'bool':\n if (valueToCheck === 'true' || valueToCheck === true) return true\n if (valueToCheck === 'false' || valueToCheck === false) return false\n return valueToCheck // Return the original value if it's not 'true' or 'false'\n case 'json':\n if (isWholeString) {\n if (isPlainObject(valueToCheck) || isArray(valueToCheck))\n return valueToCheck\n try {\n return JSON.parse(valueToCheck as string)\n } catch (err) {\n return valueToCheck\n }\n }\n return valueToCheck\n case 'any':\n return valueToCheck\n default:\n throw new Error(`Unsupported type: ${type}`)\n }\n}\n\nexport default replace\n"],"names":[],"version":3,"file":"module.js.map"}
1
+ {"mappings":"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","sources":["index.ts","replacePlaceholders.ts","replace.ts"],"sourcesContent":["import replacePlaceholders from './replacePlaceholders';\nexport default replacePlaceholders;\n","import deepmerge from 'deepmerge'\nimport { get, isArray, isArrayBuffer, isPlainObject, isString } from 'lodash-es'\nimport traverse from 'traverse'\nimport replace from './replace'\nexport default function replacePlaceholders<T>(\n obj: T extends string | string[] | Record<string, unknown> ? T : never,\n context: Record<string, unknown>\n): T {\n if (isString(obj)) {\n return replace(obj, context) as T\n }\n\n if (isArray(obj)) {\n return obj.map(item => replacePlaceholders(item, context)) as T\n }\n\n if (isPlainObject(obj)) {\n // First pass: replace all string placeholders and track if $truto_merge exists\n let hasMergeKey = false\n const replaced = traverse(obj).map(function (value) {\n if (this.circular) {\n this.remove()\n } else if (isPlainObject(value) && '$truto_merge' in value) {\n hasMergeKey = true\n } else if (isString(value)) {\n this.update(replace(value, context))\n } else if (isArrayBuffer(value) || value instanceof Blob) {\n const val = get(obj, this.path)\n this.update(val)\n this.block()\n }\n })\n\n // Second pass: handle $truto_merge (only if needed)\n if (!hasMergeKey) {\n return replaced as T\n }\n\n return traverse(replaced).map(function (value) {\n if (this.circular) {\n this.remove()\n } else if (isPlainObject(value) && '$truto_merge' in value) {\n const mergeValue = value['$truto_merge']\n const mergeValues = isArray(mergeValue) ? mergeValue : [mergeValue]\n\n // Start with the base object (without $truto_merge key)\n let result: Record<string, unknown> = {}\n for (const key in value) {\n if (key !== '$truto_merge') {\n result[key] = value[key]\n }\n }\n\n // Merge each resolved value (already resolved in first pass)\n for (const resolvedValue of mergeValues) {\n // Only merge if it's a plain object\n if (isPlainObject(resolvedValue)) {\n result = deepmerge(result, resolvedValue as Record<string, unknown>)\n }\n // Skip if it's undefined, null, a string (unresolved placeholder), or any non-object\n }\n\n this.update(result)\n }\n }) as T\n }\n\n throw new Error('Invalid type')\n}\n","import { isArray, isPlainObject, isString, toString, trim } from 'lodash-es'\nimport { get as getWild } from 'wild-wild-path'\n\nfunction replace(\n str = '',\n obj: object = {}\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n const regex = /{{([\\w-./|:?\\s]+)}}/gi\n const typeSplitRegex = /:(?=[\\w\\s]+)/gm\n const matches = str.match(regex)\n let result: string | any = str\n\n if (matches) {\n matches.forEach(match => {\n const [matchStr, defaultStr] = match.slice(2, -2).split('?:')\n const parts = matchStr.split('|')\n const isNullAllowed = parts.some(part => part.includes(':null'))\n const ignoreEmptyString = parts.some(part =>\n part.includes(':ignore-empty-str')\n )\n const setUndefined = parts.some(part => part.includes(':undefined'))\n\n const isWholeString = match === str\n\n let value: any = undefined\n for (const part of parts) {\n const [path, ...typeParts] = part.split(typeSplitRegex)\n const type: string = (typeParts[0] || 'str').trim()\n\n const tempValue = getWild(obj, path.trim())\n if (tempValue === '' && ignoreEmptyString) {\n continue\n }\n if (tempValue !== undefined) {\n value = typeCast(tempValue, type, isWholeString)\n break\n }\n }\n\n if (value === undefined && defaultStr) {\n const [defaultValue, defaultType] = defaultStr.split(typeSplitRegex)\n const type = defaultType || 'str'\n value = typeCast(defaultValue, type, isWholeString)\n } else if (value === undefined) {\n if (setUndefined) {\n if (isWholeString) {\n value = undefined\n } else {\n value = ''\n }\n } else if (isNullAllowed) {\n value = null\n } else {\n value = match // Keep the placeholder intact\n }\n }\n\n if (match === str) {\n result = value\n } else {\n result = result.replace(match, value)\n }\n })\n }\n\n return result\n}\n\nfunction typeCast(\n value: unknown,\n type: string,\n isWholeString: boolean\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n if (value === undefined || value === null) return value\n\n let valueToCheck = value\n if (isString(value) && type !== 'str') {\n valueToCheck = trim(value)\n }\n\n if (\n valueToCheck instanceof Blob ||\n valueToCheck instanceof ReadableStream ||\n valueToCheck instanceof WritableStream ||\n valueToCheck instanceof TransformStream\n ) {\n return valueToCheck\n }\n\n let castValue: any\n switch (type) {\n case 'ignore-empty-str':\n return valueToCheck\n case 'undefined':\n return valueToCheck\n case 'null':\n if (valueToCheck === 'null' || valueToCheck === null) return null\n return isWholeString ? valueToCheck : 'null'\n case 'int':\n castValue = parseInt(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'num':\n castValue = parseFloat(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'str':\n return toString(value)\n case 'bool':\n if (valueToCheck === 'true' || valueToCheck === true) return true\n if (valueToCheck === 'false' || valueToCheck === false) return false\n return valueToCheck // Return the original value if it's not 'true' or 'false'\n case 'json':\n if (isWholeString) {\n if (isPlainObject(valueToCheck) || isArray(valueToCheck))\n return valueToCheck\n try {\n return JSON.parse(valueToCheck as string)\n } catch (err) {\n return valueToCheck\n }\n }\n return valueToCheck\n case 'any':\n return valueToCheck\n default:\n throw new Error(`Unsupported type: ${type}`)\n }\n}\n\nexport default replace\n"],"names":[],"version":3,"file":"module.js.map"}
@@ -1 +1 @@
1
- {"mappings":"ACGA,qCAA4C,CAAC,EAC3C,GAAG,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,EACtE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,CAAC,CAwBH;AC7BD,eAAe,mBAAmB,CAAC","sources":["replace.ts","replacePlaceholders.ts","index.ts"],"sourcesContent":["import { get as getWild } from 'wild-wild-path'\nimport { isArray, isPlainObject, isString, toString, trim } from 'lodash-es'\n\nfunction replace(\n str = '',\n obj: object = {}\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n const regex = /{{([\\w-./|:?\\s]+)}}/gi\n const typeSplitRegex = /:(?=[\\w\\s]+)/gm\n const matches = str.match(regex)\n let result: string | any = str\n\n if (matches) {\n matches.forEach(match => {\n const [matchStr, defaultStr] = match.slice(2, -2).split('?:')\n const parts = matchStr.split('|')\n const isNullAllowed = parts.some(part => part.includes(':null'))\n const ignoreEmptyString = parts.some(part =>\n part.includes(':ignore-empty-str')\n )\n const setUndefined = parts.some(part => part.includes(':undefined'))\n\n const isWholeString = match === str\n\n let value: any = undefined\n for (const part of parts) {\n const [path, ...typeParts] = part.split(typeSplitRegex)\n const type: string = (typeParts[0] || 'str').trim()\n\n const tempValue = getWild(obj, path.trim())\n if (tempValue === '' && ignoreEmptyString) {\n continue\n }\n if (tempValue !== undefined) {\n value = typeCast(tempValue, type, isWholeString)\n break\n }\n }\n\n if (value === undefined && defaultStr) {\n const [defaultValue, defaultType] = defaultStr.split(typeSplitRegex)\n const type = defaultType || 'str'\n value = typeCast(defaultValue, type, isWholeString)\n } else if (value === undefined) {\n if (setUndefined) {\n if (isWholeString) {\n value = undefined\n } else {\n value = ''\n }\n } else if (isNullAllowed) {\n value = null\n } else {\n value = match // Keep the placeholder intact\n }\n }\n\n if (match === str) {\n result = value\n } else {\n result = result.replace(match, value)\n }\n })\n }\n\n return result\n}\n\nfunction typeCast(\n value: unknown,\n type: string,\n isWholeString: boolean\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n if (value === undefined || value === null) return value\n\n let valueToCheck = value\n if (isString(value) && type !== 'str') {\n valueToCheck = trim(value)\n }\n\n if (\n valueToCheck instanceof Blob ||\n valueToCheck instanceof ReadableStream ||\n valueToCheck instanceof WritableStream ||\n valueToCheck instanceof TransformStream\n ) {\n return valueToCheck\n }\n\n let castValue: any\n switch (type) {\n case 'ignore-empty-str':\n return valueToCheck\n case 'undefined':\n return valueToCheck\n case 'null':\n if (valueToCheck === 'null' || valueToCheck === null) return null\n return isWholeString ? valueToCheck : 'null'\n case 'int':\n castValue = parseInt(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'num':\n castValue = parseFloat(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'str':\n return toString(value)\n case 'bool':\n if (valueToCheck === 'true' || valueToCheck === true) return true\n if (valueToCheck === 'false' || valueToCheck === false) return false\n return valueToCheck // Return the original value if it's not 'true' or 'false'\n case 'json':\n if (isWholeString) {\n if (isPlainObject(valueToCheck) || isArray(valueToCheck))\n return valueToCheck\n try {\n return JSON.parse(valueToCheck as string)\n } catch (err) {\n return valueToCheck\n }\n }\n return valueToCheck\n case 'any':\n return valueToCheck\n default:\n throw new Error(`Unsupported type: ${type}`)\n }\n}\n\nexport default replace\n","import traverse from 'traverse'\nimport { isString, isArray, isPlainObject, isArrayBuffer, get } from 'lodash-es'\nimport replace from './replace'\nexport default function replacePlaceholders<T>(\n obj: T extends string | string[] | Record<string, unknown> ? T : never,\n context: Record<string, unknown>\n): T {\n if (isString(obj)) {\n return replace(obj, context) as T\n }\n\n if (isArray(obj)) {\n return obj.map(item => replacePlaceholders(item, context)) as T\n }\n\n if (isPlainObject(obj)) {\n return traverse(obj).map(function (value) {\n if (this.circular) {\n this.remove()\n } else if (isString(value)) {\n this.update(replace(value, context))\n } else if (isArrayBuffer(value) || value instanceof Blob) {\n const val = get(obj, this.path)\n this.update(val)\n this.block()\n }\n })\n }\n\n throw new Error('Invalid type')\n}\n","import replacePlaceholders from './replacePlaceholders';\nexport default replacePlaceholders;\n"],"names":[],"version":3,"file":"types.d.ts.map"}
1
+ {"mappings":"ACIA,qCAA4C,CAAC,EAC3C,GAAG,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,EACtE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,CAAC,CA6DH;ACnED,eAAe,mBAAmB,CAAC","sources":["replace.ts","replacePlaceholders.ts","index.ts"],"sourcesContent":["import { isArray, isPlainObject, isString, toString, trim } from 'lodash-es'\nimport { get as getWild } from 'wild-wild-path'\n\nfunction replace(\n str = '',\n obj: object = {}\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n const regex = /{{([\\w-./|:?\\s]+)}}/gi\n const typeSplitRegex = /:(?=[\\w\\s]+)/gm\n const matches = str.match(regex)\n let result: string | any = str\n\n if (matches) {\n matches.forEach(match => {\n const [matchStr, defaultStr] = match.slice(2, -2).split('?:')\n const parts = matchStr.split('|')\n const isNullAllowed = parts.some(part => part.includes(':null'))\n const ignoreEmptyString = parts.some(part =>\n part.includes(':ignore-empty-str')\n )\n const setUndefined = parts.some(part => part.includes(':undefined'))\n\n const isWholeString = match === str\n\n let value: any = undefined\n for (const part of parts) {\n const [path, ...typeParts] = part.split(typeSplitRegex)\n const type: string = (typeParts[0] || 'str').trim()\n\n const tempValue = getWild(obj, path.trim())\n if (tempValue === '' && ignoreEmptyString) {\n continue\n }\n if (tempValue !== undefined) {\n value = typeCast(tempValue, type, isWholeString)\n break\n }\n }\n\n if (value === undefined && defaultStr) {\n const [defaultValue, defaultType] = defaultStr.split(typeSplitRegex)\n const type = defaultType || 'str'\n value = typeCast(defaultValue, type, isWholeString)\n } else if (value === undefined) {\n if (setUndefined) {\n if (isWholeString) {\n value = undefined\n } else {\n value = ''\n }\n } else if (isNullAllowed) {\n value = null\n } else {\n value = match // Keep the placeholder intact\n }\n }\n\n if (match === str) {\n result = value\n } else {\n result = result.replace(match, value)\n }\n })\n }\n\n return result\n}\n\nfunction typeCast(\n value: unknown,\n type: string,\n isWholeString: boolean\n):\n | string\n | number\n | boolean\n | Record<string, unknown>\n | null\n | undefined\n | unknown {\n if (value === undefined || value === null) return value\n\n let valueToCheck = value\n if (isString(value) && type !== 'str') {\n valueToCheck = trim(value)\n }\n\n if (\n valueToCheck instanceof Blob ||\n valueToCheck instanceof ReadableStream ||\n valueToCheck instanceof WritableStream ||\n valueToCheck instanceof TransformStream\n ) {\n return valueToCheck\n }\n\n let castValue: any\n switch (type) {\n case 'ignore-empty-str':\n return valueToCheck\n case 'undefined':\n return valueToCheck\n case 'null':\n if (valueToCheck === 'null' || valueToCheck === null) return null\n return isWholeString ? valueToCheck : 'null'\n case 'int':\n castValue = parseInt(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'num':\n castValue = parseFloat(valueToCheck as string)\n return isNaN(castValue) ? valueToCheck : castValue\n case 'str':\n return toString(value)\n case 'bool':\n if (valueToCheck === 'true' || valueToCheck === true) return true\n if (valueToCheck === 'false' || valueToCheck === false) return false\n return valueToCheck // Return the original value if it's not 'true' or 'false'\n case 'json':\n if (isWholeString) {\n if (isPlainObject(valueToCheck) || isArray(valueToCheck))\n return valueToCheck\n try {\n return JSON.parse(valueToCheck as string)\n } catch (err) {\n return valueToCheck\n }\n }\n return valueToCheck\n case 'any':\n return valueToCheck\n default:\n throw new Error(`Unsupported type: ${type}`)\n }\n}\n\nexport default replace\n","import deepmerge from 'deepmerge'\nimport { get, isArray, isArrayBuffer, isPlainObject, isString } from 'lodash-es'\nimport traverse from 'traverse'\nimport replace from './replace'\nexport default function replacePlaceholders<T>(\n obj: T extends string | string[] | Record<string, unknown> ? T : never,\n context: Record<string, unknown>\n): T {\n if (isString(obj)) {\n return replace(obj, context) as T\n }\n\n if (isArray(obj)) {\n return obj.map(item => replacePlaceholders(item, context)) as T\n }\n\n if (isPlainObject(obj)) {\n // First pass: replace all string placeholders and track if $truto_merge exists\n let hasMergeKey = false\n const replaced = traverse(obj).map(function (value) {\n if (this.circular) {\n this.remove()\n } else if (isPlainObject(value) && '$truto_merge' in value) {\n hasMergeKey = true\n } else if (isString(value)) {\n this.update(replace(value, context))\n } else if (isArrayBuffer(value) || value instanceof Blob) {\n const val = get(obj, this.path)\n this.update(val)\n this.block()\n }\n })\n\n // Second pass: handle $truto_merge (only if needed)\n if (!hasMergeKey) {\n return replaced as T\n }\n\n return traverse(replaced).map(function (value) {\n if (this.circular) {\n this.remove()\n } else if (isPlainObject(value) && '$truto_merge' in value) {\n const mergeValue = value['$truto_merge']\n const mergeValues = isArray(mergeValue) ? mergeValue : [mergeValue]\n\n // Start with the base object (without $truto_merge key)\n let result: Record<string, unknown> = {}\n for (const key in value) {\n if (key !== '$truto_merge') {\n result[key] = value[key]\n }\n }\n\n // Merge each resolved value (already resolved in first pass)\n for (const resolvedValue of mergeValues) {\n // Only merge if it's a plain object\n if (isPlainObject(resolvedValue)) {\n result = deepmerge(result, resolvedValue as Record<string, unknown>)\n }\n // Skip if it's undefined, null, a string (unresolved placeholder), or any non-object\n }\n\n this.update(result)\n }\n }) as T\n }\n\n throw new Error('Invalid type')\n}\n","import replacePlaceholders from './replacePlaceholders';\nexport default replacePlaceholders;\n"],"names":[],"version":3,"file":"types.d.ts.map"}
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@truto/replace-placeholders",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Efficiently replace placeholders in strings, arrays, and objects using data from specified paths. Powered by 'wild-wild-path' and 'lodash' for robust functionality.",
5
5
  "repository": "https://github.com/trutohq/replace-placeholders.git",
6
6
  "dependencies": {
7
+ "deepmerge": "4.3.1",
7
8
  "lodash-es": "4.17.21",
8
9
  "traverse": "0.6.7",
9
10
  "wild-wild-path": "4.0.0"
@@ -38,6 +39,7 @@
38
39
  "devDependencies": {
39
40
  "@parcel/packager-ts": "2.8.3",
40
41
  "@parcel/transformer-typescript-types": "2.8.3",
42
+ "@types/deepmerge": "2.2.3",
41
43
  "@types/lodash-es": "4.17.7",
42
44
  "@types/traverse": "0.6.32",
43
45
  "@cloudflare/workers-types": "4.20250214.0",