lifecycleion 0.0.6 → 0.0.7

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
@@ -1,4 +1,4 @@
1
- # Lifecycleion v0.0.6
1
+ # Lifecycleion v0.0.7
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/lifecycleion.svg)](https://badge.fury.io/js/lifecycleion)
4
4
 
@@ -61,6 +61,14 @@ function getPathParts(path) {
61
61
  return parts;
62
62
  }
63
63
 
64
+ // src/lib/internal/stringify-template-value.ts
65
+ function stringifyTemplateValue(value) {
66
+ if (typeof value === "string") {
67
+ return value;
68
+ }
69
+ return String(value);
70
+ }
71
+
64
72
  // src/lib/curly-brackets.ts
65
73
  var PLACEHOLDER_PATTERN = /(?:\\)?{{(\s*[^{}]+?\s*)(?:\\)?\s*}}/g;
66
74
  var CurlyBrackets = function(str = "", locals = {}, fallback = "(null)") {
@@ -105,7 +113,7 @@ CurlyBrackets.compileTemplate = function(str, fallback = "(null)") {
105
113
  if (replacement === void 0 || replacement === null) {
106
114
  return fallback;
107
115
  }
108
- return String(replacement);
116
+ return stringifyTemplateValue(replacement);
109
117
  });
110
118
  };
111
119
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/curly-brackets.ts","../../src/lib/internal/path-utils.ts"],"sourcesContent":["import { getPathParts } from './internal/path-utils';\n\nexport type TemplateFunction = (locals: Record<string, unknown>) => string;\n\ninterface CurlyBracketsFunction {\n (str?: string, locals?: Record<string, unknown>, fallback?: string): string;\n compileTemplate: (str: string, fallback?: string) => TemplateFunction;\n escape: (str: string) => string;\n}\n\nconst PLACEHOLDER_PATTERN = /(?:\\\\)?{{(\\s*[^{}]+?\\s*)(?:\\\\)?\\s*}}/g;\n\n/**\n * Processes a template string, replacing placeholders with corresponding values from a provided object.\n *\n * @param {string} str - The template string to process.\n * @param locals - An object containing key-value pairs for placeholder replacement.\n * @param fallback - A default string to use when a placeholder's corresponding value is not found.\n * @returns - The processed string with placeholders replaced by their corresponding values.\n */\n\nconst CurlyBrackets: CurlyBracketsFunction = function (\n str: string = '',\n locals: Record<string, unknown> = {},\n fallback: string = '(null)',\n): string {\n // Short-circuit if no brackets - no need to process\n if (!str.includes('{{')) {\n return str;\n }\n\n const compiled = CurlyBrackets.compileTemplate(str, fallback);\n\n return compiled(locals);\n} as CurlyBracketsFunction;\n\n/**\n * Compiles a template string into a reusable function, which can be called with different sets of locals.\n * This is more efficient when you have a template that you want to use with different sets of locals,\n * as it avoids the overhead of parsing the template string each time it is used.\n *\n * @param {string} str - The template string to compile.\n * @param {string} fallback - A default string to use when a placeholder's corresponding value is not found in locals.\n * @returns A function that takes an object of locals and returns a processed string.\n */\n\nCurlyBrackets.compileTemplate = function (\n str: string,\n fallback: string = '(null)',\n): TemplateFunction {\n return (locals: Record<string, unknown>): string => {\n return str.replace(PLACEHOLDER_PATTERN, (match, p1: string) => {\n if (typeof p1 !== 'string') {\n return match;\n }\n\n const hasLeadingEscape = match.startsWith('\\\\');\n const hasEndingEscape = match.endsWith('\\\\}}');\n const isFullyEscaped = hasLeadingEscape && hasEndingEscape;\n\n if (isFullyEscaped) {\n return match.slice(1, -3) + '}}';\n }\n\n if (hasLeadingEscape) {\n return match.slice(1);\n }\n\n if (hasEndingEscape) {\n return '{{' + p1.trim() + '}}';\n }\n\n const key = p1.trim();\n const parts = getPathParts(key);\n\n if (!parts || parts.length === 0) {\n return match;\n }\n\n // Use a more specific approach to ensure the type is consistent\n let replacement: unknown = locals;\n\n for (const part of parts) {\n if (\n replacement !== undefined &&\n replacement !== null &&\n typeof replacement === 'object' &&\n part in replacement\n ) {\n replacement = (replacement as Record<string, unknown>)[part];\n } else {\n replacement = undefined;\n break;\n }\n }\n\n if (replacement === undefined || replacement === null) {\n return fallback;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return String(replacement);\n });\n };\n};\n\n/**\n * Escapes placeholders in a string by prefixing them with a backslash, preventing them from being replaced when processed.\n *\n * @param {string} str - The string in which to escape placeholders.\n * @returns {string} - The string with placeholders escaped.\n */\n\nCurlyBrackets.escape = function (str: string): string {\n // Use a regex to replace instances of {{ and }} that are not already preceded by a backslash\n return str\n .replace(/(\\\\)?{{/g, (match, backslash) => (backslash ? match : '\\\\{{'))\n .replace(/(\\\\)?}}/g, (match, backslash) => (backslash ? match : '\\\\}}'));\n};\n\nexport { CurlyBrackets };\n","const PATH_SEGMENT_PATTERN =\n /(\\w+)|\\[(\\d+)\\]|\\[\"((?:[^\"\\\\]|\\\\.)*)\"\\]|\\['((?:[^'\\\\]|\\\\.)*)'\\]/y;\n\nfunction unescapeQuotedPathPart(value: string): string {\n return value.replace(/\\\\([\"'\\\\])/g, '$1');\n}\n\n/**\n * Parses a mixed object/array path such as \"user.roles[0].name\" into lookup parts.\n */\nexport function getPathParts(path: string): string[] | null {\n const parts: string[] = [];\n let index = 0;\n\n while (index < path.length) {\n if (path[index] === '.') {\n index++;\n\n if (index >= path.length) {\n return null;\n }\n }\n\n PATH_SEGMENT_PATTERN.lastIndex = index;\n const match = PATH_SEGMENT_PATTERN.exec(path);\n\n if (!match) {\n return null;\n }\n\n if (match[1] !== undefined) {\n parts.push(match[1]);\n } else if (match[2] !== undefined) {\n parts.push(match[2]);\n } else if (match[3] !== undefined) {\n parts.push(unescapeQuotedPathPart(match[3]));\n } else if (match[4] !== undefined) {\n parts.push(unescapeQuotedPathPart(match[4]));\n }\n\n index = PATH_SEGMENT_PATTERN.lastIndex;\n\n if (index < path.length && path[index] !== '.' && path[index] !== '[') {\n return null;\n }\n }\n\n return parts;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAM,uBACJ;AAEF,SAAS,uBAAuB,OAAuB;AACrD,SAAO,MAAM,QAAQ,eAAe,IAAI;AAC1C;AAKO,SAAS,aAAa,MAA+B;AAC1D,QAAM,QAAkB,CAAC;AACzB,MAAI,QAAQ;AAEZ,SAAO,QAAQ,KAAK,QAAQ;AAC1B,QAAI,KAAK,KAAK,MAAM,KAAK;AACvB;AAEA,UAAI,SAAS,KAAK,QAAQ;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,yBAAqB,YAAY;AACjC,UAAM,QAAQ,qBAAqB,KAAK,IAAI;AAE5C,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,CAAC,MAAM,QAAW;AAC1B,YAAM,KAAK,MAAM,CAAC,CAAC;AAAA,IACrB,WAAW,MAAM,CAAC,MAAM,QAAW;AACjC,YAAM,KAAK,MAAM,CAAC,CAAC;AAAA,IACrB,WAAW,MAAM,CAAC,MAAM,QAAW;AACjC,YAAM,KAAK,uBAAuB,MAAM,CAAC,CAAC,CAAC;AAAA,IAC7C,WAAW,MAAM,CAAC,MAAM,QAAW;AACjC,YAAM,KAAK,uBAAuB,MAAM,CAAC,CAAC,CAAC;AAAA,IAC7C;AAEA,YAAQ,qBAAqB;AAE7B,QAAI,QAAQ,KAAK,UAAU,KAAK,KAAK,MAAM,OAAO,KAAK,KAAK,MAAM,KAAK;AACrE,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;;;ADtCA,IAAM,sBAAsB;AAW5B,IAAM,gBAAuC,SAC3C,MAAc,IACd,SAAkC,CAAC,GACnC,WAAmB,UACX;AAER,MAAI,CAAC,IAAI,SAAS,IAAI,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,cAAc,gBAAgB,KAAK,QAAQ;AAE5D,SAAO,SAAS,MAAM;AACxB;AAYA,cAAc,kBAAkB,SAC9B,KACA,WAAmB,UACD;AAClB,SAAO,CAAC,WAA4C;AAClD,WAAO,IAAI,QAAQ,qBAAqB,CAAC,OAAO,OAAe;AAC7D,UAAI,OAAO,OAAO,UAAU;AAC1B,eAAO;AAAA,MACT;AAEA,YAAM,mBAAmB,MAAM,WAAW,IAAI;AAC9C,YAAM,kBAAkB,MAAM,SAAS,MAAM;AAC7C,YAAM,iBAAiB,oBAAoB;AAE3C,UAAI,gBAAgB;AAClB,eAAO,MAAM,MAAM,GAAG,EAAE,IAAI;AAAA,MAC9B;AAEA,UAAI,kBAAkB;AACpB,eAAO,MAAM,MAAM,CAAC;AAAA,MACtB;AAEA,UAAI,iBAAiB;AACnB,eAAO,OAAO,GAAG,KAAK,IAAI;AAAA,MAC5B;AAEA,YAAM,MAAM,GAAG,KAAK;AACpB,YAAM,QAAQ,aAAa,GAAG;AAE9B,UAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,eAAO;AAAA,MACT;AAGA,UAAI,cAAuB;AAE3B,iBAAW,QAAQ,OAAO;AACxB,YACE,gBAAgB,UAChB,gBAAgB,QAChB,OAAO,gBAAgB,YACvB,QAAQ,aACR;AACA,wBAAe,YAAwC,IAAI;AAAA,QAC7D,OAAO;AACL,wBAAc;AACd;AAAA,QACF;AAAA,MACF;AAEA,UAAI,gBAAgB,UAAa,gBAAgB,MAAM;AACrD,eAAO;AAAA,MACT;AAGA,aAAO,OAAO,WAAW;AAAA,IAC3B,CAAC;AAAA,EACH;AACF;AASA,cAAc,SAAS,SAAU,KAAqB;AAEpD,SAAO,IACJ,QAAQ,YAAY,CAAC,OAAO,cAAe,YAAY,QAAQ,MAAO,EACtE,QAAQ,YAAY,CAAC,OAAO,cAAe,YAAY,QAAQ,MAAO;AAC3E;","names":[]}
1
+ {"version":3,"sources":["../../src/lib/curly-brackets.ts","../../src/lib/internal/path-utils.ts","../../src/lib/internal/stringify-template-value.ts"],"sourcesContent":["import { getPathParts } from './internal/path-utils';\nimport { stringifyTemplateValue } from './internal/stringify-template-value';\n\nexport type TemplateFunction = (locals: Record<string, unknown>) => string;\n\ninterface CurlyBracketsFunction {\n (str?: string, locals?: Record<string, unknown>, fallback?: string): string;\n compileTemplate: (str: string, fallback?: string) => TemplateFunction;\n escape: (str: string) => string;\n}\n\nconst PLACEHOLDER_PATTERN = /(?:\\\\)?{{(\\s*[^{}]+?\\s*)(?:\\\\)?\\s*}}/g;\n\n/**\n * Processes a template string, replacing placeholders with corresponding values from a provided object.\n *\n * @param {string} str - The template string to process.\n * @param locals - An object containing key-value pairs for placeholder replacement.\n * @param fallback - A default string to use when a placeholder's corresponding value is not found.\n * @returns - The processed string with placeholders replaced by their corresponding values.\n */\n\nconst CurlyBrackets: CurlyBracketsFunction = function (\n str: string = '',\n locals: Record<string, unknown> = {},\n fallback: string = '(null)',\n): string {\n // Short-circuit if no brackets - no need to process\n if (!str.includes('{{')) {\n return str;\n }\n\n const compiled = CurlyBrackets.compileTemplate(str, fallback);\n\n return compiled(locals);\n} as CurlyBracketsFunction;\n\n/**\n * Compiles a template string into a reusable function, which can be called with different sets of locals.\n * This is more efficient when you have a template that you want to use with different sets of locals,\n * as it avoids the overhead of parsing the template string each time it is used.\n *\n * @param {string} str - The template string to compile.\n * @param {string} fallback - A default string to use when a placeholder's corresponding value is not found in locals.\n * @returns A function that takes an object of locals and returns a processed string.\n */\n\nCurlyBrackets.compileTemplate = function (\n str: string,\n fallback: string = '(null)',\n): TemplateFunction {\n return (locals: Record<string, unknown>): string => {\n return str.replace(PLACEHOLDER_PATTERN, (match, p1: string) => {\n if (typeof p1 !== 'string') {\n return match;\n }\n\n const hasLeadingEscape = match.startsWith('\\\\');\n const hasEndingEscape = match.endsWith('\\\\}}');\n const isFullyEscaped = hasLeadingEscape && hasEndingEscape;\n\n if (isFullyEscaped) {\n return match.slice(1, -3) + '}}';\n }\n\n if (hasLeadingEscape) {\n return match.slice(1);\n }\n\n if (hasEndingEscape) {\n return '{{' + p1.trim() + '}}';\n }\n\n const key = p1.trim();\n const parts = getPathParts(key);\n\n if (!parts || parts.length === 0) {\n return match;\n }\n\n // Use a more specific approach to ensure the type is consistent\n let replacement: unknown = locals;\n\n for (const part of parts) {\n if (\n replacement !== undefined &&\n replacement !== null &&\n typeof replacement === 'object' &&\n part in replacement\n ) {\n replacement = (replacement as Record<string, unknown>)[part];\n } else {\n replacement = undefined;\n break;\n }\n }\n\n if (replacement === undefined || replacement === null) {\n return fallback;\n }\n\n return stringifyTemplateValue(replacement);\n });\n };\n};\n\n/**\n * Escapes placeholders in a string by prefixing them with a backslash, preventing them from being replaced when processed.\n *\n * @param {string} str - The string in which to escape placeholders.\n * @returns {string} - The string with placeholders escaped.\n */\n\nCurlyBrackets.escape = function (str: string): string {\n // Use a regex to replace instances of {{ and }} that are not already preceded by a backslash\n return str\n .replace(/(\\\\)?{{/g, (match, backslash) => (backslash ? match : '\\\\{{'))\n .replace(/(\\\\)?}}/g, (match, backslash) => (backslash ? match : '\\\\}}'));\n};\n\nexport { CurlyBrackets };\n","const PATH_SEGMENT_PATTERN =\n /(\\w+)|\\[(\\d+)\\]|\\[\"((?:[^\"\\\\]|\\\\.)*)\"\\]|\\['((?:[^'\\\\]|\\\\.)*)'\\]/y;\n\nfunction unescapeQuotedPathPart(value: string): string {\n return value.replace(/\\\\([\"'\\\\])/g, '$1');\n}\n\n/**\n * Parses a mixed object/array path such as \"user.roles[0].name\" into lookup parts.\n */\nexport function getPathParts(path: string): string[] | null {\n const parts: string[] = [];\n let index = 0;\n\n while (index < path.length) {\n if (path[index] === '.') {\n index++;\n\n if (index >= path.length) {\n return null;\n }\n }\n\n PATH_SEGMENT_PATTERN.lastIndex = index;\n const match = PATH_SEGMENT_PATTERN.exec(path);\n\n if (!match) {\n return null;\n }\n\n if (match[1] !== undefined) {\n parts.push(match[1]);\n } else if (match[2] !== undefined) {\n parts.push(match[2]);\n } else if (match[3] !== undefined) {\n parts.push(unescapeQuotedPathPart(match[3]));\n } else if (match[4] !== undefined) {\n parts.push(unescapeQuotedPathPart(match[4]));\n }\n\n index = PATH_SEGMENT_PATTERN.lastIndex;\n\n if (index < path.length && path[index] !== '.' && path[index] !== '[') {\n return null;\n }\n }\n\n return parts;\n}\n","/**\n * Normalizes values to the same string representation used by template rendering.\n */\nexport function stringifyTemplateValue(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n\n return String(value);\n}\n"],"mappings":"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","names":[]}
@@ -35,6 +35,14 @@ function getPathParts(path) {
35
35
  return parts;
36
36
  }
37
37
 
38
+ // src/lib/internal/stringify-template-value.ts
39
+ function stringifyTemplateValue(value) {
40
+ if (typeof value === "string") {
41
+ return value;
42
+ }
43
+ return String(value);
44
+ }
45
+
38
46
  // src/lib/curly-brackets.ts
39
47
  var PLACEHOLDER_PATTERN = /(?:\\)?{{(\s*[^{}]+?\s*)(?:\\)?\s*}}/g;
40
48
  var CurlyBrackets = function(str = "", locals = {}, fallback = "(null)") {
@@ -79,7 +87,7 @@ CurlyBrackets.compileTemplate = function(str, fallback = "(null)") {
79
87
  if (replacement === void 0 || replacement === null) {
80
88
  return fallback;
81
89
  }
82
- return String(replacement);
90
+ return stringifyTemplateValue(replacement);
83
91
  });
84
92
  };
85
93
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/lib/internal/path-utils.ts","../../src/lib/curly-brackets.ts"],"sourcesContent":["const PATH_SEGMENT_PATTERN =\n /(\\w+)|\\[(\\d+)\\]|\\[\"((?:[^\"\\\\]|\\\\.)*)\"\\]|\\['((?:[^'\\\\]|\\\\.)*)'\\]/y;\n\nfunction unescapeQuotedPathPart(value: string): string {\n return value.replace(/\\\\([\"'\\\\])/g, '$1');\n}\n\n/**\n * Parses a mixed object/array path such as \"user.roles[0].name\" into lookup parts.\n */\nexport function getPathParts(path: string): string[] | null {\n const parts: string[] = [];\n let index = 0;\n\n while (index < path.length) {\n if (path[index] === '.') {\n index++;\n\n if (index >= path.length) {\n return null;\n }\n }\n\n PATH_SEGMENT_PATTERN.lastIndex = index;\n const match = PATH_SEGMENT_PATTERN.exec(path);\n\n if (!match) {\n return null;\n }\n\n if (match[1] !== undefined) {\n parts.push(match[1]);\n } else if (match[2] !== undefined) {\n parts.push(match[2]);\n } else if (match[3] !== undefined) {\n parts.push(unescapeQuotedPathPart(match[3]));\n } else if (match[4] !== undefined) {\n parts.push(unescapeQuotedPathPart(match[4]));\n }\n\n index = PATH_SEGMENT_PATTERN.lastIndex;\n\n if (index < path.length && path[index] !== '.' && path[index] !== '[') {\n return null;\n }\n }\n\n return parts;\n}\n","import { getPathParts } from './internal/path-utils';\n\nexport type TemplateFunction = (locals: Record<string, unknown>) => string;\n\ninterface CurlyBracketsFunction {\n (str?: string, locals?: Record<string, unknown>, fallback?: string): string;\n compileTemplate: (str: string, fallback?: string) => TemplateFunction;\n escape: (str: string) => string;\n}\n\nconst PLACEHOLDER_PATTERN = /(?:\\\\)?{{(\\s*[^{}]+?\\s*)(?:\\\\)?\\s*}}/g;\n\n/**\n * Processes a template string, replacing placeholders with corresponding values from a provided object.\n *\n * @param {string} str - The template string to process.\n * @param locals - An object containing key-value pairs for placeholder replacement.\n * @param fallback - A default string to use when a placeholder's corresponding value is not found.\n * @returns - The processed string with placeholders replaced by their corresponding values.\n */\n\nconst CurlyBrackets: CurlyBracketsFunction = function (\n str: string = '',\n locals: Record<string, unknown> = {},\n fallback: string = '(null)',\n): string {\n // Short-circuit if no brackets - no need to process\n if (!str.includes('{{')) {\n return str;\n }\n\n const compiled = CurlyBrackets.compileTemplate(str, fallback);\n\n return compiled(locals);\n} as CurlyBracketsFunction;\n\n/**\n * Compiles a template string into a reusable function, which can be called with different sets of locals.\n * This is more efficient when you have a template that you want to use with different sets of locals,\n * as it avoids the overhead of parsing the template string each time it is used.\n *\n * @param {string} str - The template string to compile.\n * @param {string} fallback - A default string to use when a placeholder's corresponding value is not found in locals.\n * @returns A function that takes an object of locals and returns a processed string.\n */\n\nCurlyBrackets.compileTemplate = function (\n str: string,\n fallback: string = '(null)',\n): TemplateFunction {\n return (locals: Record<string, unknown>): string => {\n return str.replace(PLACEHOLDER_PATTERN, (match, p1: string) => {\n if (typeof p1 !== 'string') {\n return match;\n }\n\n const hasLeadingEscape = match.startsWith('\\\\');\n const hasEndingEscape = match.endsWith('\\\\}}');\n const isFullyEscaped = hasLeadingEscape && hasEndingEscape;\n\n if (isFullyEscaped) {\n return match.slice(1, -3) + '}}';\n }\n\n if (hasLeadingEscape) {\n return match.slice(1);\n }\n\n if (hasEndingEscape) {\n return '{{' + p1.trim() + '}}';\n }\n\n const key = p1.trim();\n const parts = getPathParts(key);\n\n if (!parts || parts.length === 0) {\n return match;\n }\n\n // Use a more specific approach to ensure the type is consistent\n let replacement: unknown = locals;\n\n for (const part of parts) {\n if (\n replacement !== undefined &&\n replacement !== null &&\n typeof replacement === 'object' &&\n part in replacement\n ) {\n replacement = (replacement as Record<string, unknown>)[part];\n } else {\n replacement = undefined;\n break;\n }\n }\n\n if (replacement === undefined || replacement === null) {\n return fallback;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return String(replacement);\n });\n };\n};\n\n/**\n * Escapes placeholders in a string by prefixing them with a backslash, preventing them from being replaced when processed.\n *\n * @param {string} str - The string in which to escape placeholders.\n * @returns {string} - The string with placeholders escaped.\n */\n\nCurlyBrackets.escape = function (str: string): string {\n // Use a regex to replace instances of {{ and }} that are not already preceded by a backslash\n return str\n .replace(/(\\\\)?{{/g, (match, backslash) => (backslash ? match : '\\\\{{'))\n .replace(/(\\\\)?}}/g, (match, backslash) => (backslash ? match : '\\\\}}'));\n};\n\nexport { CurlyBrackets };\n"],"mappings":";AAAA,IAAM,uBACJ;AAEF,SAAS,uBAAuB,OAAuB;AACrD,SAAO,MAAM,QAAQ,eAAe,IAAI;AAC1C;AAKO,SAAS,aAAa,MAA+B;AAC1D,QAAM,QAAkB,CAAC;AACzB,MAAI,QAAQ;AAEZ,SAAO,QAAQ,KAAK,QAAQ;AAC1B,QAAI,KAAK,KAAK,MAAM,KAAK;AACvB;AAEA,UAAI,SAAS,KAAK,QAAQ;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,yBAAqB,YAAY;AACjC,UAAM,QAAQ,qBAAqB,KAAK,IAAI;AAE5C,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,CAAC,MAAM,QAAW;AAC1B,YAAM,KAAK,MAAM,CAAC,CAAC;AAAA,IACrB,WAAW,MAAM,CAAC,MAAM,QAAW;AACjC,YAAM,KAAK,MAAM,CAAC,CAAC;AAAA,IACrB,WAAW,MAAM,CAAC,MAAM,QAAW;AACjC,YAAM,KAAK,uBAAuB,MAAM,CAAC,CAAC,CAAC;AAAA,IAC7C,WAAW,MAAM,CAAC,MAAM,QAAW;AACjC,YAAM,KAAK,uBAAuB,MAAM,CAAC,CAAC,CAAC;AAAA,IAC7C;AAEA,YAAQ,qBAAqB;AAE7B,QAAI,QAAQ,KAAK,UAAU,KAAK,KAAK,MAAM,OAAO,KAAK,KAAK,MAAM,KAAK;AACrE,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;;;ACtCA,IAAM,sBAAsB;AAW5B,IAAM,gBAAuC,SAC3C,MAAc,IACd,SAAkC,CAAC,GACnC,WAAmB,UACX;AAER,MAAI,CAAC,IAAI,SAAS,IAAI,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,cAAc,gBAAgB,KAAK,QAAQ;AAE5D,SAAO,SAAS,MAAM;AACxB;AAYA,cAAc,kBAAkB,SAC9B,KACA,WAAmB,UACD;AAClB,SAAO,CAAC,WAA4C;AAClD,WAAO,IAAI,QAAQ,qBAAqB,CAAC,OAAO,OAAe;AAC7D,UAAI,OAAO,OAAO,UAAU;AAC1B,eAAO;AAAA,MACT;AAEA,YAAM,mBAAmB,MAAM,WAAW,IAAI;AAC9C,YAAM,kBAAkB,MAAM,SAAS,MAAM;AAC7C,YAAM,iBAAiB,oBAAoB;AAE3C,UAAI,gBAAgB;AAClB,eAAO,MAAM,MAAM,GAAG,EAAE,IAAI;AAAA,MAC9B;AAEA,UAAI,kBAAkB;AACpB,eAAO,MAAM,MAAM,CAAC;AAAA,MACtB;AAEA,UAAI,iBAAiB;AACnB,eAAO,OAAO,GAAG,KAAK,IAAI;AAAA,MAC5B;AAEA,YAAM,MAAM,GAAG,KAAK;AACpB,YAAM,QAAQ,aAAa,GAAG;AAE9B,UAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,eAAO;AAAA,MACT;AAGA,UAAI,cAAuB;AAE3B,iBAAW,QAAQ,OAAO;AACxB,YACE,gBAAgB,UAChB,gBAAgB,QAChB,OAAO,gBAAgB,YACvB,QAAQ,aACR;AACA,wBAAe,YAAwC,IAAI;AAAA,QAC7D,OAAO;AACL,wBAAc;AACd;AAAA,QACF;AAAA,MACF;AAEA,UAAI,gBAAgB,UAAa,gBAAgB,MAAM;AACrD,eAAO;AAAA,MACT;AAGA,aAAO,OAAO,WAAW;AAAA,IAC3B,CAAC;AAAA,EACH;AACF;AASA,cAAc,SAAS,SAAU,KAAqB;AAEpD,SAAO,IACJ,QAAQ,YAAY,CAAC,OAAO,cAAe,YAAY,QAAQ,MAAO,EACtE,QAAQ,YAAY,CAAC,OAAO,cAAe,YAAY,QAAQ,MAAO;AAC3E;","names":[]}
1
+ {"version":3,"sources":["../../src/lib/internal/path-utils.ts","../../src/lib/internal/stringify-template-value.ts","../../src/lib/curly-brackets.ts"],"sourcesContent":["const PATH_SEGMENT_PATTERN =\n /(\\w+)|\\[(\\d+)\\]|\\[\"((?:[^\"\\\\]|\\\\.)*)\"\\]|\\['((?:[^'\\\\]|\\\\.)*)'\\]/y;\n\nfunction unescapeQuotedPathPart(value: string): string {\n return value.replace(/\\\\([\"'\\\\])/g, '$1');\n}\n\n/**\n * Parses a mixed object/array path such as \"user.roles[0].name\" into lookup parts.\n */\nexport function getPathParts(path: string): string[] | null {\n const parts: string[] = [];\n let index = 0;\n\n while (index < path.length) {\n if (path[index] === '.') {\n index++;\n\n if (index >= path.length) {\n return null;\n }\n }\n\n PATH_SEGMENT_PATTERN.lastIndex = index;\n const match = PATH_SEGMENT_PATTERN.exec(path);\n\n if (!match) {\n return null;\n }\n\n if (match[1] !== undefined) {\n parts.push(match[1]);\n } else if (match[2] !== undefined) {\n parts.push(match[2]);\n } else if (match[3] !== undefined) {\n parts.push(unescapeQuotedPathPart(match[3]));\n } else if (match[4] !== undefined) {\n parts.push(unescapeQuotedPathPart(match[4]));\n }\n\n index = PATH_SEGMENT_PATTERN.lastIndex;\n\n if (index < path.length && path[index] !== '.' && path[index] !== '[') {\n return null;\n }\n }\n\n return parts;\n}\n","/**\n * Normalizes values to the same string representation used by template rendering.\n */\nexport function stringifyTemplateValue(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n\n return String(value);\n}\n","import { getPathParts } from './internal/path-utils';\nimport { stringifyTemplateValue } from './internal/stringify-template-value';\n\nexport type TemplateFunction = (locals: Record<string, unknown>) => string;\n\ninterface CurlyBracketsFunction {\n (str?: string, locals?: Record<string, unknown>, fallback?: string): string;\n compileTemplate: (str: string, fallback?: string) => TemplateFunction;\n escape: (str: string) => string;\n}\n\nconst PLACEHOLDER_PATTERN = /(?:\\\\)?{{(\\s*[^{}]+?\\s*)(?:\\\\)?\\s*}}/g;\n\n/**\n * Processes a template string, replacing placeholders with corresponding values from a provided object.\n *\n * @param {string} str - The template string to process.\n * @param locals - An object containing key-value pairs for placeholder replacement.\n * @param fallback - A default string to use when a placeholder's corresponding value is not found.\n * @returns - The processed string with placeholders replaced by their corresponding values.\n */\n\nconst CurlyBrackets: CurlyBracketsFunction = function (\n str: string = '',\n locals: Record<string, unknown> = {},\n fallback: string = '(null)',\n): string {\n // Short-circuit if no brackets - no need to process\n if (!str.includes('{{')) {\n return str;\n }\n\n const compiled = CurlyBrackets.compileTemplate(str, fallback);\n\n return compiled(locals);\n} as CurlyBracketsFunction;\n\n/**\n * Compiles a template string into a reusable function, which can be called with different sets of locals.\n * This is more efficient when you have a template that you want to use with different sets of locals,\n * as it avoids the overhead of parsing the template string each time it is used.\n *\n * @param {string} str - The template string to compile.\n * @param {string} fallback - A default string to use when a placeholder's corresponding value is not found in locals.\n * @returns A function that takes an object of locals and returns a processed string.\n */\n\nCurlyBrackets.compileTemplate = function (\n str: string,\n fallback: string = '(null)',\n): TemplateFunction {\n return (locals: Record<string, unknown>): string => {\n return str.replace(PLACEHOLDER_PATTERN, (match, p1: string) => {\n if (typeof p1 !== 'string') {\n return match;\n }\n\n const hasLeadingEscape = match.startsWith('\\\\');\n const hasEndingEscape = match.endsWith('\\\\}}');\n const isFullyEscaped = hasLeadingEscape && hasEndingEscape;\n\n if (isFullyEscaped) {\n return match.slice(1, -3) + '}}';\n }\n\n if (hasLeadingEscape) {\n return match.slice(1);\n }\n\n if (hasEndingEscape) {\n return '{{' + p1.trim() + '}}';\n }\n\n const key = p1.trim();\n const parts = getPathParts(key);\n\n if (!parts || parts.length === 0) {\n return match;\n }\n\n // Use a more specific approach to ensure the type is consistent\n let replacement: unknown = locals;\n\n for (const part of parts) {\n if (\n replacement !== undefined &&\n replacement !== null &&\n typeof replacement === 'object' &&\n part in replacement\n ) {\n replacement = (replacement as Record<string, unknown>)[part];\n } else {\n replacement = undefined;\n break;\n }\n }\n\n if (replacement === undefined || replacement === null) {\n return fallback;\n }\n\n return stringifyTemplateValue(replacement);\n });\n };\n};\n\n/**\n * Escapes placeholders in a string by prefixing them with a backslash, preventing them from being replaced when processed.\n *\n * @param {string} str - The string in which to escape placeholders.\n * @returns {string} - The string with placeholders escaped.\n */\n\nCurlyBrackets.escape = function (str: string): string {\n // Use a regex to replace instances of {{ and }} that are not already preceded by a backslash\n return str\n .replace(/(\\\\)?{{/g, (match, backslash) => (backslash ? match : '\\\\{{'))\n .replace(/(\\\\)?}}/g, (match, backslash) => (backslash ? match : '\\\\}}'));\n};\n\nexport { CurlyBrackets };\n"],"mappings":"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","names":[]}
@@ -971,6 +971,14 @@ function getPathParts(path) {
971
971
  return parts;
972
972
  }
973
973
 
974
+ // src/lib/internal/stringify-template-value.ts
975
+ function stringifyTemplateValue(value) {
976
+ if (typeof value === "string") {
977
+ return value;
978
+ }
979
+ return String(value);
980
+ }
981
+
974
982
  // src/lib/curly-brackets.ts
975
983
  var PLACEHOLDER_PATTERN = /(?:\\)?{{(\s*[^{}]+?\s*)(?:\\)?\s*}}/g;
976
984
  var CurlyBrackets = function(str = "", locals = {}, fallback = "(null)") {
@@ -1015,7 +1023,7 @@ CurlyBrackets.compileTemplate = function(str, fallback = "(null)") {
1015
1023
  if (replacement === void 0 || replacement === null) {
1016
1024
  return fallback;
1017
1025
  }
1018
- return String(replacement);
1026
+ return stringifyTemplateValue(replacement);
1019
1027
  });
1020
1028
  };
1021
1029
  };
@@ -1391,14 +1399,17 @@ function applyRedaction(params, redactedKeys, redactFunction) {
1391
1399
  const redactedParams = deepClone(params);
1392
1400
  for (const key of redactedKeys) {
1393
1401
  if (key.includes(".") || key.includes("[")) {
1394
- const value = getNestedValue(redactedParams, key);
1402
+ const value = getNestedValue(params, key);
1395
1403
  if (value !== void 0) {
1396
- const redactedValue = redactFn(key, value);
1404
+ const redactedValue = redactFn(key, stringifyTemplateValue(value));
1397
1405
  setNestedValue(redactedParams, key, redactedValue);
1398
1406
  }
1399
1407
  } else {
1400
- if (key in redactedParams) {
1401
- redactedParams[key] = redactFn(key, redactedParams[key]);
1408
+ if (key in params) {
1409
+ redactedParams[key] = redactFn(
1410
+ key,
1411
+ stringifyTemplateValue(params[key])
1412
+ );
1402
1413
  }
1403
1414
  }
1404
1415
  }
@@ -2478,8 +2489,9 @@ var Logger = class _Logger extends EventEmitter {
2478
2489
  const params = options?.params;
2479
2490
  const tags = options?.tags;
2480
2491
  const redactedKeys = options?.redactedKeys;
2481
- const message = params ? CurlyBrackets(template, params) : template;
2482
- const redactedParams = params ? applyRedaction(params, redactedKeys, this.redactFunction) : void 0;
2492
+ const redactedParams = params && redactedKeys && redactedKeys.length > 0 ? applyRedaction(params, redactedKeys, this.redactFunction) : void 0;
2493
+ const messageParams = redactedParams ?? params;
2494
+ const message = messageParams ? CurlyBrackets(template, messageParams) : template;
2483
2495
  const entry = {
2484
2496
  timestamp,
2485
2497
  type,