ondc-code-generator 0.6.21 → 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 (36) 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/generator/generators/python/py-generator.js +1 -1
  24. package/dist/generator/generators/python/templates/json-path-utils.mustache +16 -1
  25. package/dist/generator/generators/python/templates/storage-templates/api-save.mustache +1 -1
  26. package/dist/generator/generators/typescript/templates/json-path-utils.mustache +25 -7
  27. package/dist/generator/generators/typescript/templates/storage-templates/api-save.mustache +1 -1
  28. package/dist/generator/generators/typescript/ts-generator.js +1 -1
  29. package/dist/index.d.ts +2 -1
  30. package/dist/index.js +2 -1
  31. package/dist/index.test.js +7 -1
  32. package/dist/types/compiler-types.d.ts +2 -1
  33. package/dist/types/compiler-types.js +1 -0
  34. package/dist/utils/fs-utils.js +40 -0
  35. package/package.json +2 -2
  36. package/sample.md +273 -0
@@ -0,0 +1,46 @@
1
+ package utils
2
+
3
+ import (
4
+ "encoding/json"
5
+ "strings"
6
+ )
7
+
8
+ // NormalizeKeys converts all keys in a JSON object to snake_case
9
+ func NormalizeKeys(data interface{}) interface{} {
10
+ switch v := data.(type) {
11
+ case map[string]interface{}:
12
+ normalized := make(map[string]interface{})
13
+ for key, value := range v {
14
+ normalizedKey := toSnakeCase(key)
15
+ normalized[normalizedKey] = NormalizeKeys(value)
16
+ }
17
+ return normalized
18
+ case []interface{}:
19
+ normalized := make([]interface{}, len(v))
20
+ for i, value := range v {
21
+ normalized[i] = NormalizeKeys(value)
22
+ }
23
+ return normalized
24
+ default:
25
+ return v
26
+ }
27
+ }
28
+
29
+ // toSnakeCase converts a string to snake_case
30
+ func toSnakeCase(s string) string {
31
+ var result strings.Builder
32
+ for i, r := range s {
33
+ if i > 0 && r >= 'A' && r <= 'Z' {
34
+ result.WriteRune('_')
35
+ }
36
+ result.WriteRune(r)
37
+ }
38
+ return strings.ToLower(result.String())
39
+ }
40
+
41
+ // FromJSON parses JSON bytes into interface{}
42
+ func FromJSON(data []byte) (interface{}, error) {
43
+ var result interface{}
44
+ err := json.Unmarshal(data, &result)
45
+ return result, err
46
+ }
@@ -0,0 +1,21 @@
1
+ package utils
2
+
3
+ import (
4
+ "github.com/PaesslerAG/jsonpath"
5
+ )
6
+
7
+ // GetJSONPath extracts values from a JSON object using JSONPath
8
+ func GetJSONPath(data interface{}, path string) []interface{} {
9
+ result, err := jsonpath.Get(path, data)
10
+ if err != nil {
11
+ return []interface{}{}
12
+ }
13
+
14
+ // If result is already a slice, return it
15
+ if slice, ok := result.([]interface{}); ok {
16
+ return slice
17
+ }
18
+
19
+ // Otherwise, wrap the single result in a slice
20
+ return []interface{}{result}
21
+ }
@@ -0,0 +1,30 @@
1
+ package storageactions
2
+
3
+ import (
4
+ "L1_validations/interfaces"
5
+ "L1_validations/types"
6
+ )
7
+
8
+ // Store_{{action}} saves data for the {{action}} action
9
+ func Store_{{action}}(uniquePrefix string, payload map[string]interface{}, store interfaces.StorageInterface, config types.StorageConfig) error {
10
+ {{#storeActions}}
11
+ if err := SaveFunction(payload, uniquePrefix, "{{{key}}}", "{{{value}}}", "{{action}}", store, config); err != nil {
12
+ return err
13
+ }
14
+ {{/storeActions}}
15
+ return nil
16
+ }
17
+
18
+ // LoadFor_{{action}} loads data for the {{action}} action
19
+ func LoadFor_{{action}}(uniquePrefix string, store interfaces.StorageInterface) (map[string]interface{}, error) {
20
+ result := make(map[string]interface{})
21
+
22
+ {{#loadActions}}
23
+ {{{key}}}Data, err := LoadFunction(store, uniquePrefix, "{{{key}}}")
24
+ if err == nil {
25
+ result["{{{key}}}"] = {{{key}}}Data
26
+ }
27
+ {{/loadActions}}
28
+
29
+ return result, nil
30
+ }
@@ -0,0 +1,41 @@
1
+ package storageactions
2
+
3
+ import (
4
+ "fmt"
5
+ "L1_validations/interfaces"
6
+ "L1_validations/types"
7
+ )
8
+
9
+ // Perform{{functionName}}Save saves validation data based on the action
10
+ func Perform{{functionName}}Save(action, uniquePrefix string, payload map[string]interface{}, store interfaces.StorageInterface, config *types.StorageConfig) error {
11
+ completeConfig := types.DefaultStorageConfig()
12
+ if config != nil {
13
+ if config.RetryAttempts > 0 {
14
+ completeConfig.RetryAttempts = config.RetryAttempts
15
+ }
16
+ if config.RetryDelayMs > 0 {
17
+ completeConfig.RetryDelayMs = config.RetryDelayMs
18
+ }
19
+ }
20
+
21
+ switch action {
22
+ {{#actions}}
23
+ case "{{{action}}}":
24
+ return Store_{{{action}}}(uniquePrefix, payload, store, completeConfig)
25
+ {{/actions}}
26
+ default:
27
+ return fmt.Errorf("action not found: %s", action)
28
+ }
29
+ }
30
+
31
+ // Perform{{functionName}}Load loads validation data based on the action
32
+ func Perform{{functionName}}Load(action, uniquePrefix string, store interfaces.StorageInterface) (map[string]interface{}, error) {
33
+ switch action {
34
+ {{#actions}}
35
+ case "{{{action}}}":
36
+ return LoadFor_{{{action}}}(uniquePrefix, store)
37
+ {{/actions}}
38
+ default:
39
+ return nil, fmt.Errorf("action not found: %s", action)
40
+ }
41
+ }
@@ -0,0 +1,37 @@
1
+ package utils
2
+
3
+ import (
4
+ "fmt"
5
+ "time"
6
+ "L1_validations/interfaces"
7
+ "L1_validations/types"
8
+ )
9
+
10
+ // SaveData saves data to storage with retry logic
11
+ func SaveData(uniquePrefix, key, saveData string, store interfaces.StorageInterface, config types.StorageConfig) error {
12
+ finalKey := key
13
+ retryTimes := config.RetryAttempts
14
+ delayMs := config.RetryDelayMs
15
+ attempts := 0
16
+
17
+ for attempts < retryTimes {
18
+ err := store.SaveKey(uniquePrefix, finalKey, saveData)
19
+ if err == nil {
20
+ return nil
21
+ }
22
+
23
+ attempts++
24
+ if attempts >= retryTimes {
25
+ return err
26
+ }
27
+
28
+ time.Sleep(time.Duration(delayMs) * time.Millisecond)
29
+ }
30
+
31
+ return fmt.Errorf("failed to save data after %d attempts", retryTimes)
32
+ }
33
+
34
+ // CreateKey creates a composite key from prefix and key
35
+ func CreateKey(uniquePrefix, key string) string {
36
+ return fmt.Sprintf("%s:%s", uniquePrefix, key)
37
+ }
@@ -0,0 +1,51 @@
1
+ package storageactions
2
+
3
+ import (
4
+ "encoding/json"
5
+ "time"
6
+ "L1_validations/utils"
7
+ "L1_validations/interfaces"
8
+ "L1_validations/types"
9
+ )
10
+
11
+ // SaveFunction saves a value from payload at specified path to storage
12
+ func SaveFunction(payload map[string]interface{}, uniquePrefix, key, path, action string, store interfaces.StorageInterface, config types.StorageConfig) error {
13
+ if path == "" || key == "_SELF" {
14
+ return nil
15
+ }
16
+
17
+ value := utils.GetJSONPath(payload, path)
18
+
19
+ data := map[string]interface{}{
20
+ "stored_from": action + "_action",
21
+ "key_path": path,
22
+ "value": value,
23
+ "timestamp": time.Now().Format(time.RFC3339),
24
+ }
25
+
26
+ dataBytes, err := json.Marshal(data)
27
+ if err != nil {
28
+ return err
29
+ }
30
+
31
+ return utils.SaveData(uniquePrefix, key, string(dataBytes), store, config)
32
+ }
33
+
34
+ // LoadFunction loads a value from storage by key
35
+ func LoadFunction(store interfaces.StorageInterface, uniquePrefix, key string) (interface{}, error) {
36
+ value, err := store.GetKey(uniquePrefix, key)
37
+ if err != nil {
38
+ return []interface{}{}, nil
39
+ }
40
+
41
+ var data map[string]interface{}
42
+ if err := json.Unmarshal([]byte(value), &data); err != nil {
43
+ return []interface{}{}, nil
44
+ }
45
+
46
+ if val, ok := data["value"]; ok {
47
+ return val, nil
48
+ }
49
+
50
+ return []interface{}{}, nil
51
+ }
@@ -0,0 +1,96 @@
1
+ package interfaces
2
+
3
+ // StorageInterface provides a standardized abstraction layer for storage operations
4
+ // that can be implemented by different storage backends (Redis, Memory, File, etc.).
5
+ //
6
+ // All operations return errors for failure cases.
7
+ // Keys are strings and values are stored as strings.
8
+ // Implementations should handle serialization/deserialization as needed.
9
+ // Prefix-based operations allow for namespacing and bulk operations.
10
+ //
11
+ // Example implementation:
12
+ //
13
+ // type RedisStorage struct {
14
+ // client *redis.Client
15
+ // }
16
+ //
17
+ // func (r *RedisStorage) SaveKey(uniquePrefix, key, value string) error {
18
+ // fullKey := fmt.Sprintf("%s:%s", uniquePrefix, key)
19
+ // return r.client.Set(ctx, fullKey, value, 0).Err()
20
+ // }
21
+ type StorageInterface interface {
22
+ // SaveKey saves a key-value pair to storage with a unique prefix for namespacing.
23
+ //
24
+ // Parameters:
25
+ // - uniquePrefix: A unique identifier/namespace prefix to prevent key collisions
26
+ // - key: The unique identifier for the stored value within the prefix namespace
27
+ // - value: The string value to store
28
+ //
29
+ // Returns an error if the operation fails.
30
+ //
31
+ // Example:
32
+ // err := storage.SaveKey("app1", "session:abc123", sessionDataJSON)
33
+ SaveKey(uniquePrefix, key, value string) error
34
+
35
+ // GetKey retrieves a value by its key from storage within a specific namespace.
36
+ //
37
+ // Parameters:
38
+ // - uniquePrefix: The unique identifier/namespace prefix used when storing
39
+ // - key: The unique identifier for the value to retrieve within the prefix namespace
40
+ //
41
+ // Returns the stored value or an error if the key does not exist.
42
+ //
43
+ // Example:
44
+ // sessionData, err := storage.GetKey("app1", "session:abc123")
45
+ GetKey(uniquePrefix, key string) (string, error)
46
+
47
+ // DeleteKey removes a key-value pair from storage within a specific namespace.
48
+ //
49
+ // Parameters:
50
+ // - uniquePrefix: The unique identifier/namespace prefix used when storing
51
+ // - key: The unique identifier for the value to delete within the prefix namespace
52
+ //
53
+ // Returns an error if the operation fails.
54
+ //
55
+ // Example:
56
+ // err := storage.DeleteKey("app1", "session:abc123")
57
+ DeleteKey(uniquePrefix, key string) error
58
+
59
+ // ListKeys returns all keys within a specific namespace/prefix.
60
+ //
61
+ // Parameters:
62
+ // - uniquePrefix: The unique identifier/namespace prefix to list keys from
63
+ //
64
+ // Returns an array of keys within that namespace or an error.
65
+ //
66
+ // Example:
67
+ // app1Keys, err := storage.ListKeys("app1")
68
+ // // Returns keys like: ["session:abc123", "user:456", "config:settings"]
69
+ ListKeys(uniquePrefix string) ([]string, error)
70
+
71
+ // ClearStorage removes all stored data from the storage backend.
72
+ //
73
+ // WARNING: This operation is destructive and cannot be undone.
74
+ // Use with caution, especially in production environments.
75
+ //
76
+ // Returns an error if the operation fails.
77
+ //
78
+ // Example:
79
+ // err := storage.ClearStorage() // All data is now removed
80
+ ClearStorage() error
81
+
82
+ // KeyExists checks if a key exists in storage within a specific namespace.
83
+ //
84
+ // Parameters:
85
+ // - uniquePrefix: The unique identifier/namespace prefix to check within
86
+ // - key: The unique identifier to check for existence within the prefix namespace
87
+ //
88
+ // Returns true if the key exists, false otherwise, or an error.
89
+ //
90
+ // Example:
91
+ // exists, err := storage.KeyExists("app1", "user:123")
92
+ // if exists {
93
+ // userData, _ := storage.GetKey("app1", "user:123")
94
+ // }
95
+ KeyExists(uniquePrefix, key string) (bool, error)
96
+ }
@@ -0,0 +1,15 @@
1
+ package types
2
+
3
+ // StorageConfig holds configuration for storage retry behavior
4
+ type StorageConfig struct {
5
+ RetryAttempts int // Number of retry attempts for failed operations
6
+ RetryDelayMs int // Delay in milliseconds between retry attempts
7
+ }
8
+
9
+ // DefaultStorageConfig returns the default storage configuration
10
+ func DefaultStorageConfig() StorageConfig {
11
+ return StorageConfig{
12
+ RetryAttempts: 3,
13
+ RetryDelayMs: 1000,
14
+ }
15
+ }
@@ -0,0 +1,39 @@
1
+ package types
2
+
3
+ import "L1_validations/interfaces"
4
+
5
+ // ValidationConfig holds configuration for validation execution
6
+ type ValidationConfig struct {
7
+ OnlyInvalid bool `json:"only_invalid"`
8
+ StandardLogs bool `json:"standard_logs"`
9
+ Debug bool `json:"_debug"`
10
+ HideParentErrors bool `json:"hide_parent_errors"`
11
+ StateFullValidations bool `json:"state_full_validations"`
12
+ Store interfaces.StorageInterface `json:"-"`
13
+ StorageConfig *StorageConfig `json:"storage_config,omitempty"`
14
+ UniqueKey string `json:"unique_key,omitempty"`
15
+ }
16
+
17
+ // ValidationInput is the input structure for validation functions
18
+ type ValidationInput struct {
19
+ Payload map[string]interface{} `json:"payload"`
20
+ ExternalData map[string]interface{} `json:"external_data"`
21
+ Config ValidationConfig `json:"config"`
22
+ }
23
+
24
+ // ValidationOutput represents a single validation result
25
+ type ValidationOutput struct {
26
+ TestName string `json:"test_name,omitempty"`
27
+ Valid bool `json:"valid"`
28
+ Code int `json:"code"`
29
+ Description string `json:"description,omitempty"`
30
+ DebugInfo map[string]interface{} `json:"_debug_info,omitempty"`
31
+ }
32
+
33
+ // ExternalData structure
34
+ type ExternalData struct {
35
+ {{#externalData}}
36
+ {{name}} interface{} `json:"{{name}}"`
37
+ {{/externalData}}
38
+ Self interface{} `json:"_SELF"`
39
+ }
@@ -0,0 +1,39 @@
1
+ func {{name}}(input types.ValidationInput) []types.ValidationOutput {
2
+ scope := utils.GetJSONPath(input.Payload, "{{{scopePath}}}")
3
+ subResults := []types.ValidationOutput{}
4
+ valid := true
5
+
6
+ for _, testObjRaw := range scope {
7
+ testObj, ok := testObjRaw.(map[string]interface{})
8
+ if !ok {
9
+ continue
10
+ }
11
+ testObj["_EXTERNAL"] = input.ExternalData
12
+
13
+ {{#variables}}
14
+ {{name}} {{#isAssignment}}={{/isAssignment}}{{^isAssignment}}:={{/isAssignment}} {{{value}}}
15
+ {{^isAssignment}}utils.UNUSED({{name}}){{/isAssignment}}
16
+ {{/variables}}
17
+
18
+ {{#hasContinue}}
19
+ skipCheck := {{{skipCheckStatement}}}
20
+ if skipCheck {
21
+ continue
22
+ }
23
+ {{/hasContinue}}
24
+
25
+ {{{validationCode}}}
26
+ // delete(testObj, "_EXTERNAL")
27
+ }
28
+
29
+ return append([]types.ValidationOutput{
30
+ {
31
+ TestName: "{{testName}}",
32
+ Valid: valid,
33
+ Code: func() int { if valid { return {{successCode}} } else { return {{errorCode}} } }(),
34
+ DebugInfo: map[string]interface{}{
35
+ "fed_config": `{{{TEST_OBJECT}}}`,
36
+ },
37
+ },
38
+ }, subResults...)
39
+ }
@@ -0,0 +1,51 @@
1
+ {{#isNested}}
2
+ testFunctions := []func(types.ValidationInput) []types.ValidationOutput{
3
+ {{#names}}
4
+ {{name}},
5
+ {{/names}}
6
+ }
7
+
8
+ allResults := []types.ValidationOutput{}
9
+ for _, fn := range testFunctions {
10
+ subResult := fn(input)
11
+ allResults = append(allResults, subResult...)
12
+ }
13
+ subResults = allResults
14
+ valid = true
15
+ for _, r := range subResults {
16
+ if !r.Valid {
17
+ valid = false
18
+ break
19
+ }
20
+ }
21
+
22
+ {{/isNested}}
23
+
24
+ {{^isNested}}
25
+
26
+ {{#isStateFull}}
27
+ validate := true
28
+ if input.Config.StateFullValidations {
29
+ validate = {{{returnStatement}}}
30
+ }
31
+ {{/isStateFull}}
32
+
33
+ {{^isStateFull}}
34
+ validate := {{{returnStatement}}}
35
+ {{/isStateFull}}
36
+
37
+ if !validate {
38
+ return []types.ValidationOutput{
39
+ {
40
+ TestName: "{{testName}}",
41
+ Valid: false,
42
+ Code: {{errorCode}},
43
+ Description: `{{{errorDescription}}}`,
44
+ DebugInfo: map[string]interface{}{
45
+ "fed_config": `{{{TEST_OBJECT}}}`,
46
+ },
47
+ },
48
+ }
49
+ }
50
+
51
+ {{/isNested}}