ondc-code-generator 0.5.42 → 0.5.51

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.
@@ -1,2 +1,8 @@
1
1
  import { TestObject } from "../../../types/config-types.js";
2
+ /**
3
+ * Generates the human-friendly Markdown doc:
4
+ * - Title: "### Validation: <NAME>"
5
+ * - Body: top-level AND/OR group (no 1.1.1 pointers)
6
+ * - Skip: blockquoted "Skip if:" with a unified "Any of these are true:" list
7
+ */
2
8
  export declare function markdownMessageGenerator(returnInput: string, variableValues: TestObject, startingPointer: string, skipInput?: string[]): string;
@@ -1,26 +1,34 @@
1
- import { CompileToMarkdown } from "../../../services/return-complier/ast-functions/compile-to-markdown.js";
1
+ import { CompileToMarkdown, CompileToMarkdownForSkip, } from "../../../services/return-complier/ast-functions/compile-to-markdown.js";
2
2
  import { buildAstFromInput } from "../../../services/return-complier/combined.js";
3
3
  import Mustache from "mustache";
4
- import { addBlockquoteToMarkdown, addTabToMarkdown, ConvertArrayToStringsInTestObject, } from "../../../utils/general-utils/string-utils.js";
4
+ import { addBlockquoteToMarkdown, ConvertArrayToStringsInTestObject, } from "../../../utils/general-utils/string-utils.js";
5
5
  import { TestObjectSyntax } from "../../../constants/syntax.js";
6
+ /**
7
+ * Generates the human-friendly Markdown doc:
8
+ * - Title: "### Validation: <NAME>"
9
+ * - Body: top-level AND/OR group (no 1.1.1 pointers)
10
+ * - Skip: blockquoted "Skip if:" with a unified "Any of these are true:" list
11
+ */
6
12
  export function markdownMessageGenerator(returnInput, variableValues, startingPointer, skipInput) {
7
13
  const ast = buildAstFromInput(returnInput);
8
14
  const returnTemplate = variableValues[TestObjectSyntax.Description]
9
15
  ? variableValues[TestObjectSyntax.Description]
10
- : CompileToMarkdown(ast, startingPointer, 0, false);
11
- let finalReturn = Mustache.render(returnTemplate, ConvertArrayToStringsInTestObject(variableValues));
12
- if (skipInput) {
13
- let skipMarkdown = `Note: **Condition ${startingPointer}** can be skipped if the following conditions are met:`;
14
- const letters = "BCDEFGHIJKLMNOPQRSTUVWXYZ";
15
- let index = 0;
16
- for (const skip of skipInput) {
17
- const skipAst = buildAstFromInput(skip);
18
- const skipTemplate = CompileToMarkdown(skipAst, letters[index], 0, false);
19
- const finalSkip = Mustache.render(skipTemplate, ConvertArrayToStringsInTestObject(variableValues));
20
- skipMarkdown += `\n\n${finalSkip}`;
21
- index++;
16
+ : CompileToMarkdown(ast, /*topLevel*/ true, /*depth*/ 0, /*forNot*/ false);
17
+ let finalReturn = `#### **${startingPointer}**\n\n` +
18
+ Mustache.render(returnTemplate, ConvertArrayToStringsInTestObject(variableValues));
19
+ if (skipInput && skipInput.length > 0) {
20
+ let skipMarkdown = `**Skip if:**\n`;
21
+ for (const expr of skipInput) {
22
+ const skAst = buildAstFromInput(expr);
23
+ const skBlock = CompileToMarkdownForSkip(skAst,
24
+ /*topLevel*/ false,
25
+ /*depth*/ 2,
26
+ /*forNot*/ false);
27
+ skipMarkdown += `\n${skBlock}`;
22
28
  }
23
- const blockSkip = addTabToMarkdown(addBlockquoteToMarkdown(skipMarkdown));
29
+ // Render the skip section with Mustache so {{{attr}}} etc. interpolate
30
+ const renderedSkip = Mustache.render(skipMarkdown, ConvertArrayToStringsInTestObject(variableValues));
31
+ const blockSkip = addBlockquoteToMarkdown(renderedSkip);
24
32
  finalReturn += `\n\n${blockSkip}`;
25
33
  }
26
34
  return finalReturn;
package/dist/index.js CHANGED
@@ -42,5 +42,5 @@ export { ConfigCompiler };
42
42
  // };
43
43
  // (async () => {
44
44
  // await main();
45
- // console.log("Code generation completed.");
45
+ // console.log("========== Code generation completed. ==========");
46
46
  // })();
@@ -1,2 +1,24 @@
1
1
  import { AstNode } from "../ast.js";
2
- export declare function CompileToMarkdown(ast: AstNode, pointer: string, depth: number | undefined, forNot: boolean): string;
2
+ /**
3
+ * Public API: Compile an AST to *readable* Markdown with:
4
+ * - No pointer numbering (no 1.1.1)
5
+ * - Natural language groups ("All of the following…" / "Any of these…")
6
+ * - Leaves rendered as short sentences
7
+ *
8
+ * @param ast
9
+ * @param topLevel Whether this is the very first group under the title
10
+ * @param depth Controls bullet/indent
11
+ * @param forNot Carries NOT (!) context downward
12
+ */
13
+ export declare function CompileToMarkdown(ast: AstNode, topLevel?: boolean, depth?: number, forNot?: boolean): string;
14
+ /**
15
+ * Skip-specific version: Compile an AST to *readable* Markdown for skip conditions with:
16
+ * - More natural language ("{{lhs}} is not in the payload" instead of "{{lhs}} must not be present")
17
+ * - Simpler phrasing suitable for skip conditions
18
+ *
19
+ * @param ast
20
+ * @param topLevel Whether this is the very first group under the title
21
+ * @param depth Controls bullet/indent
22
+ * @param forNot Carries NOT (!) context downward
23
+ */
24
+ export declare function CompileToMarkdownForSkip(ast: AstNode, topLevel?: boolean, depth?: number, forNot?: boolean): string;
@@ -1,66 +1,133 @@
1
1
  import { AllIn, AnyIn, AreUnique, ArePresent, EqualTo, FollowRegex, GreaterThan, LessThan, NoneIn, } from "../tokens.js";
2
+ /**
3
+ * Leaf (unary/binary) message templates, rewritten to be short & human-friendly.
4
+ * NOTE: We keep triple-mustaches so Mustache can expand safely.
5
+ */
2
6
  const uniaryMessages = {
3
- [AreUnique.LABEL ?? "are unique"]: (variable, forNot) => `all values of {{{${variable}}}} must${forNot ? " **not**" : ""} be unique`,
4
- [ArePresent.LABEL ?? "are present"]: (variable, forNot) => `{{{${variable}}}} must${forNot ? " **not**" : ""} be present in the payload`,
7
+ [AreUnique.LABEL ?? "are unique"]: (variable, forNot) => `All values of {{{${variable}}}} ${forNot ? "must **not** be unique" : "are unique"}`,
8
+ [ArePresent.LABEL ?? "are present"]: (variable, forNot) => `{{{${variable}}}} ${forNot ? "must **not** be present" : "must be present"} in the payload`,
9
+ };
10
+ /**
11
+ * Skip-specific message templates for more natural language in skip conditions
12
+ */
13
+ const skipUniaryMessages = {
14
+ [AreUnique.LABEL ?? "are unique"]: (variable, forNot) => `{{{${variable}}}} values ${forNot ? "are not unique" : "are unique"}`,
15
+ [ArePresent.LABEL ?? "are present"]: (variable, forNot) => `{{{${variable}}}} ${forNot ? "is not in the payload" : "is in the payload"}`,
5
16
  };
6
17
  const binaryMessages = {
7
- [AllIn.LABEL ?? "all in"]: (lhs, rhs, forNot) => `every element of {{{${lhs}}}} must${forNot ? " **not**" : ""} be in {{{${rhs}}}}`,
8
- [AnyIn.LABEL ?? "any in"]: (lhs, rhs, forNot) => `at least one element of {{{${lhs}}}} must${forNot ? " **not**" : ""} be in {{{${rhs}}}}`,
9
- [FollowRegex.LABEL ?? "follow regex"]: (lhs, rhs, forNot) => `all elements of {{{${lhs}}}} must${forNot ? " **not**" : ""} follow every regex in {{{${rhs}}}}`,
10
- [NoneIn.LABEL ?? "none in"]: (lhs, rhs, forNot) => `no element of {{{${lhs}}}} must${forNot ? " **not**" : ""} be in {{{${rhs}}}}`,
11
- [EqualTo.LABEL ?? "equal to"]: (lhs, rhs, forNot) => `{{{${lhs}}}} must${forNot ? " **not**" : ""} be equal to {{{${rhs}}}}`,
12
- [GreaterThan.LABEL ?? "greater than"]: (lhs, rhs, forNot) => `{{{${lhs}}}} must${forNot ? " **not**" : ""} be greater than {{{${rhs}}}}`,
13
- [LessThan.LABEL ?? "less than"]: (lhs, rhs, forNot) => `{{{${lhs}}}} must${forNot ? " **not**" : ""} be less than {{{${rhs}}}}`,
18
+ [AllIn.LABEL ?? "all in"]: (lhs, rhs, forNot) => `${forNot ? "Not all" : "All"} elements of {{{${lhs}}}} ${forNot ? "may be" : "must be"} in {{{${rhs}}}}`,
19
+ [AnyIn.LABEL ?? "any in"]: (lhs, rhs, forNot) => `${forNot ? "None of" : "At least one of"} {{{${lhs}}}} ${forNot ? "may be" : "must be"} in {{{${rhs}}}}`,
20
+ [FollowRegex.LABEL ?? "follow regex"]: (lhs, rhs, forNot) => `${forNot ? "Some elements of" : "All elements of"} {{{${lhs}}}} ${forNot ? "may fail to" : "must"} follow every regex in {{{${rhs}}}}`,
21
+ [NoneIn.LABEL ?? "none in"]: (lhs, rhs, forNot) => `${forNot ? "Some elements of" : "No element of"} {{{${lhs}}}} ${forNot ? "may be in" : "must be in"} {{{${rhs}}}}`,
22
+ [EqualTo.LABEL ?? "equal to"]: (lhs, rhs, forNot) => `{{{${lhs}}}} ${forNot ? "must **not** equal" : "must equal"} {{{${rhs}}}}`,
23
+ [GreaterThan.LABEL ?? "greater than"]: (lhs, rhs, forNot) => `{{{${lhs}}}} ${forNot ? "must **not** be greater than" : "must be greater than"} {{{${rhs}}}}`,
24
+ [LessThan.LABEL ?? "less than"]: (lhs, rhs, forNot) => `{{{${lhs}}}} ${forNot ? "must **not** be less than" : "must be less than"} {{{${rhs}}}}`,
25
+ };
26
+ /**
27
+ * Skip-specific binary message templates for more natural language in skip conditions
28
+ */
29
+ const skipBinaryMessages = {
30
+ [AllIn.LABEL ?? "all in"]: (lhs, rhs, forNot) => `${forNot ? "not all" : "all"} elements of {{{${lhs}}}} are in {{{${rhs}}}}`,
31
+ [AnyIn.LABEL ?? "any in"]: (lhs, rhs, forNot) => `${forNot ? "none of" : "any of"} {{{${lhs}}}} are in {{{${rhs}}}}`,
32
+ [FollowRegex.LABEL ?? "follow regex"]: (lhs, rhs, forNot) => `{{{${lhs}}}} ${forNot ? "doesn't follow" : "follows"} regex {{{${rhs}}}}`,
33
+ [NoneIn.LABEL ?? "none in"]: (lhs, rhs, forNot) => `${forNot ? "some" : "none"} of {{{${lhs}}}} are in {{{${rhs}}}}`,
34
+ [EqualTo.LABEL ?? "equal to"]: (lhs, rhs, forNot) => `{{{${lhs}}}} ${forNot ? "is not equal to" : "equals"} {{{${rhs}}}}`,
35
+ [GreaterThan.LABEL ?? "greater than"]: (lhs, rhs, forNot) => `{{{${lhs}}}} ${forNot ? "is not greater than" : "is greater than"} {{{${rhs}}}}`,
36
+ [LessThan.LABEL ?? "less than"]: (lhs, rhs, forNot) => `{{{${lhs}}}} ${forNot ? "is not less than" : "is less than"} {{{${rhs}}}}`,
14
37
  };
15
- export function CompileToMarkdown(ast, pointer, depth = 0, forNot) {
16
- const indent = " ".repeat(depth); // 2 spaces per depth level
17
- // Helper function to indent multi-line strings
18
- function indentMultilineString(str, indentLevel) {
19
- const subIndent = " ".repeat(indentLevel);
20
- return str
38
+ /**
39
+ * Public API: Compile an AST to *readable* Markdown with:
40
+ * - No pointer numbering (no 1.1.1)
41
+ * - Natural language groups ("All of the following…" / "Any of these…")
42
+ * - Leaves rendered as short sentences
43
+ *
44
+ * @param ast
45
+ * @param topLevel Whether this is the very first group under the title
46
+ * @param depth Controls bullet/indent
47
+ * @param forNot Carries NOT (!) context downward
48
+ */
49
+ export function CompileToMarkdown(ast, topLevel = true, depth = 0, forNot = false) {
50
+ return compileToMarkdownInternal(ast, topLevel, depth, forNot, false);
51
+ }
52
+ /**
53
+ * Skip-specific version: Compile an AST to *readable* Markdown for skip conditions with:
54
+ * - More natural language ("{{lhs}} is not in the payload" instead of "{{lhs}} must not be present")
55
+ * - Simpler phrasing suitable for skip conditions
56
+ *
57
+ * @param ast
58
+ * @param topLevel Whether this is the very first group under the title
59
+ * @param depth Controls bullet/indent
60
+ * @param forNot Carries NOT (!) context downward
61
+ */
62
+ export function CompileToMarkdownForSkip(ast, topLevel = true, depth = 0, forNot = false) {
63
+ return compileToMarkdownInternal(ast, topLevel, depth, forNot, true);
64
+ }
65
+ /**
66
+ * Internal implementation shared by both CompileToMarkdown and CompileToMarkdownForSkip
67
+ */
68
+ function compileToMarkdownInternal(ast, topLevel = true, depth = 0, forNot = false, isSkip = false) {
69
+ const indent = " ".repeat(depth);
70
+ // Render a group label (AND/OR) with correct style.
71
+ function groupLabel(isAnd, asBullet, indentStr) {
72
+ const label = isAnd
73
+ ? "**All of the following must be true:**"
74
+ : "**Any of these must be true:**";
75
+ return asBullet ? `${indentStr}- ${label}` : `${indentStr}${label}`;
76
+ }
77
+ // Ensure each line in a block is indented (used for nested groups).
78
+ function indentBlock(block, extraDepth = 1) {
79
+ const pad = " ".repeat(extraDepth);
80
+ return block
21
81
  .split("\n")
22
- .map((line) => subIndent + line)
82
+ .map((l) => (l.length ? pad + l : l))
23
83
  .join("\n");
24
84
  }
85
+ // RETURN: just compile its expression at same depth/topLevel
25
86
  if (ast.type === "returnStatement") {
26
- const returnStatement = ast;
27
- const generated = CompileToMarkdown(returnStatement.expression, `${pointer}`, depth, forNot);
28
- return `${generated}`;
87
+ const ret = ast;
88
+ return compileToMarkdownInternal(ret.expression, topLevel, depth, forNot, isSkip);
29
89
  }
90
+ // AND / OR group
30
91
  if (ast.type === "binaryOperator") {
31
- const binary = ast;
32
- const subMdLhs = CompileToMarkdown(binary.lhs, getNextPointer(pointer, 1), depth + 1, forNot);
33
- const subMdRhs = CompileToMarkdown(binary.rhs, getNextPointer(pointer, 2), depth + 1, forNot);
34
- const indentedSubMdLhs = indentMultilineString(subMdLhs, 0); // LHS already indented
35
- const indentedSubMdRhs = indentMultilineString(subMdRhs, 0); // RHS already indented
36
- if (binary.operator === "&&") {
37
- return `${indent}- **condition ${pointer}**: all of the following sub conditions must${forNot ? "**not**" : ""} be met:\n\n${indentedSubMdLhs}\n${indentedSubMdRhs}`;
92
+ const { operator, lhs, rhs } = ast;
93
+ const isAnd = operator === "&&";
94
+ const labelLine = groupLabel(isAnd, !topLevel, indent);
95
+ // Render children as bullet items (no numbering)
96
+ const leftRendered = compileToMarkdownInternal(lhs, false, depth + 1, forNot, isSkip);
97
+ const rightRendered = compileToMarkdownInternal(rhs, false, depth + 1, forNot, isSkip);
98
+ // If top-level group: label as standalone line, then list items
99
+ // If nested: label as bullet, then nested bullets further indented
100
+ if (topLevel) {
101
+ return [labelLine, leftRendered, rightRendered].join("\n");
38
102
  }
39
- if (binary.operator === "||") {
40
- return `${indent}- **condition ${pointer}**: any one of the following sub conditions must${forNot ? "**not**" : ""} be met:\n\n${indentedSubMdLhs}\n${indentedSubMdRhs}`;
103
+ else {
104
+ return [labelLine, leftRendered, rightRendered].join("\n");
41
105
  }
42
106
  }
107
+ // NOT
43
108
  if (ast.type === "notOperator") {
44
109
  const not = ast;
45
- return CompileToMarkdown(not.expression, pointer, depth, !forNot);
110
+ return compileToMarkdownInternal(not.expression, topLevel, depth, !forNot, isSkip);
46
111
  }
112
+ // LEAVES (unary / binary custom functions)
47
113
  if (ast.type === "customUniaryFunction") {
48
- const customFunction = ast;
49
- const func = customFunction.customFunction;
50
- const messageFunction = uniaryMessages[func];
51
- const lhs = customFunction.expression;
52
- return `${indent}- **condition ${pointer}**: ${messageFunction(lhs.name, forNot)}`;
114
+ const custom = ast;
115
+ const fn = custom.customFunction;
116
+ const lhs = custom.expression;
117
+ const msgFn = isSkip
118
+ ? skipUniaryMessages[fn]
119
+ : uniaryMessages[fn];
120
+ return `${indent}- ${msgFn(lhs.name, forNot)}`;
53
121
  }
54
122
  if (ast.type === "customBinaryFunction") {
55
- const customFunction = ast;
56
- const func = customFunction.customFunction;
57
- const messageFunction = binaryMessages[func];
58
- const lhs = customFunction.lhs;
59
- const rhs = customFunction.rhs;
60
- return `${indent}- **condition ${pointer}**: ${messageFunction(lhs.name, rhs.name, forNot)}`;
123
+ const custom = ast;
124
+ const fn = custom.customFunction;
125
+ const lhs = custom.lhs;
126
+ const rhs = custom.rhs;
127
+ const msgFn = isSkip
128
+ ? skipBinaryMessages[fn]
129
+ : binaryMessages[fn];
130
+ return `${indent}- ${msgFn(lhs.name, rhs.name, forNot)}`;
61
131
  }
62
132
  throw new Error("Invalid AST node:" + JSON.stringify(ast));
63
133
  }
64
- function getNextPointer(currentPointer, nextIndex) {
65
- return `${currentPointer}.${nextIndex}`;
66
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ondc-code-generator",
3
- "version": "0.5.42",
3
+ "version": "0.5.51",
4
4
  "description": "generate code from build.yaml ",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",