ondc-code-generator 0.7.3 → 0.7.5

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 (29) hide show
  1. package/alpha/possible-json-paths.json +3734 -0
  2. package/dist/bin/cli.js +63 -3
  3. package/dist/constants/syntax.js +26 -0
  4. package/dist/generator/config-compiler.d.ts +4 -3
  5. package/dist/generator/config-compiler.js +16 -7
  6. package/dist/generator/generators/classes/abstract-generator.d.ts +1 -0
  7. package/dist/generator/generators/documentation/md-generator.d.ts +1 -0
  8. package/dist/generator/generators/documentation/md-generator.js +3 -0
  9. package/dist/generator/generators/go/go-generator.d.ts +1 -0
  10. package/dist/generator/generators/go/go-generator.js +39 -4
  11. package/dist/generator/generators/go/templates/api-tests.mustache +0 -1
  12. package/dist/generator/generators/go/templates/index.mustache +1 -1
  13. package/dist/generator/generators/go/templates/json-normalizer.mustache +10 -12
  14. package/dist/generator/generators/go/templates/test-config.mustache +3 -3
  15. package/dist/generator/generators/go/templates/test-object.mustache +4 -8
  16. package/dist/generator/generators/go/templates/test-templates/validator-test.mustache +167 -0
  17. package/dist/generator/generators/go/templates/validation-code.mustache +1 -1
  18. package/dist/generator/generators/javascript/js-generator.d.ts +1 -0
  19. package/dist/generator/generators/javascript/js-generator.js +3 -0
  20. package/dist/generator/generators/python/py-generator.d.ts +1 -0
  21. package/dist/generator/generators/python/py-generator.js +3 -0
  22. package/dist/generator/generators/typescript/ts-generator.d.ts +1 -0
  23. package/dist/generator/generators/typescript/ts-generator.js +3 -0
  24. package/dist/services/schema-service.d.ts +2 -1
  25. package/dist/services/schema-service.js +2 -1
  26. package/dist/types/build.d.ts +1 -0
  27. package/dist/utils/general-utils/string-utils.d.ts +1 -0
  28. package/dist/utils/general-utils/string-utils.js +3 -0
  29. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -41,7 +41,7 @@ program
41
41
  console.log(Cli.description.info("Initializing compiler..."));
42
42
  await compiler.initialize(buildYaml);
43
43
  console.log(Cli.description.info("Generating validation code..."));
44
- await compiler.generateValidationFromBuild(functionName, output);
44
+ await compiler.generateValidationFromBuild(functionName, output, true);
45
45
  console.log(Cli.description.success(`Validation code generated successfully in ${output} for language ${lang}`));
46
46
  }
47
47
  catch (error) {
@@ -57,8 +57,56 @@ program
57
57
  .option("-o, --output <directory>", "Output directory for generated schema")
58
58
  .option("-f, --format <format>", "Output format (json, yaml,typescript)")
59
59
  .description("Generate L0 schema")
60
- .action(async () => {
61
- console.log("Schema generation command invoked");
60
+ .action(async (options) => {
61
+ console.log(Cli.title("Ondc Schema Generator"));
62
+ try {
63
+ const { config, output, format } = options;
64
+ if (!config || !output || !format) {
65
+ console.log(Cli.description.error("Please provide all required options: --config, --output, --format"));
66
+ process.exit(1);
67
+ }
68
+ console.log(Cli.description.info(`Generating L0 schema...`));
69
+ const buildPath = path.resolve(process.cwd(), config);
70
+ console.log(Cli.description.info(`Reading build file from ${buildPath}...`));
71
+ const buildYaml = await fs.readFile(buildPath, "utf-8");
72
+ const compiler = new ConfigCompiler(SupportedLanguages.Typescript);
73
+ await compiler.initialize(buildYaml);
74
+ const formatType = getSchemaFormat(format);
75
+ await compiler.generateL0Schema(output, formatType, true);
76
+ }
77
+ catch (error) {
78
+ const message = error instanceof Error ? error.message : String(error);
79
+ console.error(Cli.description.error(`Error: ${message}`));
80
+ process.exit(1);
81
+ }
82
+ });
83
+ program
84
+ .command("extract-payloads")
85
+ .alias("ext-payloads")
86
+ .description("Extract sample payloads from build.yaml")
87
+ .option("-c, --config <path>", "Path to build.yaml file")
88
+ .option("-o, --output <directory>", "Output directory for extracted payloads")
89
+ .action(async (options) => {
90
+ console.log(Cli.title("Ondc Sample Payload Extractor"));
91
+ try {
92
+ const { config, output } = options;
93
+ if (!config || !output) {
94
+ console.log(Cli.description.error("Please provide all required options: --config, --output"));
95
+ process.exit(1);
96
+ }
97
+ console.log(Cli.description.info(`Extracting sample payloads...`));
98
+ const buildPath = path.resolve(process.cwd(), config);
99
+ console.log(Cli.description.info(`Reading build file from ${buildPath}...`));
100
+ const buildYaml = await fs.readFile(buildPath, "utf-8");
101
+ const compiler = new ConfigCompiler(SupportedLanguages.Typescript);
102
+ await compiler.initialize(buildYaml);
103
+ await compiler.extractPayloadsFromBuild(output);
104
+ }
105
+ catch (error) {
106
+ const message = error instanceof Error ? error.message : String(error);
107
+ console.error(Cli.description.error(`Error: ${message}`));
108
+ process.exit(1);
109
+ }
62
110
  });
63
111
  program.parse();
64
112
  function getSupportedLanguage(lang) {
@@ -75,6 +123,18 @@ function getSupportedLanguage(lang) {
75
123
  throw new Error(`Unsupported language: ${lang}. Supported languages are: ${getValidLanguageOptions()}`);
76
124
  }
77
125
  }
126
+ function getSchemaFormat(format) {
127
+ switch (format.toLowerCase()) {
128
+ case "json":
129
+ return "json";
130
+ case "typescript":
131
+ return "typescript";
132
+ case "yaml":
133
+ throw new Error("YAML format is not yet supported");
134
+ default:
135
+ throw new Error(`Unsupported format: ${format}. Supported formats are: json, typescript`);
136
+ }
137
+ }
78
138
  function getValidLanguageOptions() {
79
139
  return Object.values(SupportedLanguages).join(", ");
80
140
  }
@@ -168,4 +168,30 @@ export const ReservedKeywords = new Set([
168
168
  "match",
169
169
  "case",
170
170
  "_",
171
+ // golang keywords
172
+ "break",
173
+ "default",
174
+ "func",
175
+ "interface",
176
+ "select",
177
+ "case",
178
+ "defer",
179
+ "go",
180
+ "map",
181
+ "struct",
182
+ "chan",
183
+ "else",
184
+ "goto",
185
+ "package",
186
+ "switch",
187
+ "const",
188
+ "fallthrough",
189
+ "if",
190
+ "range",
191
+ "type",
192
+ "continue",
193
+ "for",
194
+ "import",
195
+ "return",
196
+ "var",
171
197
  ]);
@@ -20,9 +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) => Promise<void>;
24
- generateL0Schema: (outputPath?: string, type?: "json" | "typescript") => Promise<void>;
23
+ generateCode: (valConfig: ValidationConfig, codeName?: string, minimal?: boolean, outputPath?: string, absolutePath?: boolean) => Promise<void>;
24
+ generateL0Schema: (outputPath?: string, type?: "json" | "typescript", absolutePath?: boolean) => Promise<void>;
25
25
  generateValidPaths: () => Promise<Record<string, string[]>>;
26
- generateValidationFromBuild: (codeName: string, outputPath: string) => Promise<void>;
26
+ generateValidationFromBuild: (codeName: string, outputPath: string, absolutePath?: boolean) => Promise<void>;
27
+ extractPayloadsFromBuild: (outputPath: string) => Promise<void>;
27
28
  }
28
29
  export {};
@@ -1,5 +1,5 @@
1
1
  import { loadAndDereferenceYaml } from "../utils/config-utils/yaml.js";
2
- import { SchemaExtactionService as SchemaExtractionService } from "../services/schema-service.js";
2
+ import { ExtractionService as SchemaExtractionService } from "../services/schema-service.js";
3
3
  import { SupportedLanguages } from "../types/compiler-types.js";
4
4
  import { TypescriptGenerator } from "./generators/typescript/ts-generator.js";
5
5
  import { ConfigValidator } from "./validators/config-validator.js";
@@ -57,7 +57,7 @@ export class ConfigCompiler {
57
57
  // throw new Error("validation failed");
58
58
  };
59
59
  // };
60
- this.generateCode = async (valConfig, codeName = "L1-Validations", minimal = false, outputPath = "./") => {
60
+ this.generateCode = async (valConfig, codeName = "L1-Validations", minimal = false, outputPath = "./", absolutePath = false) => {
61
61
  valConfig = JSON.parse(JSON.stringify(valConfig));
62
62
  if (this.generatorConfig?.duplicateVariablesInChildren) {
63
63
  valConfig = duplicateVariablesInChildren(valConfig);
@@ -69,7 +69,9 @@ export class ConfigCompiler {
69
69
  await this.performValidations(valConfig);
70
70
  }
71
71
  // Generate code based on the language
72
- const targetPath = `${outputPath}generated/${codeName}`;
72
+ const targetPath = absolutePath
73
+ ? outputPath
74
+ : `${outputPath}generated/${codeName}`;
73
75
  switch (this.language) {
74
76
  case SupportedLanguages.Typescript:
75
77
  await new TypescriptGenerator(valConfig, this.errorDefinitions ?? [], targetPath).generateCode({
@@ -95,11 +97,13 @@ export class ConfigCompiler {
95
97
  throw new Error("Language not supported");
96
98
  }
97
99
  };
98
- this.generateL0Schema = async (outputPath = "./", type = "typescript") => {
100
+ this.generateL0Schema = async (outputPath = "./", type = "typescript", absolutePath = false) => {
99
101
  if (!this.jsonSchemas) {
100
102
  throw new Error("Schemas not initialized");
101
103
  }
102
- const targetPath = `${outputPath}generated/L0-schemas/`;
104
+ const targetPath = absolutePath
105
+ ? outputPath
106
+ : `${outputPath}generated/L0-schemas/`;
103
107
  for (const schema in this.jsonSchemas) {
104
108
  const json = this.jsonSchemas[schema];
105
109
  if (type === "typescript") {
@@ -129,13 +133,18 @@ export class ConfigCompiler {
129
133
  // );
130
134
  return this.possibleJsonPaths;
131
135
  };
132
- this.generateValidationFromBuild = async (codeName, outputPath) => {
136
+ this.generateValidationFromBuild = async (codeName, outputPath, absolutePath = false) => {
133
137
  if (!this.buildData)
134
138
  throw new Error("Build data not initialized");
135
139
  const valConfig = this.buildData["x-validations"];
136
140
  if (!valConfig)
137
141
  throw new Error("No validation config found in build data");
138
- await this.generateCode(valConfig, codeName, false, outputPath);
142
+ await this.generateCode(valConfig, codeName, false, outputPath, absolutePath);
143
+ };
144
+ this.extractPayloadsFromBuild = async (outputPath) => {
145
+ if (!this.buildData)
146
+ throw new Error("Build data not initialized");
147
+ const payloads = this.SchemaExtractionService.extractPayloadExamples(this.buildData);
139
148
  };
140
149
  this.language = language;
141
150
  this.SchemaExtractionService = new SchemaExtractionService();
@@ -11,4 +11,5 @@ export declare abstract class CodeGenerator {
11
11
  abstract generateSessionDataCode(): Promise<void>;
12
12
  abstract generateValidationCode(): Promise<void>;
13
13
  abstract generateCode(codeConfig: CodeGeneratorProps): Promise<void>;
14
+ abstract generateUnitTestingCode(): Promise<void>;
14
15
  }
@@ -2,6 +2,7 @@ import { TestObject } from "../../../types/config-types.js";
2
2
  import { CodeGenerator } from "../classes/abstract-generator.js";
3
3
  export declare class MarkdownDocGenerator extends CodeGenerator {
4
4
  generateSessionDataCode(): Promise<void>;
5
+ generateUnitTestingCode(): Promise<void>;
5
6
  generateValidationCode: () => Promise<void>;
6
7
  generateCode: () => Promise<void>;
7
8
  generateMarkdownForTest: (testObject: TestObject) => string;
@@ -54,4 +54,7 @@ export class MarkdownDocGenerator extends CodeGenerator {
54
54
  generateSessionDataCode() {
55
55
  throw new Error("Method not implemented.");
56
56
  }
57
+ generateUnitTestingCode() {
58
+ throw new Error("Method not implemented.");
59
+ }
57
60
  }
@@ -10,4 +10,5 @@ export declare class GoGenerator extends CodeGenerator {
10
10
  private createVariablesCode;
11
11
  private createValidationLogicCode;
12
12
  private CreateErrorMarkdown;
13
+ generateUnitTestingCode(): Promise<void>;
13
14
  }
@@ -8,7 +8,7 @@ import { writeAndFormatCode } from "../../../utils/fs-utils.js";
8
8
  import { collectLoadData } from "../../../utils/config-utils/load-variables.js";
9
9
  import { compileInputToGo } from "./go-ast.js";
10
10
  import { getVariablesFromTest } from "../../../utils/general-utils/test-object-utils.js";
11
- import { ConvertArrayToStringGoStyle } from "../../../utils/general-utils/string-utils.js";
11
+ import { ConvertArrayToStringGoStyle, removeAllSpecialCharacters, } from "../../../utils/general-utils/string-utils.js";
12
12
  import { markdownMessageGenerator } from "../documentation/markdown-message-generator.js";
13
13
  const __filename = fileURLToPath(import.meta.url);
14
14
  const __dirname = path.dirname(__filename);
@@ -34,6 +34,7 @@ export class GoGenerator extends CodeGenerator {
34
34
  await writeAndFormatCode(this.rootPath, `./${packageName}/main-validator.go`, this.generateIndexFile(Object.keys(this.validationConfig[ConfigSyntax.Tests]), codeConfig.codeName), "go");
35
35
  await writeAndFormatCode(this.rootPath, `./${packageName}/go.mod`, goMod, "text");
36
36
  await this.generateSessionDataCode();
37
+ await this.generateUnitTestingCode();
37
38
  };
38
39
  this.generateTestFunction = async (testObject) => {
39
40
  const template = readFileSync(path.resolve(__dirname, "./templates/test-object.mustache"), "utf-8");
@@ -255,11 +256,38 @@ ${importList.map((imp) => `\t${imp}`).join("\n")}
255
256
  createVariablesCode(testObject) {
256
257
  const variables = [];
257
258
  const varNames = getVariablesFromTest(testObject);
259
+ const returnStatement = testObject[TestObjectSyntax.Return];
260
+ const continueStatement = testObject[TestObjectSyntax.Continue];
261
+ let elementsList = [];
262
+ // REPLACE ALL special WITH empty AND SPLIT
263
+ if (typeof returnStatement === "string") {
264
+ elementsList = removeAllSpecialCharacters(returnStatement).split(" ");
265
+ }
266
+ if (continueStatement) {
267
+ const contElements = removeAllSpecialCharacters(continueStatement).split(" ");
268
+ for (const elem of contElements) {
269
+ if (!elementsList.includes(elem)) {
270
+ elementsList.push(elem);
271
+ }
272
+ }
273
+ }
258
274
  for (const name of varNames) {
259
275
  const value = testObject[name];
260
- const final = typeof value === "string"
261
- ? `validationutils.GetJsonPath(testObjMap, "${value}",true)`
262
- : ConvertArrayToStringGoStyle(value);
276
+ if (!elementsList.includes(name)) {
277
+ console.log(`Variable ${name} not used in return or continue statements, skipping generation.: \n ${returnStatement} \n ${continueStatement}`);
278
+ console.log(elementsList);
279
+ continue;
280
+ }
281
+ let final = "";
282
+ if (value.includes("_EXTERNAL")) {
283
+ final = `validationutils.GetJsonPath(input, "${value}",true)`;
284
+ }
285
+ else {
286
+ final =
287
+ typeof value === "string"
288
+ ? `validationutils.GetJsonPath(testObjMap, "${value}",true)`
289
+ : ConvertArrayToStringGoStyle(value);
290
+ }
263
291
  variables.push({
264
292
  name: name,
265
293
  value: final,
@@ -316,6 +344,13 @@ ${importList.map((imp) => `\t${imp}`).join("\n")}
316
344
  CreateErrorMarkdown(testObject, skipList) {
317
345
  return markdownMessageGenerator(testObject[TestObjectSyntax.Return], testObject, testObject[TestObjectSyntax.Name], skipList);
318
346
  }
347
+ async generateUnitTestingCode() {
348
+ const testTemplate = readFileSync(path.resolve(__dirname, "./templates/test-templates/validator-test.mustache"), "utf-8");
349
+ const finalTestCode = Mustache.render(testTemplate, {
350
+ functionName: this.codeConfig?.codeName ?? "L1Validations",
351
+ });
352
+ await writeAndFormatCode(this.rootPath, `./${packageName}/main-validator_test.go`, finalTestCode, "go");
353
+ }
319
354
  }
320
355
  function stringToCaps(str) {
321
356
  return str.charAt(0).toUpperCase() + str.slice(1);
@@ -4,7 +4,6 @@ package jsonvalidations
4
4
 
5
5
  import (
6
6
  "validationpkg/validationutils"
7
- "fmt"
8
7
  )
9
8
 
10
9
  func {{apiName}}_Tests(input validationutils.ValidationInput) ([]validationutils.ValidationOutput, error) {
@@ -1,5 +1,5 @@
1
1
  // Code generated by github.com/ONDC-Official/automation-validation-compiler, DO NOT EDIT.
2
- package main
2
+ package validationpkg
3
3
 
4
4
  {{{importCode}}}
5
5
 
@@ -2,14 +2,11 @@
2
2
 
3
3
  package validationutils
4
4
 
5
- import (
6
- "encoding/json"
7
- )
8
5
 
9
6
  // NormalizeKeys normalizes JSON structures so that:
10
- // - All objects with the same property name share the union of keys seen anywhere
11
- // - All objects inside the same array share the union of keys at that array level
12
- // - Missing keys are filled with nil
7
+ // - All objects with the same property name share the union of keys seen anywhere
8
+ // - All objects inside the same array share the union of keys at that array level
9
+ // - Missing keys are filled with nil
13
10
  func NormalizeKeys(input interface{}) interface{} {
14
11
  // Step 1: Collect templates by property name
15
12
  templatesByPropName := make(map[string]map[string]struct{})
@@ -67,12 +64,12 @@ func applyTemplates(node interface{}, templates map[string]map[string]struct{})
67
64
  if obj, ok := item.(map[string]interface{}); ok {
68
65
  // Create new object with array union keys
69
66
  next := make(map[string]interface{})
70
-
67
+
71
68
  // Copy existing keys
72
69
  for k, val := range obj {
73
70
  next[k] = val
74
71
  }
75
-
72
+
76
73
  // Add missing keys from array union
77
74
  for key := range arrayUnion {
78
75
  if _, exists := next[key]; !exists {
@@ -141,15 +138,16 @@ func fillFromTemplate(propName string, obj map[string]interface{}, templates map
141
138
  return filled
142
139
  }
143
140
 
144
- // DeepCloneJSON creates a deep clone of a JSON-serializable structure
141
+ // DeepCloneJSON creates a deep clone of a JSON-serializable structure using sonic
145
142
  func DeepCloneJSON(v interface{}) interface{} {
146
- b, err := json.Marshal(v)
143
+ /* b, err := sonic.Marshal(v)
147
144
  if err != nil {
148
145
  panic(err) // or handle error
149
146
  }
150
147
  var out interface{}
151
- if err := json.Unmarshal(b, &out); err != nil {
148
+ if err := sonic.Unmarshal(b, &out); err != nil {
152
149
  panic(err)
153
150
  }
154
- return out
151
+ return out */
152
+ return v
155
153
  }
@@ -49,9 +49,9 @@ type ExternalData struct {
49
49
 
50
50
  // ValidationInput represents the input data for validation functions
51
51
  type ValidationInput struct {
52
- Payload interface{}
53
- ExternalData ExternalData
54
- Config ValidationConfig
52
+ Payload interface{} `json:"payload"`
53
+ ExternalData ExternalData `json:"_EXTERNAL,omitempty"`
54
+ Config ValidationConfig `json:"_CONFIG,omitempty"`
55
55
  }
56
56
 
57
57
  // TestFunction is a function type that takes ValidationInput and returns a slice of ValidationOutput
@@ -4,13 +4,9 @@ var {{name}} = func (input validationutils.ValidationInput) ([]validationutils.V
4
4
  subResults := make([]validationutils.ValidationOutput, 0)
5
5
  valid := true
6
6
  configureDebugInfo := ""
7
- for _, testObj := range scope {
8
- testObjMap, ok := validationutils.DeepCloneJSON(testObj).(map[string]interface{})
9
- if !ok {
10
- return nil, fmt.Errorf("Invalid object structure in scope for test {{name}}")
11
- }
12
-
13
- testObjMap["_EXTERNAL"] = validationutils.DeepCloneJSON(input.ExternalData)
7
+ for _, testObjMap := range scope {
8
+ validationutils.UnusedFunction(testObjMap)
9
+ // testObjMap["_EXTERNAL"] = validationutils.DeepCloneJSON(input.ExternalData)
14
10
 
15
11
  {{#variables}}
16
12
  {{name}} := {{{value}}}
@@ -26,7 +22,7 @@ var {{name}} = func (input validationutils.ValidationInput) ([]validationutils.V
26
22
 
27
23
  {{{validationCode}}}
28
24
 
29
- delete(testObjMap, "_EXTERNAL")
25
+ // delete(testObjMap, "_EXTERNAL")
30
26
  }
31
27
 
32
28
  result := validationutils.ValidationOutput{
@@ -0,0 +1,167 @@
1
+ // Code generated by github.com/ONDC-Official/automation-validation-compiler, DO NOT EDIT.
2
+
3
+ package validationpkg
4
+
5
+
6
+ // How to run:
7
+ //
8
+ // 1) Create example payload files under ./examples (relative to this package):
9
+ // validationpkg/examples/search.json
10
+ // validationpkg/examples/on_search.json
11
+ // Each file must contain a JSON array of payload objects.
12
+ //
13
+ // 2) From the validationpkg module directory, run:
14
+ // go test -run TestPerformL1validations_Examples -v
15
+ // Or from the repo root:
16
+ // go test ./ondcValidator/validationpkg -run TestPerformL1validations_Examples -v
17
+ //
18
+ // Outputs are written under ./examples_output/<action>/case-XXX/output.json.
19
+
20
+
21
+ import (
22
+ "encoding/json"
23
+ "fmt"
24
+ "os"
25
+ "path/filepath"
26
+ "strings"
27
+ "testing"
28
+
29
+ "validationpkg/validationutils"
30
+ )
31
+
32
+ type noopStorage struct{}
33
+
34
+ func (n *noopStorage) SaveKey(uniquePrefix string, key string, value string) error { return nil }
35
+ func (n *noopStorage) GetKey(uniquePrefix string, key string) (string, error) {
36
+ return "", fmt.Errorf("noop storage: key not found")
37
+ }
38
+ func (n *noopStorage) DeleteKey(uniquePrefix string, key string) error { return nil }
39
+ func (n *noopStorage) ListKeys(uniquePrefix string) ([]string, error) {
40
+ return nil, fmt.Errorf("noop storage: list not supported")
41
+ }
42
+ func (n *noopStorage) ClearStorage() error { return nil }
43
+ func (n *noopStorage) KeyExists(uniquePrefix string, key string) (bool, error) { return false, nil }
44
+
45
+ type validationRunOutput struct {
46
+ Action string `json:"action"`
47
+ Case int `json:"case"`
48
+ UniqueKey string `json:"uniqueKey"`
49
+ Error string `json:"error,omitempty"`
50
+ Results []validationutils.ValidationOutput `json:"results,omitempty"`
51
+ }
52
+
53
+ func TestPerformL1validations_Examples(t *testing.T) {
54
+ examplesDir := "examples"
55
+ if _, err := os.Stat(examplesDir); err != nil {
56
+ if os.IsNotExist(err) {
57
+ t.Skipf("%s directory not found; skipping example-based validations", examplesDir)
58
+ }
59
+ t.Fatalf("failed to stat %s: %v", examplesDir, err)
60
+ }
61
+
62
+ files, err := filepath.Glob(filepath.Join(examplesDir, "*.json"))
63
+ if err != nil {
64
+ t.Fatalf("failed to glob examples: %v", err)
65
+ }
66
+ if len(files) == 0 {
67
+ t.Skipf("no example files found in %s", examplesDir)
68
+ }
69
+
70
+ outputRoot := "examples_output"
71
+ if err := os.MkdirAll(outputRoot, 0o755); err != nil {
72
+ t.Fatalf("failed to create output dir %s: %v", outputRoot, err)
73
+ }
74
+
75
+ store := &noopStorage{}
76
+
77
+ for _, filePath := range files {
78
+ action := strings.TrimSuffix(filepath.Base(filePath), filepath.Ext(filePath))
79
+
80
+ t.Run(action, func(t *testing.T) {
81
+ data, err := os.ReadFile(filePath)
82
+ if err != nil {
83
+ t.Fatalf("failed to read %s: %v", filePath, err)
84
+ }
85
+
86
+ var payloads []json.RawMessage
87
+ if err := json.Unmarshal(data, &payloads); err != nil {
88
+ t.Fatalf("%s must contain a JSON array of payloads: %v", filePath, err)
89
+ }
90
+ if len(payloads) == 0 {
91
+ t.Skipf("no payloads in %s", filePath)
92
+ }
93
+
94
+ for i, raw := range payloads {
95
+ caseNum := i + 1
96
+
97
+ var payload interface{}
98
+ if err := json.Unmarshal(raw, &payload); err != nil {
99
+ t.Errorf("case %d: payload is not valid JSON: %v", caseNum, err)
100
+ continue
101
+ }
102
+
103
+ uniqueKey := extractTransactionID(payload)
104
+ if uniqueKey == "" {
105
+ uniqueKey = fmt.Sprintf("%s-case-%03d", action, caseNum)
106
+ }
107
+
108
+ cfg := &validationutils.ValidationConfig{
109
+ StateFullValidations: false,
110
+ Debug: false,
111
+ OnlyInvalid: true,
112
+ HideParentErrors: true,
113
+ UniqueKey: &uniqueKey,
114
+ Store: store,
115
+ }
116
+
117
+ results, runErr := Perform{{functionName}}(action, payload, cfg, validationutils.ExternalData{})
118
+ out := validationRunOutput{
119
+ Action: action,
120
+ Case: caseNum,
121
+ UniqueKey: uniqueKey,
122
+ Results: results,
123
+ }
124
+ if runErr != nil {
125
+ out.Error = runErr.Error()
126
+ }
127
+
128
+ caseDir := filepath.Join(outputRoot, action, fmt.Sprintf("case-%03d", caseNum))
129
+ if err := os.MkdirAll(caseDir, 0o755); err != nil {
130
+ t.Errorf("case %d: failed to create output dir %s: %v", caseNum, caseDir, err)
131
+ continue
132
+ }
133
+
134
+ encoded, err := json.MarshalIndent(out, "", " ")
135
+ if err != nil {
136
+ t.Errorf("case %d: failed to marshal output: %v", caseNum, err)
137
+ continue
138
+ }
139
+
140
+ if err := os.WriteFile(filepath.Join(caseDir, "output.json"), encoded, 0o644); err != nil {
141
+ t.Errorf("case %d: failed to write output.json: %v", caseNum, err)
142
+ }
143
+
144
+ if runErr != nil {
145
+ t.Errorf("case %d: PerformL1validations returned error: %v", caseNum, runErr)
146
+ }
147
+ }
148
+ })
149
+ }
150
+ }
151
+
152
+ func extractTransactionID(payload interface{}) string {
153
+ root, ok := payload.(map[string]interface{})
154
+ if !ok {
155
+ return ""
156
+ }
157
+ ctx, ok := root["context"].(map[string]interface{})
158
+ if !ok {
159
+ return ""
160
+ }
161
+ if v, ok := ctx["transaction_id"]; ok {
162
+ if s, ok := v.(string); ok {
163
+ return s
164
+ }
165
+ }
166
+ return ""
167
+ }
@@ -59,7 +59,7 @@ if(!validate){
59
59
  FedConfig: configureDebugInfo,
60
60
  },
61
61
  }
62
- delete(testObjMap, "_EXTERNAL")
62
+ // delete(testObjMap, "_EXTERNAL")
63
63
  return []validationutils.ValidationOutput{result},nil
64
64
  }
65
65
 
@@ -1,6 +1,7 @@
1
1
  import { CodeGenerator, CodeGeneratorProps } from "../classes/abstract-generator.js";
2
2
  export declare class JavascriptGenerator extends CodeGenerator {
3
3
  private tempTsPath;
4
+ generateUnitTestingCode(): Promise<void>;
4
5
  constructor(validationConfig: any, errorCodes: any[], rootPath?: string);
5
6
  generateSessionDataCode: () => Promise<never>;
6
7
  generateValidationCode: () => Promise<void>;
@@ -12,6 +12,9 @@ const execAsync = promisify(exec);
12
12
  const __filename = fileURLToPath(import.meta.url);
13
13
  const __dirname = path.dirname(__filename);
14
14
  export class JavascriptGenerator extends CodeGenerator {
15
+ generateUnitTestingCode() {
16
+ throw new Error("Method not implemented.");
17
+ }
15
18
  constructor(validationConfig, errorCodes, rootPath = "./") {
16
19
  super(validationConfig, errorCodes, rootPath);
17
20
  this.generateSessionDataCode = async () => {
@@ -2,6 +2,7 @@ import { TestObject } from "../../../types/config-types.js";
2
2
  import { CodeGenerator, CodeGeneratorProps } from "../classes/abstract-generator.js";
3
3
  export declare class PythonGenerator extends CodeGenerator {
4
4
  codeConfig: CodeGeneratorProps | undefined;
5
+ generateUnitTestingCode(): Promise<void>;
5
6
  generateSessionDataCode: () => Promise<void>;
6
7
  generateValidationCode: () => Promise<void>;
7
8
  generateCode: (codeConfig: CodeGeneratorProps) => Promise<void>;
@@ -185,6 +185,9 @@ export class PythonGenerator extends CodeGenerator {
185
185
  }
186
186
  };
187
187
  }
188
+ generateUnitTestingCode() {
189
+ throw new Error("Method not implemented.");
190
+ }
188
191
  CreateErrorMarkdown(testObject, skipList) {
189
192
  return markdownMessageGenerator(testObject[TestObjectSyntax.Return], testObject, testObject[TestObjectSyntax.Name], skipList);
190
193
  }
@@ -15,4 +15,5 @@ export declare class TypescriptGenerator extends CodeGenerator {
15
15
  private generateErrorFile;
16
16
  private getExternalKeys;
17
17
  private generateIndexFile;
18
+ generateUnitTestingCode(): Promise<void>;
18
19
  }
@@ -286,4 +286,7 @@ export class TypescriptGenerator extends CodeGenerator {
286
286
  masterFunction: masterFunction,
287
287
  });
288
288
  }
289
+ generateUnitTestingCode() {
290
+ throw new Error("Method not implemented.");
291
+ }
289
292
  }
@@ -1,6 +1,7 @@
1
1
  import { JSONSchema7 } from "json-schema";
2
2
  import { BUILD_TYPE } from "../types/build.js";
3
- export declare class SchemaExtactionService {
3
+ export declare class ExtractionService {
4
4
  extractSchemas: (data: BUILD_TYPE, removeRequired: boolean, removeEnums: boolean) => Promise<Record<string, JSONSchema7>>;
5
5
  extractPossiblePaths: (schemas: Record<string, JSONSchema7>) => Record<string, string[]>;
6
+ extractPayloadExamples: (data: BUILD_TYPE) => void;
6
7
  }