ondc-code-generator 0.8.7 → 0.8.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/alpha/docs/page/index.html +6137 -0
- package/alpha/docs/page/style.css +204 -0
- package/alpha/docs/readme.md +5939 -0
- package/alpha/docs/validPaths.json +14351 -0
- package/alpha/page/index.html +6137 -0
- package/alpha/page/style.css +204 -0
- package/alpha/readme.md +5939 -0
- package/alpha/validPaths.json +11393 -34240
- package/alpha/validationpkg/examples/search.json +143 -0
- package/alpha/validationpkg/examples_output/search/case-001/output.json +12 -0
- package/alpha/validationpkg/go.mod +8 -0
- package/alpha/validationpkg/go.sum +4 -0
- package/alpha/validationpkg/jsonvalidations/cancel.go +1289 -0
- package/alpha/validationpkg/jsonvalidations/confirm.go +9121 -0
- package/alpha/validationpkg/jsonvalidations/init.go +4864 -0
- package/alpha/validationpkg/jsonvalidations/issue.go +4868 -0
- package/alpha/validationpkg/jsonvalidations/on_cancel.go +7111 -0
- package/alpha/validationpkg/jsonvalidations/on_confirm.go +8903 -0
- package/alpha/validationpkg/jsonvalidations/on_init.go +4445 -0
- package/alpha/validationpkg/jsonvalidations/on_issue.go +2828 -0
- package/alpha/validationpkg/jsonvalidations/on_issue_status.go +1938 -0
- package/alpha/validationpkg/jsonvalidations/on_search.go +3356 -0
- package/alpha/validationpkg/jsonvalidations/on_status.go +8129 -0
- package/alpha/validationpkg/jsonvalidations/on_track.go +1415 -0
- package/alpha/validationpkg/jsonvalidations/on_update.go +8700 -0
- package/alpha/validationpkg/jsonvalidations/search.go +3585 -0
- package/alpha/validationpkg/jsonvalidations/status.go +1073 -0
- package/alpha/validationpkg/jsonvalidations/track.go +1073 -0
- package/alpha/validationpkg/jsonvalidations/update.go +3012 -0
- package/alpha/validationpkg/main-validator.go +196 -0
- package/alpha/validationpkg/main-validator_test.go +165 -0
- package/alpha/validationpkg/storageutils/api_save_utils.go +83 -0
- package/alpha/validationpkg/storageutils/cancel.go +30 -0
- package/alpha/validationpkg/storageutils/confirm.go +30 -0
- package/alpha/validationpkg/storageutils/index.go +132 -0
- package/alpha/validationpkg/storageutils/init.go +30 -0
- package/alpha/validationpkg/storageutils/issue.go +30 -0
- package/alpha/validationpkg/storageutils/on_cancel.go +30 -0
- package/alpha/validationpkg/storageutils/on_confirm.go +30 -0
- package/alpha/validationpkg/storageutils/on_init.go +30 -0
- package/alpha/validationpkg/storageutils/on_issue.go +30 -0
- package/alpha/validationpkg/storageutils/on_issue_status.go +30 -0
- package/alpha/validationpkg/storageutils/on_search.go +30 -0
- package/alpha/validationpkg/storageutils/on_status.go +30 -0
- package/alpha/validationpkg/storageutils/on_track.go +30 -0
- package/alpha/validationpkg/storageutils/on_update.go +30 -0
- package/alpha/validationpkg/storageutils/save_utils.go +75 -0
- package/alpha/validationpkg/storageutils/search.go +30 -0
- package/alpha/validationpkg/storageutils/status.go +30 -0
- package/alpha/validationpkg/storageutils/track.go +30 -0
- package/alpha/validationpkg/storageutils/update.go +30 -0
- package/alpha/validationpkg/validationutils/json_normalizer.go +152 -0
- package/alpha/validationpkg/validationutils/json_path_utils.go +173 -0
- package/alpha/validationpkg/validationutils/storage-interface.go +107 -0
- package/alpha/validationpkg/validationutils/test-config.go +69 -0
- package/alpha/validationpkg/validationutils/validation_utils.go +429 -0
- package/dist/bin/cli.js +6 -2
- package/dist/generator/config-compiler.d.ts +2 -2
- package/dist/generator/config-compiler.js +10 -4
- package/dist/generator/generators/classes/abstract-generator.d.ts +1 -0
- package/dist/generator/generators/go/go-generator.js +34 -17
- package/dist/generator/generators/go/templates/api-tests.mustache +1 -1
- package/dist/generator/generators/go/templates/go-mod.mustache +1 -1
- package/dist/generator/generators/go/templates/index.mustache +1 -1
- package/dist/generator/generators/go/templates/storage-templates/api-save-utils.mustache +1 -1
- package/dist/generator/generators/go/templates/storage-templates/api-save.mustache +1 -1
- package/dist/generator/generators/go/templates/storage-templates/index.mustache +1 -1
- package/dist/generator/generators/go/templates/storage-templates/save-utils.mustache +1 -1
- package/dist/generator/generators/go/templates/test-templates/validator-test.mustache +6 -6
- package/dist/types/compiler-types.d.ts +2 -1
- package/dist/types/compiler-types.js +1 -0
- package/docs/jval-dsl.md +913 -0
- package/package.json +1 -1
- package/alpha/possible-json-paths.json +0 -248
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
// Code generated by github.com/ONDC-Official/automation-validation-compiler, DO NOT EDIT.
|
|
2
|
+
|
|
3
|
+
package validationutils
|
|
4
|
+
|
|
5
|
+
import (
|
|
6
|
+
"fmt"
|
|
7
|
+
"strconv"
|
|
8
|
+
"strings"
|
|
9
|
+
"sync"
|
|
10
|
+
"time"
|
|
11
|
+
|
|
12
|
+
"github.com/dlclark/regexp2"
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
// toStringSlice converts []interface{} to []string, returns false if any element is not a string
|
|
16
|
+
func toStringSlice(operand []interface{}) ([]string, bool) {
|
|
17
|
+
result := make([]string, len(operand))
|
|
18
|
+
for i, v := range operand {
|
|
19
|
+
str, ok := v.(string)
|
|
20
|
+
if !ok {
|
|
21
|
+
// Try to convert to string
|
|
22
|
+
if v == nil {
|
|
23
|
+
result[i] = "null"
|
|
24
|
+
} else {
|
|
25
|
+
result[i] = fmt.Sprintf("%v", v)
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
result[i] = str
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return result, true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func AreUnique(operand []interface{}) bool {
|
|
35
|
+
strs, ok := toStringSlice(operand)
|
|
36
|
+
if !ok {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
valuesSet := make(map[string]struct{})
|
|
41
|
+
for _, v := range strs {
|
|
42
|
+
valuesSet[v] = struct{}{}
|
|
43
|
+
}
|
|
44
|
+
return len(valuesSet) == len(strs)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func ArePresent(operand []interface{}) bool {
|
|
48
|
+
strs, ok := toStringSlice(operand)
|
|
49
|
+
if !ok {
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
return NoneIn(operand, []interface{}{"null", "undefined"}) && len(strs) > 0
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Lookup interface for abstraction
|
|
56
|
+
type lookup interface {
|
|
57
|
+
contains(string) bool
|
|
58
|
+
isEmpty() bool
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Map-based lookup (O(1))
|
|
62
|
+
type mapLookup struct {
|
|
63
|
+
items map[string]bool
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
func (m *mapLookup) contains(item string) bool {
|
|
67
|
+
return m.items[item]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
func (m *mapLookup) isEmpty() bool {
|
|
71
|
+
return len(m.items) == 0
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Slice-based lookup (O(n))
|
|
75
|
+
type sliceLookup struct {
|
|
76
|
+
items []string
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
func (s *sliceLookup) contains(item string) bool {
|
|
80
|
+
for _, v := range s.items {
|
|
81
|
+
if v == item {
|
|
82
|
+
return true
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
func (s *sliceLookup) isEmpty() bool {
|
|
89
|
+
return len(s.items) == 0
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Smart lookup creation - auto-detects and optimizes
|
|
93
|
+
func createLookup(right []interface{}) (lookup, bool) {
|
|
94
|
+
// Case 1: Check if right contains a single map
|
|
95
|
+
if len(right) == 1 {
|
|
96
|
+
switch m := right[0].(type) {
|
|
97
|
+
case map[string]interface{}:
|
|
98
|
+
result := make(map[string]bool, len(m))
|
|
99
|
+
for k := range m {
|
|
100
|
+
result[k] = true
|
|
101
|
+
}
|
|
102
|
+
return &mapLookup{items: result}, true
|
|
103
|
+
case map[string]bool:
|
|
104
|
+
return &mapLookup{items: m}, true
|
|
105
|
+
case map[string]string:
|
|
106
|
+
result := make(map[string]bool, len(m))
|
|
107
|
+
for k := range m {
|
|
108
|
+
result[k] = true
|
|
109
|
+
}
|
|
110
|
+
return &mapLookup{items: result}, true
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Case 2: Convert slice to string slice
|
|
115
|
+
rightStrs, ok := toStringSlice(right)
|
|
116
|
+
if !ok {
|
|
117
|
+
return nil, false
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Optimization: Convert large slices to maps for better performance
|
|
121
|
+
const threshold = 10
|
|
122
|
+
if len(rightStrs) > threshold {
|
|
123
|
+
m := make(map[string]bool, len(rightStrs))
|
|
124
|
+
for _, v := range rightStrs {
|
|
125
|
+
m[v] = true
|
|
126
|
+
}
|
|
127
|
+
return &mapLookup{items: m}, true
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return &sliceLookup{items: rightStrs}, true
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Updated comparison functions
|
|
134
|
+
func AllIn(left []interface{}, right []interface{}) bool {
|
|
135
|
+
leftStrs, ok1 := toStringSlice(left)
|
|
136
|
+
if !ok1 {
|
|
137
|
+
return false
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
rightLookup, ok2 := createLookup(right)
|
|
141
|
+
if !ok2 {
|
|
142
|
+
return false
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if len(leftStrs) == 0 && !rightLookup.isEmpty() {
|
|
146
|
+
return false
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
for _, v := range leftStrs {
|
|
150
|
+
if !rightLookup.contains(v) {
|
|
151
|
+
return false
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return true
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
func AnyIn(left []interface{}, right []interface{}) bool {
|
|
158
|
+
leftStrs, ok1 := toStringSlice(left)
|
|
159
|
+
if !ok1 {
|
|
160
|
+
return false
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
rightLookup, ok2 := createLookup(right)
|
|
164
|
+
if !ok2 {
|
|
165
|
+
return false
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if len(leftStrs) == 0 && !rightLookup.isEmpty() {
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
for _, v := range leftStrs {
|
|
173
|
+
if rightLookup.contains(v) {
|
|
174
|
+
return true
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return false
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
func NoneIn(left []interface{}, right []interface{}) bool {
|
|
181
|
+
leftStrs, ok1 := toStringSlice(left)
|
|
182
|
+
if !ok1 {
|
|
183
|
+
return false
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
rightLookup, ok2 := createLookup(right)
|
|
187
|
+
if !ok2 {
|
|
188
|
+
return false
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
for _, v := range leftStrs {
|
|
192
|
+
if rightLookup.contains(v) {
|
|
193
|
+
return false
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return true
|
|
197
|
+
}
|
|
198
|
+
func EqualTo(left []interface{}, right []interface{}) bool {
|
|
199
|
+
leftStrs, ok1 := toStringSlice(left)
|
|
200
|
+
rightStrs, ok2 := toStringSlice(right)
|
|
201
|
+
if !ok1 || !ok2 {
|
|
202
|
+
return false
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if len(leftStrs) != len(rightStrs) {
|
|
206
|
+
return false
|
|
207
|
+
}
|
|
208
|
+
for i, v := range leftStrs {
|
|
209
|
+
if v != rightStrs[i] {
|
|
210
|
+
return false
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return true
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
func GreaterThan(left []interface{}, right []interface{}) bool {
|
|
217
|
+
leftStrs, ok1 := toStringSlice(left)
|
|
218
|
+
rightStrs, ok2 := toStringSlice(right)
|
|
219
|
+
if !ok1 || !ok2 {
|
|
220
|
+
return false
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
areAllISO := func(arr []string) bool {
|
|
224
|
+
for _, v := range arr {
|
|
225
|
+
if !isISO8601(v) {
|
|
226
|
+
return false
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return true
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
areAllNumbers := func(arr []string) bool {
|
|
233
|
+
for _, v := range arr {
|
|
234
|
+
if _, err := strconv.ParseFloat(v, 64); err != nil {
|
|
235
|
+
return false
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return true
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if areAllISO(leftStrs) && areAllISO(rightStrs) {
|
|
242
|
+
leftDates := make([]int64, len(leftStrs))
|
|
243
|
+
for i, date := range leftStrs {
|
|
244
|
+
t, _ := time.Parse(time.RFC3339, date)
|
|
245
|
+
leftDates[i] = t.UnixMilli()
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
rightDates := make([]int64, len(rightStrs))
|
|
249
|
+
for i, date := range rightStrs {
|
|
250
|
+
t, _ := time.Parse(time.RFC3339, date)
|
|
251
|
+
rightDates[i] = t.UnixMilli()
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
for i, ld := range leftDates {
|
|
255
|
+
if i >= len(rightDates) || ld <= rightDates[i] {
|
|
256
|
+
if i < len(rightDates) {
|
|
257
|
+
return false
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return true
|
|
262
|
+
} else if areAllNumbers(leftStrs) && areAllNumbers(rightStrs) {
|
|
263
|
+
leftNumbers := make([]float64, len(leftStrs))
|
|
264
|
+
for i, v := range leftStrs {
|
|
265
|
+
leftNumbers[i], _ = strconv.ParseFloat(v, 64)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
rightNumbers := make([]float64, len(rightStrs))
|
|
269
|
+
for i, v := range rightStrs {
|
|
270
|
+
rightNumbers[i], _ = strconv.ParseFloat(v, 64)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
for i, ln := range leftNumbers {
|
|
274
|
+
if i >= len(rightNumbers) || ln <= rightNumbers[i] {
|
|
275
|
+
if i < len(rightNumbers) {
|
|
276
|
+
return false
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return true
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return false
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
func LessThan(left []interface{}, right []interface{}) bool {
|
|
287
|
+
leftStrs, ok1 := toStringSlice(left)
|
|
288
|
+
rightStrs, ok2 := toStringSlice(right)
|
|
289
|
+
if !ok1 || !ok2 {
|
|
290
|
+
return false
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
areAllISO := func(arr []string) bool {
|
|
294
|
+
for _, v := range arr {
|
|
295
|
+
if !isISO8601(v) {
|
|
296
|
+
return false
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return true
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
areAllNumbers := func(arr []string) bool {
|
|
303
|
+
for _, v := range arr {
|
|
304
|
+
if _, err := strconv.ParseFloat(v, 64); err != nil {
|
|
305
|
+
return false
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return true
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if areAllISO(leftStrs) && areAllISO(rightStrs) {
|
|
312
|
+
leftDates := make([]int64, len(leftStrs))
|
|
313
|
+
for i, date := range leftStrs {
|
|
314
|
+
t, _ := time.Parse(time.RFC3339, date)
|
|
315
|
+
leftDates[i] = t.UnixMilli()
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
rightDates := make([]int64, len(rightStrs))
|
|
319
|
+
for i, date := range rightStrs {
|
|
320
|
+
t, _ := time.Parse(time.RFC3339, date)
|
|
321
|
+
rightDates[i] = t.UnixMilli()
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
for i, ld := range leftDates {
|
|
325
|
+
if i >= len(rightDates) || ld >= rightDates[i] {
|
|
326
|
+
if i < len(rightDates) {
|
|
327
|
+
return false
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return true
|
|
332
|
+
} else if areAllNumbers(leftStrs) && areAllNumbers(rightStrs) {
|
|
333
|
+
leftNumbers := make([]float64, len(leftStrs))
|
|
334
|
+
for i, v := range leftStrs {
|
|
335
|
+
leftNumbers[i], _ = strconv.ParseFloat(v, 64)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
rightNumbers := make([]float64, len(rightStrs))
|
|
339
|
+
for i, v := range rightStrs {
|
|
340
|
+
rightNumbers[i], _ = strconv.ParseFloat(v, 64)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
for i, ln := range leftNumbers {
|
|
344
|
+
if i >= len(rightNumbers) || ln >= rightNumbers[i] {
|
|
345
|
+
if i < len(rightNumbers) {
|
|
346
|
+
return false
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return true
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return false
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
var regexCache sync.Map // cache compiled regexes
|
|
357
|
+
|
|
358
|
+
func FollowRegex(left []interface{}, regexArray []interface{}) bool {
|
|
359
|
+
leftStrs, ok1 := toStringSlice(left)
|
|
360
|
+
regexStrs, ok2 := toStringSlice(regexArray)
|
|
361
|
+
if !ok1 || !ok2 {
|
|
362
|
+
return false
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if len(leftStrs) == 0 && len(regexStrs) != 0 {
|
|
366
|
+
return false
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
for _, regexStr := range regexStrs {
|
|
370
|
+
var re *regexp2.Regexp
|
|
371
|
+
regexStr = sanitizeRegex(regexStr)
|
|
372
|
+
fmt.Printf("Using regex: %s\n", regexStr)
|
|
373
|
+
// Check cache first
|
|
374
|
+
if cached, ok := regexCache.Load(regexStr); ok {
|
|
375
|
+
re = cached.(*regexp2.Regexp)
|
|
376
|
+
} else {
|
|
377
|
+
compiled, err := regexp2.Compile(regexStr, 0)
|
|
378
|
+
if err != nil {
|
|
379
|
+
fmt.Printf("Invalid regex '%s': %v\n", regexStr, err)
|
|
380
|
+
return false
|
|
381
|
+
}
|
|
382
|
+
regexCache.Store(regexStr, compiled)
|
|
383
|
+
re = compiled
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
for _, v := range leftStrs {
|
|
387
|
+
match, err := re.MatchString(v)
|
|
388
|
+
if err != nil || !match {
|
|
389
|
+
return false
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return true
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Only fixes escapes that are invalid in regexp2
|
|
398
|
+
func sanitizeRegex(regex string) string {
|
|
399
|
+
regex = strings.ReplaceAll(regex, `\_`, `_`) // escaped underscore → literal
|
|
400
|
+
regex = strings.ReplaceAll(regex, `\-`, `-`) // escaped hyphen → literal
|
|
401
|
+
return regex
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
func isISO8601(str string) bool {
|
|
405
|
+
iso8601Regex, err := regexp2.Compile(`^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$`, 0)
|
|
406
|
+
if err != nil {
|
|
407
|
+
return false
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
match, err := iso8601Regex.MatchString(str)
|
|
411
|
+
if err != nil || !match {
|
|
412
|
+
return false
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
_, err = time.Parse(time.RFC3339, str)
|
|
416
|
+
return err == nil
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// StringSliceToInterface converts []string to []interface{}
|
|
420
|
+
func StringSliceToInterface(strs []string) []interface{} {
|
|
421
|
+
result := make([]interface{}, len(strs))
|
|
422
|
+
for i, v := range strs {
|
|
423
|
+
result[i] = v
|
|
424
|
+
}
|
|
425
|
+
return result
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// UnusedFunction to avoid unused variable errors
|
|
429
|
+
func UnusedFunction(item interface{}) {}
|
package/dist/bin/cli.js
CHANGED
|
@@ -23,9 +23,10 @@ program
|
|
|
23
23
|
.option("-f, --function-name <name>", "Name of the validation function to generate")
|
|
24
24
|
.option("-o, --output <directory>", "Output directory for generated code")
|
|
25
25
|
.option("-l, --lang <language>", "Target programming language (typescript, python, javascript, go)")
|
|
26
|
+
.option("-p, --packageName <name>", "Package name for generated code (applicable for Go)", "validationpkg")
|
|
26
27
|
.description("Generate validation code")
|
|
27
28
|
.action(async (options) => {
|
|
28
|
-
const { config, output, lang, functionName } = options;
|
|
29
|
+
const { config, output, lang, functionName, packageName } = options;
|
|
29
30
|
console.log(Cli.title("Ondc Validation Code Generator"));
|
|
30
31
|
if (!config || !output || !lang) {
|
|
31
32
|
console.log(Cli.description.error("Please provide all required options: --config, --output, --lang"));
|
|
@@ -34,6 +35,7 @@ program
|
|
|
34
35
|
try {
|
|
35
36
|
console.log(Cli.description.info(`Generating validation code for language: ${lang}`));
|
|
36
37
|
const functionName = options.functionName || "L1validations";
|
|
38
|
+
const packageName = options.packageName || "validationpkg";
|
|
37
39
|
const language = getSupportedLanguage(lang);
|
|
38
40
|
const compiler = new ConfigCompiler(language);
|
|
39
41
|
const buildPath = path.resolve(process.cwd(), config);
|
|
@@ -44,7 +46,7 @@ program
|
|
|
44
46
|
const validPaths = await compiler.generateValidPaths();
|
|
45
47
|
writeFileSync(path.resolve(output, "validPaths.json"), JSON.stringify(validPaths, null, 2));
|
|
46
48
|
console.log(Cli.description.info("Generating validation code..."));
|
|
47
|
-
await compiler.generateValidationFromBuild(functionName, output, true);
|
|
49
|
+
await compiler.generateValidationFromBuild(functionName, output, true, packageName);
|
|
48
50
|
console.log(Cli.description.success(`Validation code generated successfully in ${output} for language ${lang}`));
|
|
49
51
|
}
|
|
50
52
|
catch (error) {
|
|
@@ -122,6 +124,8 @@ function getSupportedLanguage(lang) {
|
|
|
122
124
|
return SupportedLanguages.Javascript;
|
|
123
125
|
case "go":
|
|
124
126
|
return SupportedLanguages.Golang;
|
|
127
|
+
case "md":
|
|
128
|
+
return SupportedLanguages.Markdown;
|
|
125
129
|
default:
|
|
126
130
|
throw new Error(`Unsupported language: ${lang}. Supported languages are: ${getValidLanguageOptions()}`);
|
|
127
131
|
}
|
|
@@ -20,10 +20,10 @@ export declare class ConfigCompiler {
|
|
|
20
20
|
initialize: (buildYaml: string, generatorConfig?: Partial<CodeGeneratorConfig>) => Promise<void>;
|
|
21
21
|
performValidations: (valConfig: ValidationConfig) => Promise<void>;
|
|
22
22
|
withMinimalValidations: (valConfig: ValidationConfig) => Promise<void>;
|
|
23
|
-
generateCode: (valConfig: ValidationConfig, codeName?: string, minimal?: boolean, outputPath?: string, absolutePath?: boolean) => Promise<void>;
|
|
23
|
+
generateCode: (valConfig: ValidationConfig, codeName?: string, minimal?: boolean, outputPath?: string, absolutePath?: boolean, goPackageName?: string) => Promise<void>;
|
|
24
24
|
generateL0Schema: (outputPath?: string, type?: "json" | "typescript", absolutePath?: boolean) => Promise<void>;
|
|
25
25
|
generateValidPaths: () => Promise<Record<string, string[]>>;
|
|
26
|
-
generateValidationFromBuild: (codeName: string, outputPath: string, absolutePath?: boolean) => Promise<void>;
|
|
26
|
+
generateValidationFromBuild: (codeName: string, outputPath: string, absolutePath?: boolean, goPackageName?: string) => Promise<void>;
|
|
27
27
|
extractPayloadsFromBuild: (outputPath: string) => Promise<void>;
|
|
28
28
|
}
|
|
29
29
|
export {};
|
|
@@ -12,6 +12,7 @@ import { duplicateVariablesInChildren } from "../utils/config-utils/duplicateVar
|
|
|
12
12
|
import { PythonGenerator } from "./generators/python/py-generator.js";
|
|
13
13
|
import { JavascriptGenerator } from "./generators/javascript/js-generator.js";
|
|
14
14
|
import { GoGenerator } from "./generators/go/go-generator.js";
|
|
15
|
+
import { MarkdownDocGenerator } from "./generators/documentation/md-generator.js";
|
|
15
16
|
const __filename = fileURLToPath(import.meta.url);
|
|
16
17
|
const __dirname = path.dirname(__filename);
|
|
17
18
|
const defaultConfig = {
|
|
@@ -27,7 +28,8 @@ export class ConfigCompiler {
|
|
|
27
28
|
this.generatorConfig = finalConfig;
|
|
28
29
|
this.buildData = await loadAndDereferenceYaml(buildYaml);
|
|
29
30
|
this.jsonSchemas = await this.SchemaExtractionService.extractSchemas(this.buildData, finalConfig.removeRequiredFromSchema, finalConfig.removeEnumsFromSchema);
|
|
30
|
-
this.possibleJsonPaths =
|
|
31
|
+
this.possibleJsonPaths =
|
|
32
|
+
this.SchemaExtractionService.extractPossiblePaths(this.jsonSchemas);
|
|
31
33
|
const errors = this.buildData["x-errorcodes"];
|
|
32
34
|
this.errorDefinitions = errors.code;
|
|
33
35
|
};
|
|
@@ -57,7 +59,7 @@ export class ConfigCompiler {
|
|
|
57
59
|
// throw new Error("validation failed");
|
|
58
60
|
};
|
|
59
61
|
// };
|
|
60
|
-
this.generateCode = async (valConfig, codeName = "L1-Validations", minimal = false, outputPath = "./", absolutePath = false) => {
|
|
62
|
+
this.generateCode = async (valConfig, codeName = "L1-Validations", minimal = false, outputPath = "./", absolutePath = false, goPackageName = "validationpkg") => {
|
|
61
63
|
try {
|
|
62
64
|
console.log("[ CODE GENERATION ] Starting code generation...");
|
|
63
65
|
valConfig = JSON.parse(JSON.stringify(valConfig));
|
|
@@ -93,8 +95,12 @@ export class ConfigCompiler {
|
|
|
93
95
|
case SupportedLanguages.Golang:
|
|
94
96
|
await new GoGenerator(valConfig, this.errorDefinitions ?? [], targetPath).generateCode({
|
|
95
97
|
codeName: codeName,
|
|
98
|
+
goPkgName: goPackageName,
|
|
96
99
|
});
|
|
97
100
|
break;
|
|
101
|
+
case SupportedLanguages.Markdown:
|
|
102
|
+
await new MarkdownDocGenerator(valConfig, this.errorDefinitions ?? [], targetPath).generateCode();
|
|
103
|
+
break;
|
|
98
104
|
default:
|
|
99
105
|
throw new Error("Language not supported");
|
|
100
106
|
}
|
|
@@ -144,13 +150,13 @@ export class ConfigCompiler {
|
|
|
144
150
|
// );
|
|
145
151
|
return this.possibleJsonPaths;
|
|
146
152
|
};
|
|
147
|
-
this.generateValidationFromBuild = async (codeName, outputPath, absolutePath = false) => {
|
|
153
|
+
this.generateValidationFromBuild = async (codeName, outputPath, absolutePath = false, goPackageName = "validationpkg") => {
|
|
148
154
|
if (!this.buildData)
|
|
149
155
|
throw new Error("Build data not initialized");
|
|
150
156
|
const valConfig = this.buildData["x-validations"];
|
|
151
157
|
if (!valConfig)
|
|
152
158
|
throw new Error("No validation config found in build data");
|
|
153
|
-
await this.generateCode(valConfig, codeName, false, outputPath, absolutePath);
|
|
159
|
+
await this.generateCode(valConfig, codeName, false, outputPath, absolutePath, goPackageName);
|
|
154
160
|
};
|
|
155
161
|
this.extractPayloadsFromBuild = async (outputPath) => {
|
|
156
162
|
if (!this.buildData)
|
|
@@ -2,6 +2,7 @@ import { ValidationConfig } from "../../../types/config-types";
|
|
|
2
2
|
import { ErrorDefinition } from "../../../types/error-codes";
|
|
3
3
|
export type CodeGeneratorProps = {
|
|
4
4
|
codeName: string;
|
|
5
|
+
goPkgName?: string;
|
|
5
6
|
};
|
|
6
7
|
export declare abstract class CodeGenerator {
|
|
7
8
|
validationConfig: ValidationConfig;
|
|
@@ -13,27 +13,33 @@ import { markdownMessageGenerator } from "../documentation/markdown-message-gene
|
|
|
13
13
|
import { MarkdownDocGenerator } from "../documentation/md-generator.js";
|
|
14
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
15
|
const __dirname = path.dirname(__filename);
|
|
16
|
-
const
|
|
16
|
+
const defaultPkgName = "validationpkg";
|
|
17
17
|
export class GoGenerator extends CodeGenerator {
|
|
18
18
|
constructor() {
|
|
19
19
|
super(...arguments);
|
|
20
20
|
this.generateCode = async (codeConfig) => {
|
|
21
21
|
this.codeConfig = codeConfig;
|
|
22
|
+
if (!this.codeConfig.goPkgName) {
|
|
23
|
+
this.codeConfig.goPkgName = defaultPkgName;
|
|
24
|
+
}
|
|
22
25
|
const jsonPathUtilsCode = readFileSync(path.resolve(__dirname, "./templates/json-path-utils.mustache"), "utf-8");
|
|
23
26
|
const validationUtils = readFileSync(path.resolve(__dirname, "./templates/validation-utils.mustache"), "utf-8");
|
|
24
27
|
const typesTemplate = readFileSync(path.resolve(__dirname, "./templates/test-config.mustache"), "utf-8");
|
|
25
28
|
const normalizerTemplate = readFileSync(path.resolve(__dirname, "./templates/json-normalizer.mustache"), "utf-8");
|
|
26
29
|
const goMod = readFileSync(path.resolve(__dirname, "./templates/go-mod.mustache"), "utf-8");
|
|
30
|
+
const goModCode = Mustache.render(goMod, {
|
|
31
|
+
pkgName: codeConfig.goPkgName,
|
|
32
|
+
});
|
|
27
33
|
const typesCode = Mustache.render(typesTemplate, {
|
|
28
34
|
externalData: this.getExternalKeys(),
|
|
29
35
|
});
|
|
30
|
-
writeAndFormatCode(this.rootPath, `./${
|
|
31
|
-
writeAndFormatCode(this.rootPath, `./${
|
|
32
|
-
writeAndFormatCode(this.rootPath, `./${
|
|
33
|
-
writeAndFormatCode(this.rootPath, `./${
|
|
36
|
+
writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/validationutils/json_path_utils.go`, jsonPathUtilsCode, "go");
|
|
37
|
+
writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/validationutils/validation_utils.go`, validationUtils, "go");
|
|
38
|
+
writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/validationutils/test-config.go`, typesCode, "go");
|
|
39
|
+
writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/validationutils/json_normalizer.go`, normalizerTemplate, "go");
|
|
34
40
|
await this.generateValidationCode();
|
|
35
|
-
await writeAndFormatCode(this.rootPath, `./${
|
|
36
|
-
await writeAndFormatCode(this.rootPath, `./${
|
|
41
|
+
await writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/main-validator.go`, this.generateIndexFile(Object.keys(this.validationConfig[ConfigSyntax.Tests]), codeConfig.codeName), "go");
|
|
42
|
+
await writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/go.mod`, goModCode, "text");
|
|
37
43
|
await this.generateSessionDataCode();
|
|
38
44
|
await this.generateUnitTestingCode();
|
|
39
45
|
await new MarkdownDocGenerator(this.validationConfig, this.errorCodes, this.rootPath).generateCode();
|
|
@@ -69,16 +75,23 @@ export class GoGenerator extends CodeGenerator {
|
|
|
69
75
|
const relevantSessionData = {};
|
|
70
76
|
collectLoadData(tests, relevantSessionData);
|
|
71
77
|
const sessionDataUtilsTemplate = readFileSync(path.resolve(__dirname, "./templates/storage-templates/save-utils.mustache"), "utf-8");
|
|
78
|
+
const sessionDataUtilsCode = Mustache.render(sessionDataUtilsTemplate, {
|
|
79
|
+
pkgName: this.codeConfig.goPkgName,
|
|
80
|
+
});
|
|
72
81
|
const storageInterfaceTemplate = readFileSync(path.resolve(__dirname, "./templates/storage-templates/storage-interface.mustache"), "utf-8");
|
|
73
82
|
const indexTemplate = readFileSync(path.resolve(__dirname, "./templates/storage-templates/index.mustache"), "utf-8");
|
|
74
83
|
const saveActionTemplate = readFileSync(path.resolve(__dirname, "./templates/storage-templates/api-save.mustache"), "utf-8");
|
|
75
84
|
const saveActionUtilsTemplate = readFileSync(path.resolve(__dirname, "./templates/storage-templates/api-save-utils.mustache"), "utf-8");
|
|
85
|
+
const saveActionUtilsCode = Mustache.render(saveActionUtilsTemplate, {
|
|
86
|
+
pkgName: this.codeConfig.goPkgName,
|
|
87
|
+
});
|
|
76
88
|
const allActions = Object.keys(tests);
|
|
77
89
|
const indexCode = Mustache.render(indexTemplate, {
|
|
78
90
|
actions: Array.from(allActions).map((action) => {
|
|
79
91
|
return { action: action };
|
|
80
92
|
}),
|
|
81
93
|
functionName: this.codeConfig.codeName.replace(/[^a-zA-Z0-9_]/g, ""),
|
|
94
|
+
pkgName: this.codeConfig.goPkgName,
|
|
82
95
|
});
|
|
83
96
|
for (const action of allActions) {
|
|
84
97
|
const loadData = relevantSessionData[action] || {};
|
|
@@ -101,13 +114,14 @@ export class GoGenerator extends CodeGenerator {
|
|
|
101
114
|
key: value,
|
|
102
115
|
})),
|
|
103
116
|
action: action,
|
|
117
|
+
pkgName: this.codeConfig.goPkgName,
|
|
104
118
|
});
|
|
105
|
-
await writeAndFormatCode(this.rootPath, `./${
|
|
119
|
+
await writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/storageutils/${action}.go`, saveCode, "go");
|
|
106
120
|
}
|
|
107
|
-
await writeAndFormatCode(this.rootPath, `./${
|
|
108
|
-
await writeAndFormatCode(this.rootPath, `./${
|
|
109
|
-
await writeAndFormatCode(this.rootPath, `./${
|
|
110
|
-
await writeAndFormatCode(this.rootPath, `./${
|
|
121
|
+
await writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/storageutils/save_utils.go`, sessionDataUtilsCode, "go");
|
|
122
|
+
await writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/validationutils/storage-interface.go`, storageInterfaceTemplate, "go");
|
|
123
|
+
await writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/storageutils/index.go`, indexCode, "go");
|
|
124
|
+
await writeAndFormatCode(this.rootPath, `./${this.codeConfig.goPkgName}/storageutils/api_save_utils.go`, saveActionUtilsCode, "go");
|
|
111
125
|
}
|
|
112
126
|
async generateValidationCode() {
|
|
113
127
|
const testConfig = this.validationConfig[ConfigSyntax.Tests];
|
|
@@ -122,18 +136,19 @@ export class GoGenerator extends CodeGenerator {
|
|
|
122
136
|
const finalCode = Mustache.render(apiTestTemplate, {
|
|
123
137
|
functionCode: testFunction.code,
|
|
124
138
|
apiName: stringToCaps(key),
|
|
139
|
+
pkgName: this.codeConfig?.goPkgName,
|
|
125
140
|
});
|
|
126
|
-
await writeAndFormatCode(this.rootPath, `./${
|
|
141
|
+
await writeAndFormatCode(this.rootPath, `./${this.codeConfig?.goPkgName}/jsonvalidations/${key}.go`, finalCode, "go");
|
|
127
142
|
}
|
|
128
143
|
}
|
|
129
144
|
generateIndexFile(apis, functionName = "L1Validations") {
|
|
130
145
|
functionName = functionName.replace(/[^a-zA-Z0-9_]/g, "");
|
|
131
146
|
let importList = [
|
|
132
|
-
`"
|
|
133
|
-
`"
|
|
147
|
+
`"${this.codeConfig?.goPkgName}/validationutils"`,
|
|
148
|
+
`"${this.codeConfig?.goPkgName}/jsonvalidations"`,
|
|
134
149
|
`"fmt"`,
|
|
135
150
|
`"encoding/json"`,
|
|
136
|
-
`"
|
|
151
|
+
`"${this.codeConfig?.goPkgName}/storageutils"`,
|
|
137
152
|
];
|
|
138
153
|
const masterTemplate = readFileSync(path.resolve(__dirname, "./templates/index.mustache"), "utf-8");
|
|
139
154
|
const masterFunction = `func Perform${functionName}(
|
|
@@ -254,6 +269,7 @@ ${importList.map((imp) => `\t${imp}`).join("\n")}
|
|
|
254
269
|
return Mustache.render(masterTemplate, {
|
|
255
270
|
importCode: importCode,
|
|
256
271
|
masterFunction: masterFunction,
|
|
272
|
+
pkgName: this.codeConfig?.goPkgName,
|
|
257
273
|
});
|
|
258
274
|
}
|
|
259
275
|
getExternalKeys() {
|
|
@@ -365,8 +381,9 @@ ${importList.map((imp) => `\t${imp}`).join("\n")}
|
|
|
365
381
|
const testTemplate = readFileSync(path.resolve(__dirname, "./templates/test-templates/validator-test.mustache"), "utf-8");
|
|
366
382
|
const finalTestCode = Mustache.render(testTemplate, {
|
|
367
383
|
functionName: this.codeConfig?.codeName ?? "L1Validations",
|
|
384
|
+
pkgName: this.codeConfig?.goPkgName ?? defaultPkgName,
|
|
368
385
|
});
|
|
369
|
-
await writeAndFormatCode(this.rootPath, `./${
|
|
386
|
+
await writeAndFormatCode(this.rootPath, `./${this.codeConfig?.goPkgName ?? defaultPkgName}/main-validator_test.go`, finalTestCode, "go");
|
|
370
387
|
}
|
|
371
388
|
}
|
|
372
389
|
function stringToCaps(str) {
|