@typia/utils 12.0.0-dev.20260309 → 12.0.0-dev.20260310

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.
Files changed (92) hide show
  1. package/lib/http/internal/HttpLlmApplicationComposer.mjs +5 -1
  2. package/lib/http/internal/HttpLlmApplicationComposer.mjs.map +1 -1
  3. package/lib/index.mjs +9 -9
  4. package/lib/utils/LlmJson.mjs +9 -2
  5. package/lib/utils/LlmJson.mjs.map +1 -1
  6. package/lib/utils/internal/stringifyValidationFailure.js +17 -15
  7. package/lib/utils/internal/stringifyValidationFailure.js.map +1 -1
  8. package/lib/utils/internal/stringifyValidationFailure.mjs +17 -15
  9. package/lib/utils/internal/stringifyValidationFailure.mjs.map +1 -1
  10. package/lib/validators/internal/OpenApiOneOfValidator.mjs +5 -1
  11. package/lib/validators/internal/OpenApiOneOfValidator.mjs.map +1 -1
  12. package/package.json +2 -2
  13. package/src/converters/LlmSchemaConverter.ts +647 -647
  14. package/src/converters/OpenApiConverter.ts +285 -285
  15. package/src/converters/index.ts +5 -5
  16. package/src/converters/internal/LlmDescriptionInverter.ts +178 -178
  17. package/src/converters/internal/LlmParametersComposer.ts +52 -52
  18. package/src/converters/internal/OpenApiConstraintShifter.ts +154 -154
  19. package/src/converters/internal/OpenApiExclusiveEmender.ts +46 -46
  20. package/src/converters/internal/OpenApiV3Downgrader.ts +355 -355
  21. package/src/converters/internal/OpenApiV3Upgrader.ts +470 -470
  22. package/src/converters/internal/OpenApiV3_1Upgrader.ts +685 -685
  23. package/src/converters/internal/SwaggerV2Downgrader.ts +424 -424
  24. package/src/converters/internal/SwaggerV2Upgrader.ts +523 -523
  25. package/src/http/HttpError.ts +107 -107
  26. package/src/http/HttpLlm.ts +167 -167
  27. package/src/http/HttpMigration.ts +92 -92
  28. package/src/http/index.ts +3 -3
  29. package/src/http/internal/HttpLlmApplicationComposer.ts +361 -361
  30. package/src/http/internal/HttpLlmFunctionFetcher.ts +37 -37
  31. package/src/http/internal/HttpMigrateApplicationComposer.ts +56 -56
  32. package/src/http/internal/HttpMigrateRouteAccessor.ts +135 -135
  33. package/src/http/internal/HttpMigrateRouteComposer.ts +505 -505
  34. package/src/http/internal/HttpMigrateRouteFetcher.ts +203 -203
  35. package/src/index.ts +4 -4
  36. package/src/utils/ArrayUtil.ts +42 -42
  37. package/src/utils/LlmJson.ts +141 -141
  38. package/src/utils/MapUtil.ts +15 -15
  39. package/src/utils/NamingConvention.ts +205 -205
  40. package/src/utils/Singleton.ts +17 -17
  41. package/src/utils/StringUtil.ts +14 -14
  42. package/src/utils/dedent.ts +57 -57
  43. package/src/utils/index.ts +8 -8
  44. package/src/utils/internal/EndpointUtil.ts +44 -44
  45. package/src/utils/internal/JsonDescriptor.ts +70 -70
  46. package/src/utils/internal/OpenApiTypeCheckerBase.ts +822 -822
  47. package/src/utils/internal/coerceLlmArguments.ts +314 -314
  48. package/src/utils/internal/parseLenientJson.ts +894 -894
  49. package/src/utils/internal/stringifyValidationFailure.ts +415 -411
  50. package/src/validators/LlmTypeChecker.ts +402 -402
  51. package/src/validators/OpenApiTypeChecker.ts +297 -297
  52. package/src/validators/OpenApiV3TypeChecker.ts +70 -70
  53. package/src/validators/OpenApiV3_1TypeChecker.ts +86 -86
  54. package/src/validators/OpenApiValidator.ts +94 -94
  55. package/src/validators/SwaggerV2TypeChecker.ts +71 -71
  56. package/src/validators/functional/_isBigintString.ts +8 -8
  57. package/src/validators/functional/_isFormatByte.ts +7 -7
  58. package/src/validators/functional/_isFormatDate.ts +3 -3
  59. package/src/validators/functional/_isFormatDateTime.ts +4 -4
  60. package/src/validators/functional/_isFormatDuration.ts +4 -4
  61. package/src/validators/functional/_isFormatEmail.ts +4 -4
  62. package/src/validators/functional/_isFormatHostname.ts +4 -4
  63. package/src/validators/functional/_isFormatIdnEmail.ts +4 -4
  64. package/src/validators/functional/_isFormatIdnHostname.ts +4 -4
  65. package/src/validators/functional/_isFormatIpv4.ts +4 -4
  66. package/src/validators/functional/_isFormatIpv6.ts +4 -4
  67. package/src/validators/functional/_isFormatIri.ts +3 -3
  68. package/src/validators/functional/_isFormatIriReference.ts +4 -4
  69. package/src/validators/functional/_isFormatJsonPointer.ts +3 -3
  70. package/src/validators/functional/_isFormatPassword.ts +1 -1
  71. package/src/validators/functional/_isFormatRegex.ts +8 -8
  72. package/src/validators/functional/_isFormatRelativeJsonPointer.ts +4 -4
  73. package/src/validators/functional/_isFormatTime.ts +4 -4
  74. package/src/validators/functional/_isFormatUri.ts +6 -6
  75. package/src/validators/functional/_isFormatUriReference.ts +5 -5
  76. package/src/validators/functional/_isFormatUriTemplate.ts +4 -4
  77. package/src/validators/functional/_isFormatUrl.ts +4 -4
  78. package/src/validators/functional/_isFormatUuid.ts +3 -3
  79. package/src/validators/functional/_isUniqueItems.ts +159 -159
  80. package/src/validators/index.ts +14 -14
  81. package/src/validators/internal/IOpenApiValidatorContext.ts +17 -17
  82. package/src/validators/internal/OpenApiArrayValidator.ts +49 -49
  83. package/src/validators/internal/OpenApiBooleanValidator.ts +11 -11
  84. package/src/validators/internal/OpenApiConstantValidator.ts +11 -11
  85. package/src/validators/internal/OpenApiIntegerValidator.ts +49 -49
  86. package/src/validators/internal/OpenApiNumberValidator.ts +48 -48
  87. package/src/validators/internal/OpenApiObjectValidator.ts +83 -83
  88. package/src/validators/internal/OpenApiOneOfValidator.ts +309 -309
  89. package/src/validators/internal/OpenApiSchemaNamingRule.ts +124 -124
  90. package/src/validators/internal/OpenApiStationValidator.ts +115 -115
  91. package/src/validators/internal/OpenApiStringValidator.ts +88 -88
  92. package/src/validators/internal/OpenApiTupleValidator.ts +55 -55
@@ -1,205 +1,205 @@
1
- /**
2
- * String naming convention converters.
3
- *
4
- * `NamingConvention` converts between common code naming conventions:
5
- * camelCase, PascalCase, and snake_case. Handles edge cases like consecutive
6
- * uppercase letters (e.g., `XMLParser` → `xml_parser`) and leading
7
- * underscores.
8
- *
9
- * Functions:
10
- *
11
- * - {@link camel}: Convert to camelCase (`fooBar`)
12
- * - {@link pascal}: Convert to PascalCase (`FooBar`)
13
- * - {@link snake}: Convert to snake_case (`foo_bar`)
14
- * - {@link variable}: Test if string is valid JavaScript variable name
15
- *
16
- * @author Jeongho Nam - https://github.com/samchon
17
- */
18
- export namespace NamingConvention {
19
- /**
20
- * Convert to camelCase.
21
- *
22
- * @param str Input string
23
- * @returns CamelCase string
24
- */
25
- export function camel(str: string) {
26
- return unsnake({
27
- plain: (str) =>
28
- str.length
29
- ? str === str.toUpperCase()
30
- ? str.toLocaleLowerCase()
31
- : `${str[0]!.toLowerCase()}${str.substring(1)}`
32
- : str,
33
- snake: (str, i) =>
34
- i === 0 ? str.toLowerCase() : capitalize(str.toLowerCase()),
35
- })(str);
36
- }
37
-
38
- /**
39
- * Convert to PascalCase.
40
- *
41
- * @param str Input string
42
- * @returns PascalCase string
43
- */
44
- export function pascal(str: string) {
45
- return unsnake({
46
- plain: (str) =>
47
- str.length ? `${str[0]!.toUpperCase()}${str.substring(1)}` : str,
48
- snake: capitalize,
49
- })(str);
50
- }
51
-
52
- /**
53
- * Convert to snake_case.
54
- *
55
- * @param str Input string
56
- * @returns Snake_case string
57
- */
58
- export function snake(str: string): string {
59
- if (str.length === 0) return str;
60
-
61
- // PREFIX
62
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
63
- let prefix: string = "";
64
- for (let i: number = 0; i < str.length; i++) {
65
- if (str[i] === "_") prefix += "_";
66
- else break;
67
- }
68
- if (prefix.length !== 0) str = str.substring(prefix.length);
69
-
70
- const out = (s: string) => `${prefix}${s}`;
71
-
72
- // SNAKE CASE
73
- const items: string[] = str.split("_");
74
- if (items.length > 1)
75
- return out(items.map((s) => s.toLowerCase()).join("_"));
76
-
77
- // CAMEL OR PASCAL CASE
78
- const indexes: number[] = [];
79
- for (let i: number = 0; i < str.length; i++) {
80
- const code: number = str.charCodeAt(i);
81
- if (65 <= code && code <= 90) indexes.push(i);
82
- }
83
- for (let i: number = indexes.length - 1; i > 0; --i) {
84
- const now: number = indexes[i]!;
85
- const prev: number = indexes[i - 1]!;
86
- if (now - prev === 1) indexes.splice(i, 1);
87
- }
88
- if (indexes.length !== 0 && indexes[0] === 0) indexes.splice(0, 1);
89
- if (indexes.length === 0) return str.toLowerCase();
90
-
91
- let ret: string = "";
92
- for (let i: number = 0; i < indexes.length; i++) {
93
- const first: number = i === 0 ? 0 : indexes[i - 1]!;
94
- const last: number = indexes[i]!;
95
-
96
- ret += str.substring(first, last).toLowerCase();
97
- ret += "_";
98
- }
99
- ret += str.substring(indexes[indexes.length - 1]!).toLowerCase();
100
- return out(ret);
101
- }
102
-
103
- /**
104
- * Capitalize first character.
105
- *
106
- * @param str Input string
107
- * @returns Capitalized string
108
- */
109
- export const capitalize = (str: string): string =>
110
- str.length !== 0 ? str[0]!.toUpperCase() + str.slice(1) : str;
111
-
112
- /**
113
- * Lowercase first character.
114
- *
115
- * @param str Input string
116
- * @returns Localized string
117
- */
118
- export const localize = (str: string) => str[0]!.toLowerCase() + str.slice(1);
119
-
120
- /**
121
- * Check if string is valid JavaScript variable name.
122
- *
123
- * @param str String to check
124
- * @returns True if valid variable name
125
- */
126
- export const variable = (str: string): boolean =>
127
- reserved(str) === false && /^[a-zA-Z_$][a-zA-Z_$0-9]*$/g.test(str);
128
-
129
- /**
130
- * Check if string is JavaScript reserved word.
131
- *
132
- * @param str String to check
133
- * @returns True if reserved word
134
- */
135
- export const reserved = (str: string): boolean => RESERVED.has(str);
136
- }
137
-
138
- const RESERVED: Set<string> = new Set([
139
- "break",
140
- "case",
141
- "catch",
142
- "class",
143
- "const",
144
- "continue",
145
- "debugger",
146
- "default",
147
- "delete",
148
- "do",
149
- "else",
150
- "enum",
151
- "export",
152
- "extends",
153
- "false",
154
- "finally",
155
- "for",
156
- "function",
157
- "if",
158
- "import",
159
- "in",
160
- "instanceof",
161
- "module",
162
- "new",
163
- "null",
164
- "package",
165
- "public",
166
- "private",
167
- "protected",
168
- "return",
169
- "super",
170
- "switch",
171
- "this",
172
- "throw",
173
- "true",
174
- "try",
175
- "typeof",
176
- "var",
177
- "void",
178
- "while",
179
- "with",
180
- ]);
181
-
182
- const unsnake =
183
- (props: {
184
- plain: (str: string) => string;
185
- snake: (str: string, index: number) => string;
186
- }) =>
187
- (str: string): string => {
188
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
189
- let prefix: string = "";
190
- for (let i: number = 0; i < str.length; i++) {
191
- if (str[i] === "_") prefix += "_";
192
- else break;
193
- }
194
- if (prefix.length !== 0) str = str.substring(prefix.length);
195
-
196
- const out = (s: string) => `${prefix}${s}`;
197
- if (str.length === 0) return out("");
198
-
199
- const items: string[] = str.split("_").filter((s) => s.length !== 0);
200
- return items.length === 0
201
- ? out("")
202
- : items.length === 1
203
- ? out(props.plain(items[0]!))
204
- : out(items.map(props.snake).join(""));
205
- };
1
+ /**
2
+ * String naming convention converters.
3
+ *
4
+ * `NamingConvention` converts between common code naming conventions:
5
+ * camelCase, PascalCase, and snake_case. Handles edge cases like consecutive
6
+ * uppercase letters (e.g., `XMLParser` → `xml_parser`) and leading
7
+ * underscores.
8
+ *
9
+ * Functions:
10
+ *
11
+ * - {@link camel}: Convert to camelCase (`fooBar`)
12
+ * - {@link pascal}: Convert to PascalCase (`FooBar`)
13
+ * - {@link snake}: Convert to snake_case (`foo_bar`)
14
+ * - {@link variable}: Test if string is valid JavaScript variable name
15
+ *
16
+ * @author Jeongho Nam - https://github.com/samchon
17
+ */
18
+ export namespace NamingConvention {
19
+ /**
20
+ * Convert to camelCase.
21
+ *
22
+ * @param str Input string
23
+ * @returns CamelCase string
24
+ */
25
+ export function camel(str: string) {
26
+ return unsnake({
27
+ plain: (str) =>
28
+ str.length
29
+ ? str === str.toUpperCase()
30
+ ? str.toLocaleLowerCase()
31
+ : `${str[0]!.toLowerCase()}${str.substring(1)}`
32
+ : str,
33
+ snake: (str, i) =>
34
+ i === 0 ? str.toLowerCase() : capitalize(str.toLowerCase()),
35
+ })(str);
36
+ }
37
+
38
+ /**
39
+ * Convert to PascalCase.
40
+ *
41
+ * @param str Input string
42
+ * @returns PascalCase string
43
+ */
44
+ export function pascal(str: string) {
45
+ return unsnake({
46
+ plain: (str) =>
47
+ str.length ? `${str[0]!.toUpperCase()}${str.substring(1)}` : str,
48
+ snake: capitalize,
49
+ })(str);
50
+ }
51
+
52
+ /**
53
+ * Convert to snake_case.
54
+ *
55
+ * @param str Input string
56
+ * @returns Snake_case string
57
+ */
58
+ export function snake(str: string): string {
59
+ if (str.length === 0) return str;
60
+
61
+ // PREFIX
62
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
63
+ let prefix: string = "";
64
+ for (let i: number = 0; i < str.length; i++) {
65
+ if (str[i] === "_") prefix += "_";
66
+ else break;
67
+ }
68
+ if (prefix.length !== 0) str = str.substring(prefix.length);
69
+
70
+ const out = (s: string) => `${prefix}${s}`;
71
+
72
+ // SNAKE CASE
73
+ const items: string[] = str.split("_");
74
+ if (items.length > 1)
75
+ return out(items.map((s) => s.toLowerCase()).join("_"));
76
+
77
+ // CAMEL OR PASCAL CASE
78
+ const indexes: number[] = [];
79
+ for (let i: number = 0; i < str.length; i++) {
80
+ const code: number = str.charCodeAt(i);
81
+ if (65 <= code && code <= 90) indexes.push(i);
82
+ }
83
+ for (let i: number = indexes.length - 1; i > 0; --i) {
84
+ const now: number = indexes[i]!;
85
+ const prev: number = indexes[i - 1]!;
86
+ if (now - prev === 1) indexes.splice(i, 1);
87
+ }
88
+ if (indexes.length !== 0 && indexes[0] === 0) indexes.splice(0, 1);
89
+ if (indexes.length === 0) return str.toLowerCase();
90
+
91
+ let ret: string = "";
92
+ for (let i: number = 0; i < indexes.length; i++) {
93
+ const first: number = i === 0 ? 0 : indexes[i - 1]!;
94
+ const last: number = indexes[i]!;
95
+
96
+ ret += str.substring(first, last).toLowerCase();
97
+ ret += "_";
98
+ }
99
+ ret += str.substring(indexes[indexes.length - 1]!).toLowerCase();
100
+ return out(ret);
101
+ }
102
+
103
+ /**
104
+ * Capitalize first character.
105
+ *
106
+ * @param str Input string
107
+ * @returns Capitalized string
108
+ */
109
+ export const capitalize = (str: string): string =>
110
+ str.length !== 0 ? str[0]!.toUpperCase() + str.slice(1) : str;
111
+
112
+ /**
113
+ * Lowercase first character.
114
+ *
115
+ * @param str Input string
116
+ * @returns Localized string
117
+ */
118
+ export const localize = (str: string) => str[0]!.toLowerCase() + str.slice(1);
119
+
120
+ /**
121
+ * Check if string is valid JavaScript variable name.
122
+ *
123
+ * @param str String to check
124
+ * @returns True if valid variable name
125
+ */
126
+ export const variable = (str: string): boolean =>
127
+ reserved(str) === false && /^[a-zA-Z_$][a-zA-Z_$0-9]*$/g.test(str);
128
+
129
+ /**
130
+ * Check if string is JavaScript reserved word.
131
+ *
132
+ * @param str String to check
133
+ * @returns True if reserved word
134
+ */
135
+ export const reserved = (str: string): boolean => RESERVED.has(str);
136
+ }
137
+
138
+ const RESERVED: Set<string> = new Set([
139
+ "break",
140
+ "case",
141
+ "catch",
142
+ "class",
143
+ "const",
144
+ "continue",
145
+ "debugger",
146
+ "default",
147
+ "delete",
148
+ "do",
149
+ "else",
150
+ "enum",
151
+ "export",
152
+ "extends",
153
+ "false",
154
+ "finally",
155
+ "for",
156
+ "function",
157
+ "if",
158
+ "import",
159
+ "in",
160
+ "instanceof",
161
+ "module",
162
+ "new",
163
+ "null",
164
+ "package",
165
+ "public",
166
+ "private",
167
+ "protected",
168
+ "return",
169
+ "super",
170
+ "switch",
171
+ "this",
172
+ "throw",
173
+ "true",
174
+ "try",
175
+ "typeof",
176
+ "var",
177
+ "void",
178
+ "while",
179
+ "with",
180
+ ]);
181
+
182
+ const unsnake =
183
+ (props: {
184
+ plain: (str: string) => string;
185
+ snake: (str: string, index: number) => string;
186
+ }) =>
187
+ (str: string): string => {
188
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
189
+ let prefix: string = "";
190
+ for (let i: number = 0; i < str.length; i++) {
191
+ if (str[i] === "_") prefix += "_";
192
+ else break;
193
+ }
194
+ if (prefix.length !== 0) str = str.substring(prefix.length);
195
+
196
+ const out = (s: string) => `${prefix}${s}`;
197
+ if (str.length === 0) return out("");
198
+
199
+ const items: string[] = str.split("_").filter((s) => s.length !== 0);
200
+ return items.length === 0
201
+ ? out("")
202
+ : items.length === 1
203
+ ? out(props.plain(items[0]!))
204
+ : out(items.map(props.snake).join(""));
205
+ };
@@ -1,17 +1,17 @@
1
- /** @internal */
2
- export class Singleton<T, Args extends any[] = []> {
3
- private readonly closure_: (...args: Args) => T;
4
- private value_: T | object;
5
-
6
- public constructor(closure: (...args: Args) => T) {
7
- this.closure_ = closure;
8
- this.value_ = NOT_MOUNTED_YET;
9
- }
10
-
11
- public get(...args: Args): T {
12
- if (this.value_ === NOT_MOUNTED_YET) this.value_ = this.closure_(...args);
13
- return this.value_ as T;
14
- }
15
- }
16
-
17
- const NOT_MOUNTED_YET = {};
1
+ /** @internal */
2
+ export class Singleton<T, Args extends any[] = []> {
3
+ private readonly closure_: (...args: Args) => T;
4
+ private value_: T | object;
5
+
6
+ public constructor(closure: (...args: Args) => T) {
7
+ this.closure_ = closure;
8
+ this.value_ = NOT_MOUNTED_YET;
9
+ }
10
+
11
+ public get(...args: Args): T {
12
+ if (this.value_ === NOT_MOUNTED_YET) this.value_ = this.closure_(...args);
13
+ return this.value_ as T;
14
+ }
15
+ }
16
+
17
+ const NOT_MOUNTED_YET = {};
@@ -1,14 +1,14 @@
1
- /** @internal */
2
- export namespace StringUtil {
3
- export const escapeDuplicate = (props: {
4
- keep: string[];
5
- input: string;
6
- escape?: (str: string) => string;
7
- }): string =>
8
- props.keep.includes(props.input)
9
- ? escapeDuplicate({
10
- keep: props.keep,
11
- input: (props.escape ?? ((str) => `_${str}`))(props.input),
12
- })
13
- : props.input;
14
- }
1
+ /** @internal */
2
+ export namespace StringUtil {
3
+ export const escapeDuplicate = (props: {
4
+ keep: string[];
5
+ input: string;
6
+ escape?: (str: string) => string;
7
+ }): string =>
8
+ props.keep.includes(props.input)
9
+ ? escapeDuplicate({
10
+ keep: props.keep,
11
+ input: (props.escape ?? ((str) => `_${str}`))(props.input),
12
+ })
13
+ : props.input;
14
+ }
@@ -1,57 +1,57 @@
1
- /**
2
- * Remove common leading whitespace from template literal.
3
- *
4
- * Strips leading/trailing blank lines and removes the minimum indentation level
5
- * from all lines.
6
- *
7
- * @author Jeongho Nam - https://github.com/samchon
8
- * @param strings Template literal strings
9
- * @param values Interpolated values
10
- * @returns Dedented string
11
- */
12
- export function dedent(
13
- strings: TemplateStringsArray,
14
- ...values: Array<boolean | number | string>
15
- ): string {
16
- // Combine all template string parts to understand the full structure
17
- let combined: string = strings[0]!;
18
- for (let i = 0; i < values.length; i++) {
19
- combined += `__PLACEHOLDER_${i}__` + strings[i + 1];
20
- }
21
-
22
- // Split into lines
23
- const lines = combined.split("\n");
24
-
25
- // Remove leading and trailing empty lines
26
- while (lines.length > 0 && lines[0]!.trim() === "") {
27
- lines.shift();
28
- }
29
- while (lines.length > 0 && lines[lines.length - 1]!.trim() === "") {
30
- lines.pop();
31
- }
32
-
33
- if (lines.length === 0) return "";
34
-
35
- // Find minimum indentation from non-empty lines
36
- const nonEmptyLines = lines.filter((line) => line.trim() !== "");
37
- const minIndent = Math.min(
38
- ...nonEmptyLines.map((line) => {
39
- const match = line.match(/^[ \t]*/);
40
- return match ? match[0].length : 0;
41
- }),
42
- );
43
-
44
- // Remove minimum indentation from all lines
45
- const dedentedLines = lines.map((line) => {
46
- if (line.trim() === "") return "";
47
- return line.slice(minIndent);
48
- });
49
-
50
- // Replace placeholders with actual values
51
- let result = dedentedLines.join("\n");
52
- for (let i = 0; i < values.length; i++) {
53
- result = result.replace(`__PLACEHOLDER_${i}__`, String(values[i]));
54
- }
55
-
56
- return result;
57
- }
1
+ /**
2
+ * Remove common leading whitespace from template literal.
3
+ *
4
+ * Strips leading/trailing blank lines and removes the minimum indentation level
5
+ * from all lines.
6
+ *
7
+ * @author Jeongho Nam - https://github.com/samchon
8
+ * @param strings Template literal strings
9
+ * @param values Interpolated values
10
+ * @returns Dedented string
11
+ */
12
+ export function dedent(
13
+ strings: TemplateStringsArray,
14
+ ...values: Array<boolean | number | string>
15
+ ): string {
16
+ // Combine all template string parts to understand the full structure
17
+ let combined: string = strings[0]!;
18
+ for (let i = 0; i < values.length; i++) {
19
+ combined += `__PLACEHOLDER_${i}__` + strings[i + 1];
20
+ }
21
+
22
+ // Split into lines
23
+ const lines = combined.split("\n");
24
+
25
+ // Remove leading and trailing empty lines
26
+ while (lines.length > 0 && lines[0]!.trim() === "") {
27
+ lines.shift();
28
+ }
29
+ while (lines.length > 0 && lines[lines.length - 1]!.trim() === "") {
30
+ lines.pop();
31
+ }
32
+
33
+ if (lines.length === 0) return "";
34
+
35
+ // Find minimum indentation from non-empty lines
36
+ const nonEmptyLines = lines.filter((line) => line.trim() !== "");
37
+ const minIndent = Math.min(
38
+ ...nonEmptyLines.map((line) => {
39
+ const match = line.match(/^[ \t]*/);
40
+ return match ? match[0].length : 0;
41
+ }),
42
+ );
43
+
44
+ // Remove minimum indentation from all lines
45
+ const dedentedLines = lines.map((line) => {
46
+ if (line.trim() === "") return "";
47
+ return line.slice(minIndent);
48
+ });
49
+
50
+ // Replace placeholders with actual values
51
+ let result = dedentedLines.join("\n");
52
+ for (let i = 0; i < values.length; i++) {
53
+ result = result.replace(`__PLACEHOLDER_${i}__`, String(values[i]));
54
+ }
55
+
56
+ return result;
57
+ }
@@ -1,8 +1,8 @@
1
- export * from "./ArrayUtil";
2
- export * from "./LlmJson";
3
- export * from "./MapUtil";
4
- export * from "./NamingConvention";
5
- export * from "./Singleton";
6
- export * from "./StringUtil";
7
-
8
- export * from "./dedent";
1
+ export * from "./ArrayUtil";
2
+ export * from "./LlmJson";
3
+ export * from "./MapUtil";
4
+ export * from "./NamingConvention";
5
+ export * from "./Singleton";
6
+ export * from "./StringUtil";
7
+
8
+ export * from "./dedent";