@agentica/core 0.43.3 → 0.44.0-dev.20260313

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 (205) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +218 -218
  3. package/lib/constants/AgenticaSystemPrompt.js +1 -1
  4. package/lib/constants/AgenticaSystemPrompt.js.map +1 -1
  5. package/lib/context/AgenticaOperation.d.ts +3 -2
  6. package/lib/context/internal/AgenticaOperationComposer.js.map +1 -1
  7. package/lib/context/internal/AgenticaTokenUsageAggregator.js.map +1 -1
  8. package/lib/context/internal/__IChatInitialApplication.d.ts +1 -1
  9. package/lib/errors/AgenticaJsonParseError.d.ts +5 -8
  10. package/lib/errors/AgenticaJsonParseError.js +11 -6
  11. package/lib/errors/AgenticaJsonParseError.js.map +1 -1
  12. package/lib/errors/AgenticaValidationError.d.ts +1 -1
  13. package/lib/events/AgenticaExecuteEvent.d.ts +1 -1
  14. package/lib/events/AgenticaJsonParseErrorEvent.d.ts +2 -2
  15. package/lib/factory/events.d.ts +2 -3
  16. package/lib/factory/events.js +1 -2
  17. package/lib/factory/events.js.map +1 -1
  18. package/lib/functional/assertHttpController.d.ts +2 -3
  19. package/lib/functional/assertHttpController.js +3939 -2656
  20. package/lib/functional/assertHttpController.js.map +1 -1
  21. package/lib/functional/assertHttpLlmApplication.d.ts +3 -3
  22. package/lib/functional/assertHttpLlmApplication.js +3939 -2656
  23. package/lib/functional/assertHttpLlmApplication.js.map +1 -1
  24. package/lib/functional/assertMcpController.d.ts +2 -2
  25. package/lib/functional/assertMcpController.js +202 -629
  26. package/lib/functional/assertMcpController.js.map +1 -1
  27. package/lib/functional/createMcpLlmApplication.d.ts +6 -0
  28. package/lib/functional/createMcpLlmApplication.js +56 -0
  29. package/lib/functional/createMcpLlmApplication.js.map +1 -0
  30. package/lib/functional/validateHttpController.d.ts +3 -3
  31. package/lib/functional/validateHttpController.js +3367 -2268
  32. package/lib/functional/validateHttpController.js.map +1 -1
  33. package/lib/functional/validateHttpLlmApplication.d.ts +3 -4
  34. package/lib/functional/validateHttpLlmApplication.js +3367 -2268
  35. package/lib/functional/validateHttpLlmApplication.js.map +1 -1
  36. package/lib/functional/validateMcpController.d.ts +2 -2
  37. package/lib/functional/validateMcpController.js +388 -1161
  38. package/lib/functional/validateMcpController.js.map +1 -1
  39. package/lib/histories/AgenticaExecuteHistory.d.ts +1 -1
  40. package/lib/index.mjs +21256 -18946
  41. package/lib/index.mjs.map +1 -1
  42. package/lib/orchestrate/call.js +43 -56
  43. package/lib/orchestrate/call.js.map +1 -1
  44. package/lib/orchestrate/cancel.js +9 -66
  45. package/lib/orchestrate/cancel.js.map +1 -1
  46. package/lib/orchestrate/initialize.js +4 -947
  47. package/lib/orchestrate/initialize.js.map +1 -1
  48. package/lib/orchestrate/select.js +11 -68
  49. package/lib/orchestrate/select.js.map +1 -1
  50. package/lib/structures/IAgenticaController.d.ts +143 -151
  51. package/lib/structures/IMcpTool.d.ts +52 -0
  52. package/lib/structures/IMcpTool.js +3 -0
  53. package/lib/structures/IMcpTool.js.map +1 -0
  54. package/lib/utils/ChatGptCompletionMessageUtil.js +16 -5
  55. package/lib/utils/ChatGptCompletionMessageUtil.js.map +1 -1
  56. package/lib/utils/ChatGptCompletionMessageUtil.spec.js +0 -5
  57. package/lib/utils/ChatGptCompletionMessageUtil.spec.js.map +1 -1
  58. package/package.json +7 -9
  59. package/prompts/cancel.md +5 -5
  60. package/prompts/common.md +3 -3
  61. package/prompts/describe.md +7 -7
  62. package/prompts/execute.md +122 -122
  63. package/prompts/initialize.md +3 -3
  64. package/prompts/json_parse_error.md +35 -33
  65. package/prompts/select.md +7 -7
  66. package/prompts/validate.md +123 -123
  67. package/prompts/validate_repeated.md +31 -31
  68. package/src/Agentica.ts +367 -367
  69. package/src/MicroAgentica.ts +357 -357
  70. package/src/constants/AgenticaConstant.ts +4 -4
  71. package/src/constants/AgenticaDefaultPrompt.ts +44 -44
  72. package/src/constants/AgenticaSystemPrompt.ts +1 -1
  73. package/src/constants/index.ts +2 -2
  74. package/src/context/AgenticaContext.ts +136 -136
  75. package/src/context/AgenticaContextRequestResult.ts +14 -14
  76. package/src/context/AgenticaOperation.ts +73 -72
  77. package/src/context/AgenticaOperationCollection.ts +49 -49
  78. package/src/context/AgenticaOperationSelection.ts +9 -9
  79. package/src/context/AgenticaTokenUsage.ts +186 -186
  80. package/src/context/MicroAgenticaContext.ts +99 -99
  81. package/src/context/index.ts +5 -5
  82. package/src/context/internal/AgenticaOperationComposer.ts +177 -177
  83. package/src/context/internal/AgenticaTokenUsageAggregator.ts +66 -66
  84. package/src/context/internal/__IChatCancelFunctionsApplication.ts +23 -23
  85. package/src/context/internal/__IChatFunctionReference.ts +21 -21
  86. package/src/context/internal/__IChatInitialApplication.ts +15 -15
  87. package/src/context/internal/__IChatSelectFunctionsApplication.ts +24 -24
  88. package/src/context/internal/isAgenticaContext.ts +11 -11
  89. package/src/errors/AgenticaJsonParseError.ts +52 -47
  90. package/src/errors/AgenticaValidationError.ts +49 -49
  91. package/src/errors/index.ts +2 -2
  92. package/src/events/AgenticaAssistantMessageEvent.ts +12 -12
  93. package/src/events/AgenticaCallEvent.ts +27 -27
  94. package/src/events/AgenticaCancelEvent.ts +9 -9
  95. package/src/events/AgenticaDescribeEvent.ts +14 -14
  96. package/src/events/AgenticaEvent.ts +59 -59
  97. package/src/events/AgenticaEvent.type.ts +19 -19
  98. package/src/events/AgenticaEventBase.ts +18 -18
  99. package/src/events/AgenticaEventSource.ts +6 -6
  100. package/src/events/AgenticaExecuteEvent.ts +45 -45
  101. package/src/events/AgenticaInitializeEvent.ts +7 -7
  102. package/src/events/AgenticaJsonParseErrorEvent.ts +16 -15
  103. package/src/events/AgenticaRequestEvent.ts +27 -27
  104. package/src/events/AgenticaResponseEvent.ts +32 -32
  105. package/src/events/AgenticaSelectEvent.ts +11 -11
  106. package/src/events/AgenticaUserMessageEvent.ts +12 -12
  107. package/src/events/AgenticaValidateEvent.ts +32 -32
  108. package/src/events/MicroAgenticaEvent.ts +45 -45
  109. package/src/events/index.ts +15 -15
  110. package/src/factory/events.ts +357 -359
  111. package/src/factory/histories.ts +348 -348
  112. package/src/factory/index.ts +3 -3
  113. package/src/factory/operations.ts +16 -16
  114. package/src/functional/assertHttpController.ts +106 -104
  115. package/src/functional/assertHttpLlmApplication.ts +52 -57
  116. package/src/functional/assertMcpController.ts +47 -44
  117. package/src/functional/createMcpLlmApplication.ts +72 -0
  118. package/src/functional/index.ts +7 -7
  119. package/src/functional/validateHttpController.ts +113 -110
  120. package/src/functional/validateHttpLlmApplication.ts +65 -70
  121. package/src/functional/validateMcpController.ts +53 -50
  122. package/src/histories/AgenticaAssistantMessageHistory.ts +10 -10
  123. package/src/histories/AgenticaCancelHistory.ts +8 -8
  124. package/src/histories/AgenticaDescribeHistory.ts +18 -18
  125. package/src/histories/AgenticaExecuteHistory.ts +64 -64
  126. package/src/histories/AgenticaHistory.ts +28 -28
  127. package/src/histories/AgenticaHistoryBase.ts +35 -35
  128. package/src/histories/AgenticaSelectHistory.ts +8 -8
  129. package/src/histories/AgenticaSystemMessageHistory.ts +10 -10
  130. package/src/histories/AgenticaUserMessageHistory.ts +11 -11
  131. package/src/histories/MicroAgenticaHistory.ts +19 -19
  132. package/src/histories/contents/AgenticaUserMessageAudioContent.ts +21 -21
  133. package/src/histories/contents/AgenticaUserMessageContent.ts +19 -19
  134. package/src/histories/contents/AgenticaUserMessageContentBase.ts +6 -6
  135. package/src/histories/contents/AgenticaUserMessageFileContent.ts +25 -25
  136. package/src/histories/contents/AgenticaUserMessageImageContent.ts +33 -33
  137. package/src/histories/contents/AgenticaUserMessageTextContent.ts +15 -15
  138. package/src/histories/contents/index.ts +5 -5
  139. package/src/histories/index.ts +10 -10
  140. package/src/index.ts +15 -15
  141. package/src/json/IAgenticaEventJson.ts +265 -265
  142. package/src/json/IAgenticaEventJson.type.ts +19 -19
  143. package/src/json/IAgenticaHistoryJson.ts +165 -165
  144. package/src/json/IAgenticaHistoryJson.type.ts +19 -19
  145. package/src/json/IAgenticaOperationJson.ts +36 -36
  146. package/src/json/IAgenticaOperationSelectionJson.ts +26 -26
  147. package/src/json/IAgenticaTokenUsageJson.ts +107 -107
  148. package/src/json/IMicroAgenticaEventJson.ts +22 -22
  149. package/src/json/IMicroAgenticaHistoryJson.ts +25 -25
  150. package/src/json/index.ts +7 -7
  151. package/src/orchestrate/call.ts +542 -558
  152. package/src/orchestrate/cancel.ts +265 -269
  153. package/src/orchestrate/describe.ts +66 -66
  154. package/src/orchestrate/execute.ts +61 -61
  155. package/src/orchestrate/index.ts +6 -6
  156. package/src/orchestrate/initialize.ts +102 -102
  157. package/src/orchestrate/internal/cancelFunctionFromContext.ts +33 -33
  158. package/src/orchestrate/internal/selectFunctionFromContext.ts +34 -34
  159. package/src/orchestrate/select.ts +320 -322
  160. package/src/structures/IAgenticaConfig.ts +83 -83
  161. package/src/structures/IAgenticaConfigBase.ts +87 -87
  162. package/src/structures/IAgenticaController.ts +143 -151
  163. package/src/structures/IAgenticaExecutor.ts +167 -167
  164. package/src/structures/IAgenticaProps.ts +78 -78
  165. package/src/structures/IAgenticaSystemPrompt.ts +236 -236
  166. package/src/structures/IAgenticaVendor.ts +54 -54
  167. package/src/structures/IMcpTool.ts +60 -0
  168. package/src/structures/IMicroAgenticaConfig.ts +56 -56
  169. package/src/structures/IMicroAgenticaExecutor.ts +67 -67
  170. package/src/structures/IMicroAgenticaProps.ts +77 -77
  171. package/src/structures/IMicroAgenticaSystemPrompt.ts +169 -169
  172. package/src/structures/index.ts +10 -10
  173. package/src/transformers/transformHistory.ts +172 -172
  174. package/src/utils/AssistantMessageEmptyError.ts +20 -20
  175. package/src/utils/AsyncQueue.spec.ts +355 -355
  176. package/src/utils/AsyncQueue.ts +95 -95
  177. package/src/utils/ByteArrayUtil.ts +5 -5
  178. package/src/utils/ChatGptCompletionMessageUtil.spec.ts +314 -320
  179. package/src/utils/ChatGptCompletionMessageUtil.ts +210 -195
  180. package/src/utils/ChatGptCompletionStreamingUtil.spec.ts +909 -909
  181. package/src/utils/ChatGptCompletionStreamingUtil.ts +91 -91
  182. package/src/utils/ChatGptTokenUsageAggregator.spec.ts +226 -226
  183. package/src/utils/ChatGptTokenUsageAggregator.ts +57 -57
  184. package/src/utils/MPSC.spec.ts +276 -276
  185. package/src/utils/MPSC.ts +42 -42
  186. package/src/utils/Singleton.spec.ts +138 -138
  187. package/src/utils/Singleton.ts +42 -42
  188. package/src/utils/StreamUtil.spec.ts +512 -512
  189. package/src/utils/StreamUtil.ts +87 -87
  190. package/src/utils/__map_take.spec.ts +140 -140
  191. package/src/utils/__map_take.ts +13 -13
  192. package/src/utils/__retry.spec.ts +198 -198
  193. package/src/utils/__retry.ts +18 -18
  194. package/src/utils/assertExecuteFailure.ts +16 -16
  195. package/src/utils/index.ts +4 -4
  196. package/src/utils/request.ts +140 -140
  197. package/src/utils/types.ts +50 -50
  198. package/lib/context/internal/AgenticaOperationComposer.spec.d.ts +0 -1
  199. package/lib/context/internal/AgenticaOperationComposer.spec.js +0 -353
  200. package/lib/context/internal/AgenticaOperationComposer.spec.js.map +0 -1
  201. package/lib/utils/JsonUtil.d.ts +0 -8
  202. package/lib/utils/JsonUtil.js +0 -349
  203. package/lib/utils/JsonUtil.js.map +0 -1
  204. package/src/context/internal/AgenticaOperationComposer.spec.ts +0 -401
  205. package/src/utils/JsonUtil.ts +0 -460
@@ -1,460 +0,0 @@
1
- import type { ILlmSchema, IValidation } from "@samchon/openapi";
2
-
3
- import { LlmTypeChecker } from "@samchon/openapi";
4
- import { addMissingBraces, removeEmptyObjectPrefix, removeTrailingCommas } from "es-jsonkit";
5
- import { jsonrepair } from "jsonrepair";
6
- import { Escaper } from "typia/lib/utils/Escaper";
7
-
8
- export const JsonUtil = {
9
- parse,
10
- stringifyValidationFailure,
11
- };
12
-
13
- const pipe = (...fns: ((str: string) => string)[]) => (str: string) => fns.reduce((acc, fn) => fn(acc), str);
14
-
15
- function parse(
16
- str: string,
17
- parameters?: ILlmSchema.IParameters,
18
- ): any {
19
- str = pipe(removeEmptyObjectPrefix, addMissingBraces, removeTrailingCommas, jsonrepair)(str);
20
-
21
- const output: any = (() => {
22
- const value = JSON.parse(str);
23
- if (typeof value === "string" && parameters !== undefined) {
24
- try {
25
- return parse(value);
26
- }
27
- catch {}
28
- }
29
- return value;
30
- })();
31
- if (parameters !== undefined) {
32
- decompose(parameters, output);
33
- }
34
- return output;
35
- }
36
-
37
- function decompose(
38
- parameters: ILlmSchema.IParameters,
39
- output: any,
40
- ): void {
41
- if (
42
- Object.keys(parameters.properties).length === 0
43
- || typeof output !== "object"
44
- || output === null) {
45
- return;
46
- }
47
-
48
- for (const [key, schema] of Object.entries(parameters.properties)) {
49
- const value: any = output[key];
50
- if (typeof value === "string"
51
- && isInstanceType({
52
- $defs: parameters.$defs,
53
- schema,
54
- }) === true) {
55
- try {
56
- output[key] = parse(value);
57
- }
58
- catch {}
59
- }
60
- }
61
- }
62
-
63
- function isInstanceType(props: {
64
- $defs: Record<string, ILlmSchema>;
65
- schema: ILlmSchema;
66
- }): boolean {
67
- if (LlmTypeChecker.isReference(props.schema)) {
68
- return isInstanceType({
69
- $defs: props.$defs,
70
- schema: props.$defs[props.schema.$ref.split("/").pop()!] ?? {},
71
- });
72
- }
73
- return LlmTypeChecker.isNull(props.schema)
74
- || LlmTypeChecker.isObject(props.schema)
75
- || LlmTypeChecker.isArray(props.schema)
76
- || (
77
- LlmTypeChecker.isAnyOf(props.schema)
78
- && props.schema.anyOf.every(s => isInstanceType({
79
- $defs: props.$defs,
80
- schema: s,
81
- }))
82
- );
83
- }
84
-
85
- function stringifyValidationFailure(
86
- failure: IValidation.IFailure,
87
- ): string {
88
- const usedErrors = new Set<IValidation.IError>();
89
-
90
- const jsonOutput = stringify({
91
- value: failure.data,
92
- errors: failure.errors,
93
- path: "$input",
94
- tab: 0,
95
- inArray: false,
96
- inToJson: false,
97
- usedErrors,
98
- });
99
-
100
- // Find errors that couldn't be embedded
101
- const unmappableErrors = failure.errors.filter(e => !usedErrors.has(e));
102
-
103
- // If there are unmappable errors, append them as a separate block
104
- if (unmappableErrors.length > 0) {
105
- return `\`\`\`json\n${jsonOutput}\n\`\`\`\n\n**Unmappable validation errors:**\n\n\`\`\`json\n${JSON.stringify(unmappableErrors, null, 2)}\n\`\`\``;
106
- }
107
-
108
- return `\`\`\`json\n${jsonOutput}\n\`\`\``;
109
- }
110
-
111
- function stringify(props: {
112
- value: unknown;
113
- errors: IValidation.IError[];
114
- path: string;
115
- tab: number;
116
- inArray: boolean;
117
- inToJson: boolean;
118
- usedErrors: Set<IValidation.IError>;
119
- }): string {
120
- const { value, errors, path, tab, inArray, inToJson, usedErrors } = props;
121
- const indent: string = " ".repeat(tab);
122
- const errorComment: string = getErrorComment(path, errors, usedErrors);
123
-
124
- // Handle undefined in arrays
125
- if (inArray && value === undefined) {
126
- return `${indent}undefined${errorComment}`;
127
- }
128
-
129
- // Array
130
- if (Array.isArray(value)) {
131
- // Check for missing array element errors (path[])
132
- const missingElementErrors = getMissingArrayElementErrors(
133
- path,
134
- errors,
135
- usedErrors,
136
- );
137
- const hasMissingElements = missingElementErrors.length > 0;
138
-
139
- if (value.length === 0) {
140
- // Empty array but has missing element errors - show placeholders
141
- if (hasMissingElements) {
142
- const innerIndent = " ".repeat(tab + 1);
143
- const lines: string[] = [];
144
- lines.push(`${indent}[${errorComment}`);
145
- missingElementErrors.forEach((e, idx) => {
146
- const errComment = ` // ❌ ${JSON.stringify([{ path: e.path, expected: e.expected, description: e.description }])}`;
147
- const comma = idx < missingElementErrors.length - 1 ? "," : "";
148
- lines.push(`${innerIndent}undefined${comma}${errComment}`);
149
- });
150
- lines.push(`${indent}]`);
151
- return lines.join("\n");
152
- }
153
- return `${indent}[]${errorComment}`;
154
- }
155
-
156
- const lines: string[] = [];
157
- lines.push(`${indent}[${errorComment}`);
158
-
159
- value.forEach((item: unknown, index: number) => {
160
- const itemPath: string = `${path}[${index}]`;
161
- const isLastElement = index === value.length - 1;
162
- // If there are missing element errors, this is not truly the last line
163
- const needsComma = !isLastElement || hasMissingElements;
164
-
165
- let itemStr: string = stringify({
166
- value: item,
167
- errors,
168
- path: itemPath,
169
- tab: tab + 1,
170
- inArray: true,
171
- inToJson: false,
172
- usedErrors,
173
- });
174
- // Add comma before the error comment if not the last element
175
- if (needsComma) {
176
- const itemLines: string[] = itemStr.split("\n");
177
- const lastLine: string = itemLines[itemLines.length - 1]!;
178
- const commentIndex: number = lastLine.indexOf(" //");
179
- if (commentIndex !== -1) {
180
- itemLines[itemLines.length - 1] = `${lastLine.slice(
181
- 0,
182
- commentIndex,
183
- )},${lastLine.slice(commentIndex)}`;
184
- }
185
- else {
186
- itemLines[itemLines.length - 1] += ",";
187
- }
188
- itemStr = itemLines.join("\n");
189
- }
190
- lines.push(itemStr);
191
- });
192
-
193
- // Add missing element placeholders at the end for each [] error
194
- if (hasMissingElements) {
195
- const innerIndent = " ".repeat(tab + 1);
196
- missingElementErrors.forEach((e, idx) => {
197
- const errComment = ` // ❌ ${JSON.stringify([{ path: e.path, expected: e.expected, description: e.description }])}`;
198
- const comma = idx < missingElementErrors.length - 1 ? "," : "";
199
- lines.push(`${innerIndent}undefined${comma}${errComment}`);
200
- });
201
- }
202
-
203
- lines.push(`${indent}]`);
204
- return lines.join("\n");
205
- }
206
-
207
- // Object
208
- if (typeof value === "object" && value !== null) {
209
- // Check for toJSON method
210
- if (!inToJson && typeof (value as any).toJSON === "function") {
211
- const jsonValue: unknown = (value as any).toJSON();
212
- return stringify({
213
- value: jsonValue,
214
- errors,
215
- path,
216
- tab,
217
- inArray,
218
- inToJson: true,
219
- usedErrors,
220
- });
221
- }
222
-
223
- // Get all entries from the object (including undefined values that have errors)
224
- const allEntries: [string, unknown][] = Object.entries(value);
225
-
226
- // Split into defined and undefined entries
227
- const definedEntries: [string, unknown][] = allEntries.filter(
228
- ([_, val]) => val !== undefined,
229
- );
230
- const undefinedEntryKeys: Set<string> = new Set(
231
- allEntries.filter(([_, val]) => val === undefined).map(([key]) => key),
232
- );
233
-
234
- // Find missing properties that have validation errors (not in object at all)
235
- const missingKeys: string[] = getMissingProperties(path, value, errors);
236
-
237
- // Combine: defined entries + undefined entries with errors + missing properties
238
- const undefinedKeysWithErrors: string[] = Array.from(
239
- undefinedEntryKeys,
240
- ).filter((key) => {
241
- const propPath = Escaper.variable(key)
242
- ? `${path}.${key}`
243
- : `${path}[${JSON.stringify(key)}]`;
244
- return errors.some(e => e.path.startsWith(propPath));
245
- });
246
-
247
- const allKeys: string[] = [
248
- ...definedEntries.map(([key]) => key),
249
- ...undefinedKeysWithErrors,
250
- ...missingKeys,
251
- ];
252
-
253
- if (allKeys.length === 0) {
254
- return `${indent}{}${errorComment}`;
255
- }
256
-
257
- const lines: string[] = [];
258
- lines.push(`${indent}{${errorComment}`);
259
-
260
- allKeys.forEach((key, index, array) => {
261
- const propPath: string = Escaper.variable(key)
262
- ? `${path}.${key}`
263
- : `${path}[${JSON.stringify(key)}]`;
264
- const propIndent: string = " ".repeat(tab + 1);
265
-
266
- // Get the value (undefined for missing properties or undefined entries)
267
- const val: unknown
268
- = missingKeys.includes(key) || undefinedKeysWithErrors.includes(key)
269
- ? undefined
270
- : (value as any)[key];
271
-
272
- // Primitive property value (including undefined for missing properties)
273
- if (
274
- val === undefined
275
- || val === null
276
- || typeof val === "boolean"
277
- || typeof val === "number"
278
- || typeof val === "string"
279
- ) {
280
- const propErrorComment: string = getErrorComment(
281
- propPath,
282
- errors,
283
- usedErrors,
284
- );
285
- const keyStr: string = JSON.stringify(key);
286
- const valueStr: string
287
- = val === undefined
288
- ? `${propIndent}${keyStr}: undefined`
289
- : `${propIndent}${keyStr}: ${JSON.stringify(val)}`;
290
- const withComma: string
291
- = index < array.length - 1 ? `${valueStr},` : valueStr;
292
- const line: string = withComma + propErrorComment;
293
- lines.push(line);
294
- }
295
- // Complex property value (object or array)
296
- else {
297
- const keyLine: string = `${propIndent}${JSON.stringify(key)}: `;
298
- let valStr: string = stringify({
299
- value: val,
300
- errors,
301
- path: propPath,
302
- tab: tab + 1,
303
- inArray: false,
304
- inToJson: false,
305
- usedErrors,
306
- });
307
- const valStrWithoutIndent: string = valStr.trimStart();
308
- // Add comma before the error comment if not the last property
309
- if (index < array.length - 1) {
310
- const valLines: string[] = valStrWithoutIndent.split("\n");
311
- const lastLine: string = valLines[valLines.length - 1]!;
312
- const commentIndex: number = lastLine.indexOf(" //");
313
- if (commentIndex !== -1) {
314
- valLines[valLines.length - 1] = `${lastLine.slice(
315
- 0,
316
- commentIndex,
317
- )},${lastLine.slice(commentIndex)}`;
318
- }
319
- else {
320
- valLines[valLines.length - 1] += ",";
321
- }
322
- valStr = valLines.join("\n");
323
- }
324
- else {
325
- valStr = valStrWithoutIndent;
326
- }
327
- const combined: string = keyLine + valStr;
328
- lines.push(combined);
329
- }
330
- });
331
-
332
- lines.push(`${indent}}`);
333
- return lines.join("\n");
334
- }
335
-
336
- // Primitive types (null, boolean, number, string, undefined, etc.)
337
- const valStr: string
338
- = value === undefined
339
- ? "undefined"
340
- : (JSON.stringify(value) ?? String(value));
341
- return `${indent}${valStr}${errorComment}`;
342
- }
343
-
344
- /** Get error comment for a given path */
345
- function getErrorComment(
346
- path: string,
347
- errors: IValidation.IError[],
348
- usedErrors: Set<IValidation.IError>,
349
- ): string {
350
- const pathErrors: IValidation.IError[] = errors.filter(
351
- (e: IValidation.IError) => e.path === path,
352
- );
353
- if (pathErrors.length === 0) {
354
- return "";
355
- }
356
-
357
- // Mark these errors as used
358
- pathErrors.forEach(e => usedErrors.add(e));
359
-
360
- return ` // ❌ ${JSON.stringify(
361
- pathErrors.map(e => ({
362
- path: e.path,
363
- expected: e.expected,
364
- description: e.description,
365
- })),
366
- )}`;
367
- }
368
-
369
- /**
370
- * Check if there are missing array element errors (path ending with []) Returns
371
- * an array of error objects, one per missing element
372
- */
373
- function getMissingArrayElementErrors(
374
- path: string,
375
- errors: IValidation.IError[],
376
- usedErrors: Set<IValidation.IError>,
377
- ): IValidation.IError[] {
378
- const wildcardPath = `${path}[]`;
379
- const missingErrors = errors.filter(e => e.path === wildcardPath);
380
-
381
- // Mark these errors as used
382
- missingErrors.forEach(e => usedErrors.add(e));
383
-
384
- return missingErrors;
385
- }
386
-
387
- /**
388
- * Find missing properties that have validation errors but don't exist in the
389
- * data Returns array of property keys that should be displayed as undefined
390
- */
391
- function getMissingProperties(
392
- path: string,
393
- value: object,
394
- errors: IValidation.IError[],
395
- ): string[] {
396
- const missingKeys: Set<string> = new Set();
397
-
398
- for (const e of errors) {
399
- // Check if error.path is a direct child of current path
400
- const childKey = extractDirectChildKey(path, e.path);
401
- if (childKey !== null) {
402
- // Check if this property actually exists in the value
403
- if (!(childKey in value)) {
404
- missingKeys.add(childKey);
405
- }
406
- }
407
- }
408
-
409
- return Array.from(missingKeys);
410
- }
411
-
412
- /**
413
- * Extract direct child property key if errorPath is a direct child of
414
- * parentPath Returns null if not a direct child
415
- *
416
- * Examples:
417
- *
418
- * - ExtractDirectChildKey("$input", "$input.email") => "email"
419
- * - ExtractDirectChildKey("$input", "$input.user.email") => null (grandchild)
420
- * - ExtractDirectChildKey("$input.user", "$input.user.email") => "email"
421
- * - ExtractDirectChildKey("$input", "$input[0]") => null (array index, not object
422
- * property)
423
- * - ExtractDirectChildKey("$input", "$input["foo-bar"]") => "foo-bar"
424
- * - ExtractDirectChildKey("$input", "$input["foo"]["bar"]") => null (grandchild)
425
- */
426
- function extractDirectChildKey(
427
- parentPath: string,
428
- errorPath: string,
429
- ): string | null {
430
- if (!errorPath.startsWith(parentPath)) {
431
- return null;
432
- }
433
-
434
- const suffix = errorPath.slice(parentPath.length);
435
-
436
- // Match ".propertyName" pattern (direct child property with dot notation)
437
- // Should not contain additional dots or brackets after the property name
438
- const dotMatch = suffix.match(/^\.([^.[\]]+)$/);
439
- if (dotMatch !== null) {
440
- return dotMatch[1]!;
441
- }
442
-
443
- // Match '["key"]' pattern (direct child property with bracket notation)
444
- // The key is a JSON-encoded string
445
- const bracketMatch = suffix.match(/^\[("[^"\\]*(?:\\.[^"\\]*)*")\]$/);
446
- if (bracketMatch !== null) {
447
- try {
448
- const parsed = JSON.parse(bracketMatch[1]!);
449
- // Ensure it's a string key, not a number (array index)
450
- if (typeof parsed === "string") {
451
- return parsed;
452
- }
453
- }
454
- catch {
455
- // Invalid JSON, ignore
456
- }
457
- }
458
-
459
- return null;
460
- }