@agentica/core 0.43.2 → 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 -18948
  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 -350
  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 -462
@@ -1,462 +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 (Object.keys(parameters.properties).length !== 1) {
42
- return;
43
- }
44
- else if (typeof output !== "object" || output === null) {
45
- return;
46
- }
47
-
48
- const key: string = Object.keys(parameters.properties)[0]!;
49
- const value: any = output[key];
50
- const schema: ILlmSchema = parameters.properties[key]!;
51
- if (
52
- typeof value === "string"
53
- && isInstanceType({
54
- $defs: parameters.$defs,
55
- schema,
56
- }) === true
57
- ) {
58
- try {
59
- output[key] = parse(value);
60
- }
61
- catch {}
62
- }
63
- }
64
-
65
- function isInstanceType(props: {
66
- $defs: Record<string, ILlmSchema>;
67
- schema: ILlmSchema;
68
- }): boolean {
69
- if (LlmTypeChecker.isReference(props.schema)) {
70
- return isInstanceType({
71
- $defs: props.$defs,
72
- schema: props.$defs[props.schema.$ref.split("/").pop()!] ?? {},
73
- });
74
- }
75
- return LlmTypeChecker.isNull(props.schema)
76
- || LlmTypeChecker.isObject(props.schema)
77
- || LlmTypeChecker.isArray(props.schema)
78
- || (
79
- LlmTypeChecker.isAnyOf(props.schema)
80
- && props.schema.anyOf.every(s => isInstanceType({
81
- $defs: props.$defs,
82
- schema: s,
83
- }))
84
- );
85
- }
86
-
87
- function stringifyValidationFailure(
88
- failure: IValidation.IFailure,
89
- ): string {
90
- const usedErrors = new Set<IValidation.IError>();
91
-
92
- const jsonOutput = stringify({
93
- value: failure.data,
94
- errors: failure.errors,
95
- path: "$input",
96
- tab: 0,
97
- inArray: false,
98
- inToJson: false,
99
- usedErrors,
100
- });
101
-
102
- // Find errors that couldn't be embedded
103
- const unmappableErrors = failure.errors.filter(e => !usedErrors.has(e));
104
-
105
- // If there are unmappable errors, append them as a separate block
106
- if (unmappableErrors.length > 0) {
107
- return `\`\`\`json\n${jsonOutput}\n\`\`\`\n\n**Unmappable validation errors:**\n\n\`\`\`json\n${JSON.stringify(unmappableErrors, null, 2)}\n\`\`\``;
108
- }
109
-
110
- return `\`\`\`json\n${jsonOutput}\n\`\`\``;
111
- }
112
-
113
- function stringify(props: {
114
- value: unknown;
115
- errors: IValidation.IError[];
116
- path: string;
117
- tab: number;
118
- inArray: boolean;
119
- inToJson: boolean;
120
- usedErrors: Set<IValidation.IError>;
121
- }): string {
122
- const { value, errors, path, tab, inArray, inToJson, usedErrors } = props;
123
- const indent: string = " ".repeat(tab);
124
- const errorComment: string = getErrorComment(path, errors, usedErrors);
125
-
126
- // Handle undefined in arrays
127
- if (inArray && value === undefined) {
128
- return `${indent}undefined${errorComment}`;
129
- }
130
-
131
- // Array
132
- if (Array.isArray(value)) {
133
- // Check for missing array element errors (path[])
134
- const missingElementErrors = getMissingArrayElementErrors(
135
- path,
136
- errors,
137
- usedErrors,
138
- );
139
- const hasMissingElements = missingElementErrors.length > 0;
140
-
141
- if (value.length === 0) {
142
- // Empty array but has missing element errors - show placeholders
143
- if (hasMissingElements) {
144
- const innerIndent = " ".repeat(tab + 1);
145
- const lines: string[] = [];
146
- lines.push(`${indent}[${errorComment}`);
147
- missingElementErrors.forEach((e, idx) => {
148
- const errComment = ` // ❌ ${JSON.stringify([{ path: e.path, expected: e.expected, description: e.description }])}`;
149
- const comma = idx < missingElementErrors.length - 1 ? "," : "";
150
- lines.push(`${innerIndent}undefined${comma}${errComment}`);
151
- });
152
- lines.push(`${indent}]`);
153
- return lines.join("\n");
154
- }
155
- return `${indent}[]${errorComment}`;
156
- }
157
-
158
- const lines: string[] = [];
159
- lines.push(`${indent}[${errorComment}`);
160
-
161
- value.forEach((item: unknown, index: number) => {
162
- const itemPath: string = `${path}[${index}]`;
163
- const isLastElement = index === value.length - 1;
164
- // If there are missing element errors, this is not truly the last line
165
- const needsComma = !isLastElement || hasMissingElements;
166
-
167
- let itemStr: string = stringify({
168
- value: item,
169
- errors,
170
- path: itemPath,
171
- tab: tab + 1,
172
- inArray: true,
173
- inToJson: false,
174
- usedErrors,
175
- });
176
- // Add comma before the error comment if not the last element
177
- if (needsComma) {
178
- const itemLines: string[] = itemStr.split("\n");
179
- const lastLine: string = itemLines[itemLines.length - 1]!;
180
- const commentIndex: number = lastLine.indexOf(" //");
181
- if (commentIndex !== -1) {
182
- itemLines[itemLines.length - 1] = `${lastLine.slice(
183
- 0,
184
- commentIndex,
185
- )},${lastLine.slice(commentIndex)}`;
186
- }
187
- else {
188
- itemLines[itemLines.length - 1] += ",";
189
- }
190
- itemStr = itemLines.join("\n");
191
- }
192
- lines.push(itemStr);
193
- });
194
-
195
- // Add missing element placeholders at the end for each [] error
196
- if (hasMissingElements) {
197
- const innerIndent = " ".repeat(tab + 1);
198
- missingElementErrors.forEach((e, idx) => {
199
- const errComment = ` // ❌ ${JSON.stringify([{ path: e.path, expected: e.expected, description: e.description }])}`;
200
- const comma = idx < missingElementErrors.length - 1 ? "," : "";
201
- lines.push(`${innerIndent}undefined${comma}${errComment}`);
202
- });
203
- }
204
-
205
- lines.push(`${indent}]`);
206
- return lines.join("\n");
207
- }
208
-
209
- // Object
210
- if (typeof value === "object" && value !== null) {
211
- // Check for toJSON method
212
- if (!inToJson && typeof (value as any).toJSON === "function") {
213
- const jsonValue: unknown = (value as any).toJSON();
214
- return stringify({
215
- value: jsonValue,
216
- errors,
217
- path,
218
- tab,
219
- inArray,
220
- inToJson: true,
221
- usedErrors,
222
- });
223
- }
224
-
225
- // Get all entries from the object (including undefined values that have errors)
226
- const allEntries: [string, unknown][] = Object.entries(value);
227
-
228
- // Split into defined and undefined entries
229
- const definedEntries: [string, unknown][] = allEntries.filter(
230
- ([_, val]) => val !== undefined,
231
- );
232
- const undefinedEntryKeys: Set<string> = new Set(
233
- allEntries.filter(([_, val]) => val === undefined).map(([key]) => key),
234
- );
235
-
236
- // Find missing properties that have validation errors (not in object at all)
237
- const missingKeys: string[] = getMissingProperties(path, value, errors);
238
-
239
- // Combine: defined entries + undefined entries with errors + missing properties
240
- const undefinedKeysWithErrors: string[] = Array.from(
241
- undefinedEntryKeys,
242
- ).filter((key) => {
243
- const propPath = Escaper.variable(key)
244
- ? `${path}.${key}`
245
- : `${path}[${JSON.stringify(key)}]`;
246
- return errors.some(e => e.path.startsWith(propPath));
247
- });
248
-
249
- const allKeys: string[] = [
250
- ...definedEntries.map(([key]) => key),
251
- ...undefinedKeysWithErrors,
252
- ...missingKeys,
253
- ];
254
-
255
- if (allKeys.length === 0) {
256
- return `${indent}{}${errorComment}`;
257
- }
258
-
259
- const lines: string[] = [];
260
- lines.push(`${indent}{${errorComment}`);
261
-
262
- allKeys.forEach((key, index, array) => {
263
- const propPath: string = Escaper.variable(key)
264
- ? `${path}.${key}`
265
- : `${path}[${JSON.stringify(key)}]`;
266
- const propIndent: string = " ".repeat(tab + 1);
267
-
268
- // Get the value (undefined for missing properties or undefined entries)
269
- const val: unknown
270
- = missingKeys.includes(key) || undefinedKeysWithErrors.includes(key)
271
- ? undefined
272
- : (value as any)[key];
273
-
274
- // Primitive property value (including undefined for missing properties)
275
- if (
276
- val === undefined
277
- || val === null
278
- || typeof val === "boolean"
279
- || typeof val === "number"
280
- || typeof val === "string"
281
- ) {
282
- const propErrorComment: string = getErrorComment(
283
- propPath,
284
- errors,
285
- usedErrors,
286
- );
287
- const keyStr: string = JSON.stringify(key);
288
- const valueStr: string
289
- = val === undefined
290
- ? `${propIndent}${keyStr}: undefined`
291
- : `${propIndent}${keyStr}: ${JSON.stringify(val)}`;
292
- const withComma: string
293
- = index < array.length - 1 ? `${valueStr},` : valueStr;
294
- const line: string = withComma + propErrorComment;
295
- lines.push(line);
296
- }
297
- // Complex property value (object or array)
298
- else {
299
- const keyLine: string = `${propIndent}${JSON.stringify(key)}: `;
300
- let valStr: string = stringify({
301
- value: val,
302
- errors,
303
- path: propPath,
304
- tab: tab + 1,
305
- inArray: false,
306
- inToJson: false,
307
- usedErrors,
308
- });
309
- const valStrWithoutIndent: string = valStr.trimStart();
310
- // Add comma before the error comment if not the last property
311
- if (index < array.length - 1) {
312
- const valLines: string[] = valStrWithoutIndent.split("\n");
313
- const lastLine: string = valLines[valLines.length - 1]!;
314
- const commentIndex: number = lastLine.indexOf(" //");
315
- if (commentIndex !== -1) {
316
- valLines[valLines.length - 1] = `${lastLine.slice(
317
- 0,
318
- commentIndex,
319
- )},${lastLine.slice(commentIndex)}`;
320
- }
321
- else {
322
- valLines[valLines.length - 1] += ",";
323
- }
324
- valStr = valLines.join("\n");
325
- }
326
- else {
327
- valStr = valStrWithoutIndent;
328
- }
329
- const combined: string = keyLine + valStr;
330
- lines.push(combined);
331
- }
332
- });
333
-
334
- lines.push(`${indent}}`);
335
- return lines.join("\n");
336
- }
337
-
338
- // Primitive types (null, boolean, number, string, undefined, etc.)
339
- const valStr: string
340
- = value === undefined
341
- ? "undefined"
342
- : (JSON.stringify(value) ?? String(value));
343
- return `${indent}${valStr}${errorComment}`;
344
- }
345
-
346
- /** Get error comment for a given path */
347
- function getErrorComment(
348
- path: string,
349
- errors: IValidation.IError[],
350
- usedErrors: Set<IValidation.IError>,
351
- ): string {
352
- const pathErrors: IValidation.IError[] = errors.filter(
353
- (e: IValidation.IError) => e.path === path,
354
- );
355
- if (pathErrors.length === 0) {
356
- return "";
357
- }
358
-
359
- // Mark these errors as used
360
- pathErrors.forEach(e => usedErrors.add(e));
361
-
362
- return ` // ❌ ${JSON.stringify(
363
- pathErrors.map(e => ({
364
- path: e.path,
365
- expected: e.expected,
366
- description: e.description,
367
- })),
368
- )}`;
369
- }
370
-
371
- /**
372
- * Check if there are missing array element errors (path ending with []) Returns
373
- * an array of error objects, one per missing element
374
- */
375
- function getMissingArrayElementErrors(
376
- path: string,
377
- errors: IValidation.IError[],
378
- usedErrors: Set<IValidation.IError>,
379
- ): IValidation.IError[] {
380
- const wildcardPath = `${path}[]`;
381
- const missingErrors = errors.filter(e => e.path === wildcardPath);
382
-
383
- // Mark these errors as used
384
- missingErrors.forEach(e => usedErrors.add(e));
385
-
386
- return missingErrors;
387
- }
388
-
389
- /**
390
- * Find missing properties that have validation errors but don't exist in the
391
- * data Returns array of property keys that should be displayed as undefined
392
- */
393
- function getMissingProperties(
394
- path: string,
395
- value: object,
396
- errors: IValidation.IError[],
397
- ): string[] {
398
- const missingKeys: Set<string> = new Set();
399
-
400
- for (const e of errors) {
401
- // Check if error.path is a direct child of current path
402
- const childKey = extractDirectChildKey(path, e.path);
403
- if (childKey !== null) {
404
- // Check if this property actually exists in the value
405
- if (!(childKey in value)) {
406
- missingKeys.add(childKey);
407
- }
408
- }
409
- }
410
-
411
- return Array.from(missingKeys);
412
- }
413
-
414
- /**
415
- * Extract direct child property key if errorPath is a direct child of
416
- * parentPath Returns null if not a direct child
417
- *
418
- * Examples:
419
- *
420
- * - ExtractDirectChildKey("$input", "$input.email") => "email"
421
- * - ExtractDirectChildKey("$input", "$input.user.email") => null (grandchild)
422
- * - ExtractDirectChildKey("$input.user", "$input.user.email") => "email"
423
- * - ExtractDirectChildKey("$input", "$input[0]") => null (array index, not object
424
- * property)
425
- * - ExtractDirectChildKey("$input", "$input["foo-bar"]") => "foo-bar"
426
- * - ExtractDirectChildKey("$input", "$input["foo"]["bar"]") => null (grandchild)
427
- */
428
- function extractDirectChildKey(
429
- parentPath: string,
430
- errorPath: string,
431
- ): string | null {
432
- if (!errorPath.startsWith(parentPath)) {
433
- return null;
434
- }
435
-
436
- const suffix = errorPath.slice(parentPath.length);
437
-
438
- // Match ".propertyName" pattern (direct child property with dot notation)
439
- // Should not contain additional dots or brackets after the property name
440
- const dotMatch = suffix.match(/^\.([^.[\]]+)$/);
441
- if (dotMatch !== null) {
442
- return dotMatch[1]!;
443
- }
444
-
445
- // Match '["key"]' pattern (direct child property with bracket notation)
446
- // The key is a JSON-encoded string
447
- const bracketMatch = suffix.match(/^\[("[^"\\]*(?:\\.[^"\\]*)*")\]$/);
448
- if (bracketMatch !== null) {
449
- try {
450
- const parsed = JSON.parse(bracketMatch[1]!);
451
- // Ensure it's a string key, not a number (array index)
452
- if (typeof parsed === "string") {
453
- return parsed;
454
- }
455
- }
456
- catch {
457
- // Invalid JSON, ignore
458
- }
459
- }
460
-
461
- return null;
462
- }