ondc-code-generator 0.6.22 → 0.7.0

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 (31) hide show
  1. package/.github/copilot-instructions.md +128 -0
  2. package/GOLANG_IMPLEMENTATION.md +156 -0
  3. package/README.md +4 -1
  4. package/alpha/possible-json-paths.json +3734 -0
  5. package/dist/generator/config-compiler.js +6 -0
  6. package/dist/generator/generators/golang/go-ast.d.ts +1 -0
  7. package/dist/generator/generators/golang/go-ast.js +60 -0
  8. package/dist/generator/generators/golang/go-generator.d.ts +23 -0
  9. package/dist/generator/generators/golang/go-generator.js +511 -0
  10. package/dist/generator/generators/golang/templates/api-test.mustache +48 -0
  11. package/dist/generator/generators/golang/templates/json-normalizer.mustache +46 -0
  12. package/dist/generator/generators/golang/templates/json-path-utils.mustache +21 -0
  13. package/dist/generator/generators/golang/templates/storage-templates/api-save.mustache +30 -0
  14. package/dist/generator/generators/golang/templates/storage-templates/index.mustache +41 -0
  15. package/dist/generator/generators/golang/templates/storage-templates/save-utils.mustache +37 -0
  16. package/dist/generator/generators/golang/templates/storage-templates/storage-helpers.mustache +51 -0
  17. package/dist/generator/generators/golang/templates/storage-templates/storage-interface.mustache +96 -0
  18. package/dist/generator/generators/golang/templates/storage-templates/storage-types.mustache +15 -0
  19. package/dist/generator/generators/golang/templates/test-config.mustache +39 -0
  20. package/dist/generator/generators/golang/templates/test-object.mustache +39 -0
  21. package/dist/generator/generators/golang/templates/validation-code.mustache +51 -0
  22. package/dist/generator/generators/golang/templates/validation-utils.mustache +246 -0
  23. package/dist/index.d.ts +2 -1
  24. package/dist/index.js +2 -1
  25. package/dist/index.test.js +7 -1
  26. package/dist/types/compiler-types.d.ts +2 -1
  27. package/dist/types/compiler-types.js +1 -0
  28. package/dist/utils/fs-utils.js +40 -0
  29. package/package.json +1 -1
  30. package/sample.md +273 -0
  31. package/test-python-session.js +0 -0
@@ -0,0 +1,246 @@
1
+ package utils
2
+
3
+ import (
4
+ "fmt"
5
+ "regexp"
6
+ "strconv"
7
+ "time"
8
+ )
9
+
10
+ // UNUSED suppresses "declared and not used" compiler errors
11
+ func UNUSED(x ...interface{}) {}
12
+
13
+ // toString converts interface{} to string representation
14
+ func toString(v interface{}) string {
15
+ if v == nil {
16
+ return "null"
17
+ }
18
+ return fmt.Sprintf("%v", v)
19
+ }
20
+
21
+ // AreUnique checks if all values in the slice are unique
22
+ func AreUnique(operand []interface{}) bool {
23
+ seen := make(map[string]bool)
24
+ for _, v := range operand {
25
+ s := toString(v)
26
+ if seen[s] {
27
+ return false
28
+ }
29
+ seen[s] = true
30
+ }
31
+ return true
32
+ }
33
+
34
+ // ArePresent checks if there are no null, undefined, or empty strings in the slice
35
+ func ArePresent(operand []interface{}) bool {
36
+ return NoneIn(operand, []interface{}{"null", "undefined", ""}) && len(operand) > 0
37
+ }
38
+
39
+ // AllIn checks if all values in left are present in right
40
+ func AllIn(left, right []interface{}) bool {
41
+ if len(left) == 0 && len(right) != 0 {
42
+ return false
43
+ }
44
+ rightMap := make(map[string]bool)
45
+ for _, v := range right {
46
+ rightMap[toString(v)] = true
47
+ }
48
+ for _, v := range left {
49
+ if !rightMap[toString(v)] {
50
+ return false
51
+ }
52
+ }
53
+ return true
54
+ }
55
+
56
+ // AnyIn checks if any value in left is present in right
57
+ func AnyIn(left, right []interface{}) bool {
58
+ if len(left) == 0 && len(right) != 0 {
59
+ return false
60
+ }
61
+ rightMap := make(map[string]bool)
62
+ for _, v := range right {
63
+ rightMap[toString(v)] = true
64
+ }
65
+ for _, v := range left {
66
+ if rightMap[toString(v)] {
67
+ return true
68
+ }
69
+ }
70
+ return false
71
+ }
72
+
73
+ // NoneIn checks if none of the values in left are present in right
74
+ func NoneIn(left, right []interface{}) bool {
75
+ rightMap := make(map[string]bool)
76
+ for _, v := range right {
77
+ rightMap[toString(v)] = true
78
+ }
79
+ for _, v := range left {
80
+ if rightMap[toString(v)] {
81
+ return false
82
+ }
83
+ }
84
+ return true
85
+ }
86
+
87
+ // EqualTo checks if left and right are equal (same values in same order)
88
+ func EqualTo(left, right []interface{}) bool {
89
+ if len(left) != len(right) {
90
+ return false
91
+ }
92
+ for i, v := range left {
93
+ if toString(v) != toString(right[i]) {
94
+ return false
95
+ }
96
+ }
97
+ return true
98
+ }
99
+
100
+ // isISO8601 checks if a string is in ISO 8601 format
101
+ func isISO8601(s string) bool {
102
+ iso8601Regex := `^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$`
103
+ matched, _ := regexp.MatchString(iso8601Regex, s)
104
+ if !matched {
105
+ return false
106
+ }
107
+ _, err := time.Parse(time.RFC3339, s)
108
+ return err == nil
109
+ }
110
+
111
+ // isNumber checks if a string can be parsed as a number
112
+ func isNumber(s string) bool {
113
+ _, err := strconv.ParseFloat(s, 64)
114
+ return err == nil
115
+ }
116
+
117
+ // areAllISO checks if all values in the slice are ISO 8601 dates
118
+ func areAllISO(arr []interface{}) bool {
119
+ for _, v := range arr {
120
+ if !isISO8601(toString(v)) {
121
+ return false
122
+ }
123
+ }
124
+ return true
125
+ }
126
+
127
+ // areAllNumbers checks if all values in the slice are numbers
128
+ func areAllNumbers(arr []interface{}) bool {
129
+ for _, v := range arr {
130
+ if !isNumber(toString(v)) {
131
+ return false
132
+ }
133
+ }
134
+ return true
135
+ }
136
+
137
+ // GreaterThan checks if all values in left are greater than corresponding values in right
138
+ func GreaterThan(left, right []interface{}) bool {
139
+ if areAllISO(left) && areAllISO(right) {
140
+ leftDates := make([]time.Time, len(left))
141
+ rightDates := make([]time.Time, len(right))
142
+
143
+ for i, d := range left {
144
+ leftDates[i], _ = time.Parse(time.RFC3339, toString(d))
145
+ }
146
+ for i, d := range right {
147
+ rightDates[i], _ = time.Parse(time.RFC3339, toString(d))
148
+ }
149
+
150
+ for i, ld := range leftDates {
151
+ if i >= len(rightDates) {
152
+ continue
153
+ }
154
+ if !ld.After(rightDates[i]) {
155
+ return false
156
+ }
157
+ }
158
+ return true
159
+ } else if areAllNumbers(left) && areAllNumbers(right) {
160
+ leftNumbers := make([]float64, len(left))
161
+ rightNumbers := make([]float64, len(right))
162
+
163
+ for i, n := range left {
164
+ leftNumbers[i], _ = strconv.ParseFloat(toString(n), 64)
165
+ }
166
+ for i, n := range right {
167
+ rightNumbers[i], _ = strconv.ParseFloat(toString(n), 64)
168
+ }
169
+
170
+ for i, ln := range leftNumbers {
171
+ if i >= len(rightNumbers) {
172
+ continue
173
+ }
174
+ if ln <= rightNumbers[i] {
175
+ return false
176
+ }
177
+ }
178
+ return true
179
+ }
180
+ return false
181
+ }
182
+
183
+ // LessThan checks if all values in left are less than corresponding values in right
184
+ func LessThan(left, right []interface{}) bool {
185
+ if areAllISO(left) && areAllISO(right) {
186
+ leftDates := make([]time.Time, len(left))
187
+ rightDates := make([]time.Time, len(right))
188
+
189
+ for i, d := range left {
190
+ leftDates[i], _ = time.Parse(time.RFC3339, toString(d))
191
+ }
192
+ for i, d := range right {
193
+ rightDates[i], _ = time.Parse(time.RFC3339, toString(d))
194
+ }
195
+
196
+ for i, ld := range leftDates {
197
+ if i >= len(rightDates) {
198
+ continue
199
+ }
200
+ if !ld.Before(rightDates[i]) {
201
+ return false
202
+ }
203
+ }
204
+ return true
205
+ } else if areAllNumbers(left) && areAllNumbers(right) {
206
+ leftNumbers := make([]float64, len(left))
207
+ rightNumbers := make([]float64, len(right))
208
+
209
+ for i, n := range left {
210
+ leftNumbers[i], _ = strconv.ParseFloat(toString(n), 64)
211
+ }
212
+ for i, n := range right {
213
+ rightNumbers[i], _ = strconv.ParseFloat(toString(n), 64)
214
+ }
215
+
216
+ for i, ln := range leftNumbers {
217
+ if i >= len(rightNumbers) {
218
+ continue
219
+ }
220
+ if ln >= rightNumbers[i] {
221
+ return false
222
+ }
223
+ }
224
+ return true
225
+ }
226
+ return false
227
+ }
228
+
229
+ // FollowRegex checks if all values in left match all regex patterns in regexArray
230
+ func FollowRegex(left, regexArray []interface{}) bool {
231
+ if len(left) == 0 && len(regexArray) != 0 {
232
+ return false
233
+ }
234
+ for _, pattern := range regexArray {
235
+ re, err := regexp.Compile(toString(pattern))
236
+ if err != nil {
237
+ return false
238
+ }
239
+ for _, v := range left {
240
+ if !re.MatchString(toString(v)) {
241
+ return false
242
+ }
243
+ }
244
+ }
245
+ return true
246
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  import { ConfigCompiler } from "./generator/config-compiler.js";
2
- export { ConfigCompiler };
2
+ import { SupportedLanguages } from "./types/compiler-types.js";
3
+ export { ConfigCompiler, SupportedLanguages };
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  import { ConfigCompiler } from "./generator/config-compiler.js";
2
- export { ConfigCompiler };
2
+ import { SupportedLanguages } from "./types/compiler-types.js";
3
+ export { ConfigCompiler, SupportedLanguages };
@@ -1,4 +1,4 @@
1
- import { readFileSync } from "fs";
1
+ import { readFileSync, writeFileSync } from "fs";
2
2
  import path from "path";
3
3
  import { fileURLToPath } from "url";
4
4
  import { ConfigCompiler } from "./generator/config-compiler.js";
@@ -12,10 +12,16 @@ const main = async () => {
12
12
  const buildYaml = readFileSync(buildPath, "utf-8");
13
13
  const valConfig = JSON.parse(readFileSync(valConfigPath, "utf-8"));
14
14
  await compiler.initialize(buildYaml);
15
+ const validPaths = await compiler.generateValidPaths();
16
+ writeFileSync(path.resolve(__dirname, "../alpha/possible-json-paths.json"), JSON.stringify(validPaths, null, 2), "utf-8");
15
17
  await compiler.generateCode(valConfig, "L1_validations", false, "./alpha/python/");
16
18
  const compilerTy = new ConfigCompiler(SupportedLanguages.Typescript);
17
19
  await compilerTy.initialize(buildYaml);
18
20
  await compilerTy.generateCode(valConfig, "L1_validations", false, "./alpha/typescript/");
21
+ await compilerTy.generateL0Schema("./alpha/typescript/L0_schema/");
22
+ const compilerGo = new ConfigCompiler(SupportedLanguages.Golang);
23
+ await compilerGo.initialize(buildYaml);
24
+ await compilerGo.generateCode(valConfig, "L1_validations", false, "./alpha/golang/");
19
25
  // JavaScript generation example
20
26
  // const compilerJs = new ConfigCompiler(SupportedLanguages.Javascript);
21
27
  // await compilerJs.initialize(buildYaml);
@@ -1,5 +1,6 @@
1
1
  export declare enum SupportedLanguages {
2
2
  Typescript = "typescript",
3
3
  Python = "python",
4
- Javascript = "javascript"
4
+ Javascript = "javascript",
5
+ Golang = "golang"
5
6
  }
@@ -3,4 +3,5 @@ export var SupportedLanguages;
3
3
  SupportedLanguages["Typescript"] = "typescript";
4
4
  SupportedLanguages["Python"] = "python";
5
5
  SupportedLanguages["Javascript"] = "javascript";
6
+ SupportedLanguages["Golang"] = "golang";
6
7
  })(SupportedLanguages || (SupportedLanguages = {}));
@@ -17,6 +17,10 @@ export async function formatCode(code, lang) {
17
17
  // Basic Python formatting - clean up extra whitespace and blank lines
18
18
  return formatPythonCode(code);
19
19
  }
20
+ if (lang === "go") {
21
+ // Basic Go formatting - clean up extra whitespace and blank lines
22
+ return formatGoCode(code);
23
+ }
20
24
  return await prettier.format(code, {
21
25
  parser: lang,
22
26
  tabWidth: 4,
@@ -57,6 +61,42 @@ function formatPythonCode(code) {
57
61
  }
58
62
  return cleanedLines.join("\n") + "\n";
59
63
  }
64
+ function formatGoCode(code) {
65
+ // Similar to Python formatting - basic cleanup
66
+ const lines = code.split("\n");
67
+ const formattedLines = [];
68
+ for (let i = 0; i < lines.length; i++) {
69
+ const line = lines[i];
70
+ // Skip lines that are only whitespace
71
+ if (line.trim() === "") {
72
+ // Only add empty line if the previous line wasn't empty
73
+ if (formattedLines.length > 0 &&
74
+ formattedLines[formattedLines.length - 1].trim() !== "") {
75
+ formattedLines.push("");
76
+ }
77
+ continue;
78
+ }
79
+ // Add the line as-is (preserve existing indentation)
80
+ formattedLines.push(line);
81
+ }
82
+ // Remove multiple consecutive empty lines
83
+ const cleanedLines = [];
84
+ let lastWasEmpty = false;
85
+ for (const line of formattedLines) {
86
+ const isEmpty = line.trim() === "";
87
+ if (isEmpty && lastWasEmpty) {
88
+ continue; // Skip consecutive empty lines
89
+ }
90
+ cleanedLines.push(line);
91
+ lastWasEmpty = isEmpty;
92
+ }
93
+ // Remove trailing empty lines
94
+ while (cleanedLines.length > 0 &&
95
+ cleanedLines[cleanedLines.length - 1].trim() === "") {
96
+ cleanedLines.pop();
97
+ }
98
+ return cleanedLines.join("\n") + "\n";
99
+ }
60
100
  export async function writeAndFormatCode(rootPath, relativeFilePath, content, lang) {
61
101
  const formattedCode = await formatCode(content, lang);
62
102
  writeFileWithFsExtra(rootPath, relativeFilePath, formattedCode);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ondc-code-generator",
3
- "version": "0.6.22",
3
+ "version": "0.7.0",
4
4
  "description": "generate code from build.yaml ",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
package/sample.md ADDED
@@ -0,0 +1,273 @@
1
+ # JVAL DSL Best Practices & Naming Conventions
2
+
3
+ ## Overview
4
+
5
+ This document outlines best practices for writing effective JVAL (JSON Validation Language) configurations for the ONDC Code Generator.
6
+
7
+ ## Naming Conventions
8
+
9
+ ### Test Object Names (`_NAME_`)
10
+
11
+ - **Use snake_case** for consistency with generated function names
12
+ - **Be descriptive and specific** about what the test validates
13
+ - **Include context** when validating nested objects
14
+
15
+ ```json
16
+ // ✅ Good
17
+ "_NAME_": "validate_context_action_search"
18
+ "_NAME_": "check_provider_locations_present"
19
+ "_NAME_": "verify_payment_settlement_terms"
20
+
21
+ // ❌ Avoid
22
+ "_NAME_": "test1"
23
+ "_NAME_": "checkAction"
24
+ "_NAME_": "validate"
25
+ ```
26
+
27
+ ### Variable Names
28
+
29
+ - **Use descriptive names** that clearly indicate the data being extracted
30
+ - **Follow snake_case** convention
31
+ - **Include data type hints** when helpful (e.g., `_codes`, `_ids`, `_values`)
32
+
33
+ ```json
34
+ // ✅ Good
35
+ "context_action": "$.context.action",
36
+ "provider_location_codes": "$.message.catalog.providers[*].locations[*].id",
37
+ "settlement_terms": "$.message.order.tags[?(@.descriptor.code=='SETTLEMENT_TERMS')].list[*].code"
38
+
39
+ // ❌ Avoid
40
+ "var1": "$.context.action",
41
+ "x": "$.message.catalog.providers[*].locations[*].id",
42
+ "data": "$.some.path"
43
+ ```
44
+
45
+ ### Test Set Names
46
+
47
+ - **Use lowercase with underscores** for test set keys
48
+ - **Group by API action** or logical functionality
49
+ - **Be specific about the validation scope**
50
+
51
+ ```json
52
+ // ✅ Good
53
+ "search_validations": [...],
54
+ "on_search_catalog_validations": [...],
55
+ "payment_settlement_checks": [...]
56
+
57
+ // ❌ Avoid
58
+ "Search": [...],
59
+ "tests": [...],
60
+ "validations": [...]
61
+ ```
62
+
63
+ ## JSONPath Best Practices
64
+
65
+ ### Path Structure
66
+
67
+ - **Always start with `$`** for root-level paths
68
+ - **Use specific filters** instead of broad wildcards when possible
69
+ - **Test paths** with sample data before implementation
70
+
71
+ ```json
72
+ // ✅ Good - Specific filtering
73
+ "settlement_codes": "$.message.order.tags[?(@.descriptor.code=='SETTLEMENT_TERMS')].list[*].code"
74
+
75
+ // ⚠️ Less optimal - Too broad
76
+ "all_codes": "$.message..code"
77
+ ```
78
+
79
+ ### Scoping Strategy
80
+
81
+ - **Use `_SCOPE_`** to iterate over arrays of objects
82
+ - **Keep variables relative** to the scope when possible
83
+ - **Avoid deep nesting** in scoped validations
84
+
85
+ ```json
86
+ // ✅ Good - Proper scoping
87
+ {
88
+ "_SCOPE_": "$.message.catalog.providers[*]",
89
+ "provider_id": "$.id",
90
+ "location_ids": "$.locations[*].id",
91
+ "_RETURN_": "provider_id are present && location_ids are present"
92
+ }
93
+
94
+ // ❌ Avoid - Absolute paths in scope
95
+ {
96
+ "_SCOPE_": "$.message.catalog.providers[*]",
97
+ "provider_id": "$.message.catalog.providers[*].id", // Redundant
98
+ "_RETURN_": "provider_id are present"
99
+ }
100
+ ```
101
+
102
+ ## JVAL Expression Guidelines
103
+
104
+ ### Readability
105
+
106
+ - **Use parentheses** to clarify complex logic
107
+ - **Break complex expressions** into multiple test objects
108
+ - **Write descriptive variable names** that make expressions self-documenting
109
+
110
+ ```json
111
+ // ✅ Good - Clear logic flow
112
+ "_RETURN_": "(context_action are present) && (context_action all in valid_actions)"
113
+
114
+ // ✅ Good - Complex logic broken down
115
+ "_RETURN_": [
116
+ {
117
+ "_NAME_": "check_required_fields",
118
+ "context_action": "$.context.action",
119
+ "message_intent": "$.message.intent",
120
+ "_RETURN_": "context_action are present && message_intent are present"
121
+ },
122
+ {
123
+ "_NAME_": "validate_action_values",
124
+ "context_action": "$.context.action",
125
+ "valid_actions": ["search", "select", "init"],
126
+ "_RETURN_": "context_action all in valid_actions"
127
+ }
128
+ ]
129
+ ```
130
+
131
+ ### Error Handling
132
+
133
+ - **Always provide `_DESCRIPTION_`** for meaningful error messages
134
+ - **Use consistent error codes** within logical groups
135
+ - **Make descriptions actionable** for developers
136
+
137
+ ```json
138
+ // ✅ Good - Clear, actionable descriptions
139
+ {
140
+ "_NAME_": "validate_context_action_search",
141
+ "context_action": "$.context.action",
142
+ "valid_actions": ["search"],
143
+ "_ERROR_CODE_": 30001,
144
+ "_DESCRIPTION_": "context.action must be 'search' for search API calls",
145
+ "_RETURN_": "context_action all in valid_actions"
146
+ }
147
+ ```
148
+
149
+ ## Configuration Structure
150
+
151
+ ### Test Organization
152
+
153
+ - **Group related validations** in the same test set
154
+ - **Order tests logically** (basic → complex)
155
+ - **Use consistent error code ranges** per validation group
156
+
157
+ ```json
158
+ {
159
+ "x-validations": {
160
+ "_TESTS_": {
161
+ "basic_structure_validations": [
162
+ // Basic field presence checks first
163
+ ],
164
+ "business_logic_validations": [
165
+ // Complex business rules second
166
+ ],
167
+ "cross_field_validations": [
168
+ // Inter-field dependency checks last
169
+ ]
170
+ },
171
+ "_SESSION_DATA_": {
172
+ "search": {
173
+ "transaction_id": "$.context.transaction_id"
174
+ }
175
+ }
176
+ }
177
+ }
178
+ ```
179
+
180
+ ## Example: Complete Validation Set
181
+
182
+ ```json
183
+ {
184
+ "x-validations": {
185
+ "_TESTS_": {
186
+ "search_api_validations": [
187
+ {
188
+ "_NAME_": "validate_required_context_fields",
189
+ "context_action": "$.context.action",
190
+ "context_domain": "$.context.domain",
191
+ "transaction_id": "$.context.transaction_id",
192
+ "_ERROR_CODE_": 30001,
193
+ "_DESCRIPTION_": "Required context fields must be present in search request",
194
+ "_RETURN_": "context_action are present && context_domain are present && transaction_id are present"
195
+ },
196
+ {
197
+ "_NAME_": "validate_search_action_value",
198
+ "context_action": "$.context.action",
199
+ "expected_action": ["search"],
200
+ "_ERROR_CODE_": 30002,
201
+ "_DESCRIPTION_": "context.action must be 'search' for search API calls",
202
+ "_RETURN_": "context_action all in expected_action"
203
+ },
204
+ {
205
+ "_NAME_": "validate_intent_structure",
206
+ "_SCOPE_": "$.message.intent",
207
+ "item_descriptor_name": "$.item.descriptor.name",
208
+ "fulfillment_locations": "$.fulfillment.end.location.area_code",
209
+ "_ERROR_CODE_": 30003,
210
+ "_DESCRIPTION_": "Search intent must contain item descriptor and fulfillment location",
211
+ "_RETURN_": "item_descriptor_name are present || fulfillment_locations are present"
212
+ }
213
+ ]
214
+ },
215
+ "_SESSION_DATA_": {
216
+ "search": {
217
+ "transaction_id": "$.context.transaction_id",
218
+ "domain": "$.context.domain"
219
+ }
220
+ }
221
+ }
222
+ }
223
+ ```
224
+
225
+ ## Common Patterns
226
+
227
+ ### Enum Validation
228
+
229
+ ```json
230
+ {
231
+ "field_value": "$.path.to.field",
232
+ "allowed_values": ["value1", "value2", "value3"],
233
+ "_RETURN_": "field_value all in allowed_values"
234
+ }
235
+ ```
236
+
237
+ ### Presence Validation
238
+
239
+ ```json
240
+ {
241
+ "required_fields": ["$.field1", "$.field2", "$.field3"],
242
+ "_RETURN_": "required_fields are present"
243
+ }
244
+ ```
245
+
246
+ ### Uniqueness Validation
247
+
248
+ ```json
249
+ {
250
+ "_SCOPE_": "$.array.path[*]",
251
+ "id_values": "$.id",
252
+ "_RETURN_": "id_values are unique"
253
+ }
254
+ ```
255
+
256
+ ### Regex Pattern Validation
257
+
258
+ ```json
259
+ {
260
+ "email_field": "$.contact.email",
261
+ "email_pattern": ["^[\\w\\.-]+@[\\w\\.-]+\\.[a-zA-Z]{2,}$"],
262
+ "_RETURN_": "email_field follow regex email_pattern"
263
+ }
264
+ ```
265
+
266
+ ## Anti-Patterns to Avoid
267
+
268
+ 1. **Generic variable names** like `var1`, `data`, `temp`
269
+ 2. **Overly complex single expressions** - break into multiple tests instead
270
+ 3. **Missing error descriptions** - always provide meaningful messages
271
+ 4. **Inconsistent naming** - stick to snake_case throughout
272
+ 5. **Hard-coded values in expressions** - use variables for maintainability
273
+ 6. **Too broad JSONPath selectors** - be as specific as possible
File without changes