ondc-code-generator 0.8.8 → 0.9.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.
- package/README.md +1 -1
- package/alpha/table/page/index.html +11487 -0
- package/alpha/table/page/style.css +449 -0
- package/alpha/table/rag-table-docs/confirm.md +60 -0
- package/alpha/table/rag-table-docs/init.md +78 -0
- package/alpha/table/rag-table-docs/on_confirm.md +161 -0
- package/alpha/table/rag-table-docs/on_init.md +143 -0
- package/alpha/table/rag-table-docs/on_search.md +160 -0
- package/alpha/table/rag-table-docs/on_select.md +96 -0
- package/alpha/table/rag-table-docs/on_status.md +150 -0
- package/alpha/table/rag-table-docs/on_update.md +161 -0
- package/alpha/table/rag-table-docs/raw_table.json +11198 -0
- package/alpha/table/rag-table-docs/search.md +125 -0
- package/alpha/table/rag-table-docs/select.md +67 -0
- package/alpha/table/rag-table-docs/status.md +41 -0
- package/alpha/table/rag-table-docs/update.md +48 -0
- package/alpha/table/readme.md +1312 -0
- package/alpha/table/validPaths.json +34134 -0
- package/alpha/table.zip +0 -0
- package/dist/bin/cli.js +6 -0
- package/dist/generator/config-compiler.js +16 -0
- package/dist/generator/generators/documentation/md-generator.d.ts +11 -5
- package/dist/generator/generators/documentation/md-generator.js +22 -28
- package/dist/generator/generators/documentation/templates/index.mustache +162 -26
- package/dist/generator/generators/documentation/templates/style.css +387 -142
- package/dist/generator/generators/rag/rag-generator.d.ts +48 -0
- package/dist/generator/generators/rag/rag-generator.js +185 -0
- package/dist/generator/generators/rag/rag-table-generator.d.ts +55 -0
- package/dist/generator/generators/rag/rag-table-generator.js +263 -0
- package/dist/types/compiler-types.d.ts +4 -1
- package/dist/types/compiler-types.js +3 -0
- package/docs/jval-dsl.md +913 -0
- package/package.json +1 -1
- package/alpha/golang/newPkg/go.mod +0 -3
- package/alpha/golang/newPkg/jsonvalidations/cancel.go +0 -1289
- package/alpha/golang/newPkg/jsonvalidations/confirm.go +0 -9121
- package/alpha/golang/newPkg/jsonvalidations/init.go +0 -4864
- package/alpha/golang/newPkg/jsonvalidations/issue.go +0 -4868
- package/alpha/golang/newPkg/jsonvalidations/on_cancel.go +0 -7111
- package/alpha/golang/newPkg/jsonvalidations/on_confirm.go +0 -8903
- package/alpha/golang/newPkg/jsonvalidations/on_init.go +0 -4445
- package/alpha/golang/newPkg/jsonvalidations/on_issue.go +0 -2828
- package/alpha/golang/newPkg/jsonvalidations/on_issue_status.go +0 -1938
- package/alpha/golang/newPkg/jsonvalidations/on_search.go +0 -3356
- package/alpha/golang/newPkg/jsonvalidations/on_status.go +0 -8129
- package/alpha/golang/newPkg/jsonvalidations/on_track.go +0 -1415
- package/alpha/golang/newPkg/jsonvalidations/on_update.go +0 -8700
- package/alpha/golang/newPkg/jsonvalidations/search.go +0 -3585
- package/alpha/golang/newPkg/jsonvalidations/status.go +0 -1073
- package/alpha/golang/newPkg/jsonvalidations/track.go +0 -1073
- package/alpha/golang/newPkg/jsonvalidations/update.go +0 -3012
- package/alpha/golang/newPkg/main-validator.go +0 -196
- package/alpha/golang/newPkg/main-validator_test.go +0 -165
- package/alpha/golang/newPkg/storageutils/api_save_utils.go +0 -83
- package/alpha/golang/newPkg/storageutils/cancel.go +0 -30
- package/alpha/golang/newPkg/storageutils/confirm.go +0 -30
- package/alpha/golang/newPkg/storageutils/index.go +0 -132
- package/alpha/golang/newPkg/storageutils/init.go +0 -30
- package/alpha/golang/newPkg/storageutils/issue.go +0 -30
- package/alpha/golang/newPkg/storageutils/on_cancel.go +0 -30
- package/alpha/golang/newPkg/storageutils/on_confirm.go +0 -30
- package/alpha/golang/newPkg/storageutils/on_init.go +0 -30
- package/alpha/golang/newPkg/storageutils/on_issue.go +0 -30
- package/alpha/golang/newPkg/storageutils/on_issue_status.go +0 -30
- package/alpha/golang/newPkg/storageutils/on_search.go +0 -30
- package/alpha/golang/newPkg/storageutils/on_status.go +0 -30
- package/alpha/golang/newPkg/storageutils/on_track.go +0 -30
- package/alpha/golang/newPkg/storageutils/on_update.go +0 -30
- package/alpha/golang/newPkg/storageutils/save_utils.go +0 -75
- package/alpha/golang/newPkg/storageutils/search.go +0 -30
- package/alpha/golang/newPkg/storageutils/status.go +0 -30
- package/alpha/golang/newPkg/storageutils/track.go +0 -30
- package/alpha/golang/newPkg/storageutils/update.go +0 -30
- package/alpha/golang/newPkg/validationutils/json_normalizer.go +0 -152
- package/alpha/golang/newPkg/validationutils/json_path_utils.go +0 -173
- package/alpha/golang/newPkg/validationutils/storage-interface.go +0 -107
- package/alpha/golang/newPkg/validationutils/test-config.go +0 -69
- package/alpha/golang/newPkg/validationutils/validation_utils.go +0 -429
- package/alpha/golang/page/index.html +0 -6137
- package/alpha/golang/page/style.css +0 -204
- package/alpha/golang/readme.md +0 -5939
- package/alpha/golang/validationpkg/go.mod +0 -3
- package/alpha/golang/validationpkg/jsonvalidations/cancel.go +0 -1289
- package/alpha/golang/validationpkg/jsonvalidations/confirm.go +0 -9121
- package/alpha/golang/validationpkg/jsonvalidations/init.go +0 -4864
- package/alpha/golang/validationpkg/jsonvalidations/issue.go +0 -4868
- package/alpha/golang/validationpkg/jsonvalidations/on_cancel.go +0 -7111
- package/alpha/golang/validationpkg/jsonvalidations/on_confirm.go +0 -8903
- package/alpha/golang/validationpkg/jsonvalidations/on_init.go +0 -4445
- package/alpha/golang/validationpkg/jsonvalidations/on_issue.go +0 -2828
- package/alpha/golang/validationpkg/jsonvalidations/on_issue_status.go +0 -1938
- package/alpha/golang/validationpkg/jsonvalidations/on_search.go +0 -3356
- package/alpha/golang/validationpkg/jsonvalidations/on_status.go +0 -8129
- package/alpha/golang/validationpkg/jsonvalidations/on_track.go +0 -1415
- package/alpha/golang/validationpkg/jsonvalidations/on_update.go +0 -8700
- package/alpha/golang/validationpkg/jsonvalidations/search.go +0 -3585
- package/alpha/golang/validationpkg/jsonvalidations/status.go +0 -1073
- package/alpha/golang/validationpkg/jsonvalidations/track.go +0 -1073
- package/alpha/golang/validationpkg/jsonvalidations/update.go +0 -3012
- package/alpha/golang/validationpkg/main-validator.go +0 -196
- package/alpha/golang/validationpkg/main-validator_test.go +0 -165
- package/alpha/golang/validationpkg/storageutils/api_save_utils.go +0 -83
- package/alpha/golang/validationpkg/storageutils/cancel.go +0 -30
- package/alpha/golang/validationpkg/storageutils/confirm.go +0 -30
- package/alpha/golang/validationpkg/storageutils/index.go +0 -132
- package/alpha/golang/validationpkg/storageutils/init.go +0 -30
- package/alpha/golang/validationpkg/storageutils/issue.go +0 -30
- package/alpha/golang/validationpkg/storageutils/on_cancel.go +0 -30
- package/alpha/golang/validationpkg/storageutils/on_confirm.go +0 -30
- package/alpha/golang/validationpkg/storageutils/on_init.go +0 -30
- package/alpha/golang/validationpkg/storageutils/on_issue.go +0 -30
- package/alpha/golang/validationpkg/storageutils/on_issue_status.go +0 -30
- package/alpha/golang/validationpkg/storageutils/on_search.go +0 -30
- package/alpha/golang/validationpkg/storageutils/on_status.go +0 -30
- package/alpha/golang/validationpkg/storageutils/on_track.go +0 -30
- package/alpha/golang/validationpkg/storageutils/on_update.go +0 -30
- package/alpha/golang/validationpkg/storageutils/save_utils.go +0 -75
- package/alpha/golang/validationpkg/storageutils/search.go +0 -30
- package/alpha/golang/validationpkg/storageutils/status.go +0 -30
- package/alpha/golang/validationpkg/storageutils/track.go +0 -30
- package/alpha/golang/validationpkg/storageutils/update.go +0 -30
- package/alpha/golang/validationpkg/validationutils/json_normalizer.go +0 -152
- package/alpha/golang/validationpkg/validationutils/json_path_utils.go +0 -173
- package/alpha/golang/validationpkg/validationutils/storage-interface.go +0 -107
- package/alpha/golang/validationpkg/validationutils/test-config.go +0 -69
- package/alpha/golang/validationpkg/validationutils/validation_utils.go +0 -429
- /package/alpha/{golang/validPaths.json → validPaths.json} +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { ConfigSyntax, TestObjectSyntax } from "../../../constants/syntax.js";
|
|
2
|
+
import { CodeGenerator, } from "../classes/abstract-generator.js";
|
|
3
|
+
import { writeFileWithFsExtra } from "../../../utils/fs-utils.js";
|
|
4
|
+
import { markdownMessageGenerator } from "../documentation/markdown-message-generator.js";
|
|
5
|
+
import { buildAstFromInput } from "../../../services/return-complier/combined.js";
|
|
6
|
+
import { CompileToMarkdownForSkip } from "../../../services/return-complier/ast-functions/compile-to-markdown.js";
|
|
7
|
+
import { addBlockquoteToMarkdown, ConvertArrayToStringsInTestObject, } from "../../../utils/general-utils/string-utils.js";
|
|
8
|
+
import Mustache from "mustache";
|
|
9
|
+
/**
|
|
10
|
+
* RagGenerator — produces one Markdown file per API action under ./rag-docs/.
|
|
11
|
+
*
|
|
12
|
+
* Each file is a self-contained, richly structured document intended to be
|
|
13
|
+
* fed directly into a Retrieval-Augmented Generation (RAG) pipeline.
|
|
14
|
+
*
|
|
15
|
+
* Layout per file:
|
|
16
|
+
* ---
|
|
17
|
+
* YAML frontmatter (action, codeName, numTests, generated date)
|
|
18
|
+
* ---
|
|
19
|
+
* # <codeName> — <action> Validations
|
|
20
|
+
* Short context paragraph
|
|
21
|
+
* Numbered list of every test with its human-readable description,
|
|
22
|
+
* error code, scope, and (indented) skip condition when present.
|
|
23
|
+
*/
|
|
24
|
+
export class RagGenerator extends CodeGenerator {
|
|
25
|
+
constructor() {
|
|
26
|
+
super(...arguments);
|
|
27
|
+
this.generateValidationCode = async () => {
|
|
28
|
+
// Driven by generateCode
|
|
29
|
+
};
|
|
30
|
+
this.generateCode = async (codeConfig) => {
|
|
31
|
+
const testConfig = this.validationConfig[ConfigSyntax.Tests];
|
|
32
|
+
const { codeName } = codeConfig;
|
|
33
|
+
for (const action of Object.keys(testConfig)) {
|
|
34
|
+
const testArray = testConfig[action];
|
|
35
|
+
const md = this.buildActionMarkdown(action, codeName, testArray);
|
|
36
|
+
writeFileWithFsExtra(this.rootPath, `./rag-docs/${action}.md`, md);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
generateSessionDataCode() {
|
|
41
|
+
// Session-data code not needed for RAG output
|
|
42
|
+
return Promise.resolve();
|
|
43
|
+
}
|
|
44
|
+
generateUnitTestingCode() {
|
|
45
|
+
// Unit-test code not needed for RAG output
|
|
46
|
+
return Promise.resolve();
|
|
47
|
+
}
|
|
48
|
+
// -------------------------------------------------------------------------
|
|
49
|
+
// Private helpers
|
|
50
|
+
// -------------------------------------------------------------------------
|
|
51
|
+
buildActionMarkdown(action, codeName, testArray) {
|
|
52
|
+
const leafCount = this.countLeafTests(testArray);
|
|
53
|
+
const dateStr = new Date().toISOString().split("T")[0];
|
|
54
|
+
// YAML front-matter — picked up as metadata by most RAG loaders
|
|
55
|
+
const frontmatter = [
|
|
56
|
+
"---",
|
|
57
|
+
`action: ${action}`,
|
|
58
|
+
`codeName: ${codeName}`,
|
|
59
|
+
`numTests: ${leafCount}`,
|
|
60
|
+
`generated: ${dateStr}`,
|
|
61
|
+
"---",
|
|
62
|
+
].join("\n");
|
|
63
|
+
// Human-readable header
|
|
64
|
+
const header = [
|
|
65
|
+
`# ${codeName} — \`${action}\` Validations`,
|
|
66
|
+
"",
|
|
67
|
+
`This document describes the **${leafCount}** validation rule(s) that are`,
|
|
68
|
+
`applied when the \`${action}\` API call is processed in the **${codeName}** flow.`,
|
|
69
|
+
`Each rule maps to a single test object and is evaluated sequentially against the`,
|
|
70
|
+
`request/response payload.`,
|
|
71
|
+
"",
|
|
72
|
+
"---",
|
|
73
|
+
"",
|
|
74
|
+
].join("\n");
|
|
75
|
+
// One numbered ## section per top-level test object only.
|
|
76
|
+
// Group nodes embed their children as ### sub-sections inside themselves.
|
|
77
|
+
const sections = testArray
|
|
78
|
+
.map((test, idx) => this.buildTestSection(test, idx + 1))
|
|
79
|
+
.join("\n\n");
|
|
80
|
+
return `${frontmatter}\n\n${header}${sections}\n`;
|
|
81
|
+
}
|
|
82
|
+
/** Count only leaf (non-group) tests recursively. */
|
|
83
|
+
countLeafTests(tests) {
|
|
84
|
+
let count = 0;
|
|
85
|
+
for (const test of tests) {
|
|
86
|
+
const ret = test[TestObjectSyntax.Return];
|
|
87
|
+
if (typeof ret === "string") {
|
|
88
|
+
count++;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
count += this.countLeafTests(ret);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return count;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Renders a numbered top-level section (##) for a test object.
|
|
98
|
+
*
|
|
99
|
+
* - Leaf test → full human-readable description + metadata badges
|
|
100
|
+
* - Group node → brief intro line + all children rendered as ### sub-sections
|
|
101
|
+
* (recursing further for deeply nested groups)
|
|
102
|
+
*
|
|
103
|
+
* This preserves the parent→child relationship in the output so RAG
|
|
104
|
+
* consumers can see exactly which sub-validations belong to which group.
|
|
105
|
+
*/
|
|
106
|
+
buildTestSection(test, index) {
|
|
107
|
+
const name = test[TestObjectSyntax.Name] ?? `test_${index}`;
|
|
108
|
+
const ret = test[TestObjectSyntax.Return];
|
|
109
|
+
if (typeof ret === "string") {
|
|
110
|
+
return this.renderLeaf(test, name, `## ${index}. ${name}`);
|
|
111
|
+
}
|
|
112
|
+
// Group node — render intro + skip (before children) then nest children
|
|
113
|
+
const childSections = ret
|
|
114
|
+
.map((child, i) => this.renderChildSection(child, i + 1, "###"))
|
|
115
|
+
.join("\n\n");
|
|
116
|
+
const groupSkip = this.renderSkipBlock(test);
|
|
117
|
+
return [
|
|
118
|
+
`## ${index}. ${name}`,
|
|
119
|
+
"",
|
|
120
|
+
`Group of **${ret.length}** sub-validation(s). **All** of the following must pass:`,
|
|
121
|
+
...(groupSkip ? ["", groupSkip] : []),
|
|
122
|
+
"",
|
|
123
|
+
childSections,
|
|
124
|
+
].join("\n");
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Renders a child/nested section at the given heading level.
|
|
128
|
+
* Recurses deeper (####, #####, …) for nested groups.
|
|
129
|
+
*/
|
|
130
|
+
renderChildSection(test, index, headingLevel) {
|
|
131
|
+
const name = test[TestObjectSyntax.Name] ?? `sub_test_${index}`;
|
|
132
|
+
const ret = test[TestObjectSyntax.Return];
|
|
133
|
+
const heading = `${headingLevel} ${index}. ${name}`;
|
|
134
|
+
if (typeof ret === "string") {
|
|
135
|
+
return this.renderLeaf(test, name, heading);
|
|
136
|
+
}
|
|
137
|
+
// Nested group — go one heading level deeper
|
|
138
|
+
const nextLevel = headingLevel + "#";
|
|
139
|
+
const childSections = ret
|
|
140
|
+
.map((child, i) => this.renderChildSection(child, i + 1, nextLevel))
|
|
141
|
+
.join("\n\n");
|
|
142
|
+
const groupSkip = this.renderSkipBlock(test);
|
|
143
|
+
return [
|
|
144
|
+
heading,
|
|
145
|
+
"",
|
|
146
|
+
`Group of **${ret.length}** sub-validation(s). **All** of the following must pass:`,
|
|
147
|
+
...(groupSkip ? ["", groupSkip] : []),
|
|
148
|
+
"",
|
|
149
|
+
childSections,
|
|
150
|
+
].join("\n");
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Renders the skip block for a group node as a blockquote.
|
|
154
|
+
* Returns an empty string when there is no _CONTINUE_ on this node.
|
|
155
|
+
*/
|
|
156
|
+
renderSkipBlock(test) {
|
|
157
|
+
const skip = test[TestObjectSyntax.Continue];
|
|
158
|
+
if (!skip)
|
|
159
|
+
return "";
|
|
160
|
+
let skipMarkdown = `**Skip if:**\n`;
|
|
161
|
+
const skAst = buildAstFromInput(skip);
|
|
162
|
+
const skBlock = CompileToMarkdownForSkip(skAst, false, 2, false);
|
|
163
|
+
skipMarkdown += `\n${skBlock}`;
|
|
164
|
+
const rendered = Mustache.render(skipMarkdown, ConvertArrayToStringsInTestObject(test));
|
|
165
|
+
return addBlockquoteToMarkdown(rendered);
|
|
166
|
+
}
|
|
167
|
+
/** Renders a leaf test's heading, metadata badges, and compiled description. */
|
|
168
|
+
renderLeaf(test, name, heading) {
|
|
169
|
+
const scope = test[TestObjectSyntax.Scope];
|
|
170
|
+
const errorCode = test[TestObjectSyntax.ErrorCode];
|
|
171
|
+
const successCode = test[TestObjectSyntax.SuccessCode];
|
|
172
|
+
const skip = test[TestObjectSyntax.Continue];
|
|
173
|
+
const ret = test[TestObjectSyntax.Return];
|
|
174
|
+
const badges = [];
|
|
175
|
+
if (scope)
|
|
176
|
+
badges.push(`**Scope:** \`${scope}\``);
|
|
177
|
+
if (errorCode !== undefined)
|
|
178
|
+
badges.push(`**Error Code:** \`${errorCode}\``);
|
|
179
|
+
if (successCode !== undefined)
|
|
180
|
+
badges.push(`**Success Code:** \`${successCode}\``);
|
|
181
|
+
const badgeLine = badges.length > 0 ? badges.join(" · ") + "\n\n" : "";
|
|
182
|
+
const body = markdownMessageGenerator(ret, test, name, skip ? [skip] : undefined);
|
|
183
|
+
return `${heading}\n\n${badgeLine}${body}`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { TestObject } from "../../../types/config-types.js";
|
|
2
|
+
import { CodeGenerator, CodeGeneratorProps } from "../classes/abstract-generator.js";
|
|
3
|
+
/**
|
|
4
|
+
* RagTableGenerator — produces one Markdown **table** file per API action
|
|
5
|
+
* under `./rag-table-docs/`.
|
|
6
|
+
*
|
|
7
|
+
* Each file contains:
|
|
8
|
+
* - YAML front-matter (action, codeName, numTests, generated date)
|
|
9
|
+
* - A short summary paragraph
|
|
10
|
+
* - A single GFM table
|
|
11
|
+
*
|
|
12
|
+
* Columns: # | Type | Test Name | Group | Scope | Description | Skip If | Error Code
|
|
13
|
+
*
|
|
14
|
+
* Group nodes ARE rendered as their own rows. Their Description cell lists
|
|
15
|
+
* the immediate child test names and their Skip If cell shows the group's own
|
|
16
|
+
* _CONTINUE_ condition. Child leaf rows follow immediately after, with the
|
|
17
|
+
* Group column showing their parent's name — making hierarchy fully visible.
|
|
18
|
+
*
|
|
19
|
+
* This format is complementary to `RagGenerator` (heading-based): use it
|
|
20
|
+
* when you need a dense, scannable overview of all rules at once.
|
|
21
|
+
*/
|
|
22
|
+
export declare class RagTableGenerator extends CodeGenerator {
|
|
23
|
+
generateSessionDataCode(): Promise<void>;
|
|
24
|
+
generateUnitTestingCode(): Promise<void>;
|
|
25
|
+
generateValidationCode: () => Promise<void>;
|
|
26
|
+
generateCode: (codeConfig: CodeGeneratorProps) => Promise<void>;
|
|
27
|
+
/** Collects rows and returns structured JSON for one action. */
|
|
28
|
+
private buildActionJson;
|
|
29
|
+
buildActionMarkdown(action: string, codeName: string, testArray: TestObject[]): string;
|
|
30
|
+
/**
|
|
31
|
+
* Walks the test tree depth-first.
|
|
32
|
+
*
|
|
33
|
+
* - **Group node** → emits one summary row whose Description lists the
|
|
34
|
+
* immediate child names, and whose Skip If shows the group's own
|
|
35
|
+
* _CONTINUE_. Then recurses so children follow immediately after.
|
|
36
|
+
* - **Leaf node** → emits one row with the compiled description and its
|
|
37
|
+
* own _CONTINUE_ only (no skip inheritance from parents).
|
|
38
|
+
*/
|
|
39
|
+
private collectRows;
|
|
40
|
+
/**
|
|
41
|
+
* Renders the GFM table with all rows.
|
|
42
|
+
*
|
|
43
|
+
* Columns shown depend on whether *any* row has a value:
|
|
44
|
+
* - `Group` column hidden when no tests have a group (flat config)
|
|
45
|
+
* - `Scope`, `Skip If`, `Error Code`, `Success Code` similarly pruned
|
|
46
|
+
*/
|
|
47
|
+
private renderTable;
|
|
48
|
+
/**
|
|
49
|
+
* Sanitises a string for safe use inside a GFM table cell:
|
|
50
|
+
* - Collapses newlines and excess whitespace to a single space
|
|
51
|
+
* - Escapes pipe characters
|
|
52
|
+
* - Strips any leading `####` heading markers left by the compiler
|
|
53
|
+
*/
|
|
54
|
+
private sanitizeCell;
|
|
55
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { ConfigSyntax, TestObjectSyntax } from "../../../constants/syntax.js";
|
|
2
|
+
import { CodeGenerator, } from "../classes/abstract-generator.js";
|
|
3
|
+
import { writeFileWithFsExtra } from "../../../utils/fs-utils.js";
|
|
4
|
+
import { markdownMessageGenerator } from "../documentation/markdown-message-generator.js";
|
|
5
|
+
/**
|
|
6
|
+
* RagTableGenerator — produces one Markdown **table** file per API action
|
|
7
|
+
* under `./rag-table-docs/`.
|
|
8
|
+
*
|
|
9
|
+
* Each file contains:
|
|
10
|
+
* - YAML front-matter (action, codeName, numTests, generated date)
|
|
11
|
+
* - A short summary paragraph
|
|
12
|
+
* - A single GFM table
|
|
13
|
+
*
|
|
14
|
+
* Columns: # | Type | Test Name | Group | Scope | Description | Skip If | Error Code
|
|
15
|
+
*
|
|
16
|
+
* Group nodes ARE rendered as their own rows. Their Description cell lists
|
|
17
|
+
* the immediate child test names and their Skip If cell shows the group's own
|
|
18
|
+
* _CONTINUE_ condition. Child leaf rows follow immediately after, with the
|
|
19
|
+
* Group column showing their parent's name — making hierarchy fully visible.
|
|
20
|
+
*
|
|
21
|
+
* This format is complementary to `RagGenerator` (heading-based): use it
|
|
22
|
+
* when you need a dense, scannable overview of all rules at once.
|
|
23
|
+
*/
|
|
24
|
+
export class RagTableGenerator extends CodeGenerator {
|
|
25
|
+
constructor() {
|
|
26
|
+
super(...arguments);
|
|
27
|
+
this.generateValidationCode = async () => {
|
|
28
|
+
// Driven by generateCode
|
|
29
|
+
};
|
|
30
|
+
this.generateCode = async (codeConfig) => {
|
|
31
|
+
const testConfig = this.validationConfig[ConfigSyntax.Tests];
|
|
32
|
+
const { codeName } = codeConfig;
|
|
33
|
+
const rawJson = {};
|
|
34
|
+
for (const action of Object.keys(testConfig)) {
|
|
35
|
+
const testArray = testConfig[action];
|
|
36
|
+
const md = this.buildActionMarkdown(action, codeName, testArray);
|
|
37
|
+
writeFileWithFsExtra(this.rootPath, `./rag-table-docs/${action}.md`, md);
|
|
38
|
+
rawJson[action] = this.buildActionJson(action, codeName, testArray);
|
|
39
|
+
}
|
|
40
|
+
writeFileWithFsExtra(this.rootPath, `./rag-table-docs/raw_table.json`, JSON.stringify(rawJson, null, 2));
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
generateSessionDataCode() {
|
|
44
|
+
return Promise.resolve();
|
|
45
|
+
}
|
|
46
|
+
generateUnitTestingCode() {
|
|
47
|
+
return Promise.resolve();
|
|
48
|
+
}
|
|
49
|
+
// -------------------------------------------------------------------------
|
|
50
|
+
// Private helpers
|
|
51
|
+
// -------------------------------------------------------------------------
|
|
52
|
+
/** Collects rows and returns structured JSON for one action. */
|
|
53
|
+
buildActionJson(action, codeName, testArray) {
|
|
54
|
+
const rows = [];
|
|
55
|
+
this.collectRows(testArray, rows, "");
|
|
56
|
+
rows.forEach((r, i) => (r.index = i + 1));
|
|
57
|
+
return {
|
|
58
|
+
action,
|
|
59
|
+
codeName,
|
|
60
|
+
numLeafTests: rows.filter((r) => r.rowType === "leaf").length,
|
|
61
|
+
generated: new Date().toISOString().split("T")[0],
|
|
62
|
+
rows: rows.map(({ index: _idx, ...rest }) => rest),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
buildActionMarkdown(action, codeName, testArray) {
|
|
66
|
+
const rows = [];
|
|
67
|
+
this.collectRows(testArray, rows, "");
|
|
68
|
+
// Re-index after collection so numbering is clean
|
|
69
|
+
rows.forEach((r, i) => (r.index = i + 1));
|
|
70
|
+
const dateStr = new Date().toISOString().split("T")[0];
|
|
71
|
+
const frontmatter = [
|
|
72
|
+
"---",
|
|
73
|
+
`action: ${action}`,
|
|
74
|
+
`codeName: ${codeName}`,
|
|
75
|
+
`numTests: ${rows.length}`,
|
|
76
|
+
`generated: ${dateStr}`,
|
|
77
|
+
"---",
|
|
78
|
+
].join("\n");
|
|
79
|
+
const leafCount = rows.filter((r) => r.rowType === "leaf").length;
|
|
80
|
+
const header = [
|
|
81
|
+
`# ${codeName} — \`${action}\` Validations (Table View)`,
|
|
82
|
+
"",
|
|
83
|
+
`**${leafCount}** leaf validation rule(s) applied to \`${action}\` in the **${codeName}** flow.`,
|
|
84
|
+
`Group rows (GRP) list their immediate sub-tests. Leaf rows (LF) show the actual validation logic.`,
|
|
85
|
+
"",
|
|
86
|
+
"---",
|
|
87
|
+
"",
|
|
88
|
+
].join("\n");
|
|
89
|
+
const table = this.renderTable(rows);
|
|
90
|
+
return `${frontmatter}\n\n${header}${table}\n`;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Walks the test tree depth-first.
|
|
94
|
+
*
|
|
95
|
+
* - **Group node** → emits one summary row whose Description lists the
|
|
96
|
+
* immediate child names, and whose Skip If shows the group's own
|
|
97
|
+
* _CONTINUE_. Then recurses so children follow immediately after.
|
|
98
|
+
* - **Leaf node** → emits one row with the compiled description and its
|
|
99
|
+
* own _CONTINUE_ only (no skip inheritance from parents).
|
|
100
|
+
*/
|
|
101
|
+
collectRows(tests, acc, parentPath) {
|
|
102
|
+
for (const test of tests) {
|
|
103
|
+
const name = test[TestObjectSyntax.Name] ?? "unknown";
|
|
104
|
+
const ret = test[TestObjectSyntax.Return];
|
|
105
|
+
const ownSkip = test[TestObjectSyntax.Continue];
|
|
106
|
+
if (typeof ret === "string") {
|
|
107
|
+
// ── Leaf row ──────────────────────────────────────────────
|
|
108
|
+
const scope = test[TestObjectSyntax.Scope] ?? "";
|
|
109
|
+
const errorCode = test[TestObjectSyntax.ErrorCode] ?? "30000";
|
|
110
|
+
const successCode = test[TestObjectSyntax.SuccessCode];
|
|
111
|
+
let description;
|
|
112
|
+
try {
|
|
113
|
+
description = markdownMessageGenerator(ret, test, name, undefined)
|
|
114
|
+
.replace(/^#{1,6}\s+\*\*[^*]+\*\*\s*\n\n?/, "")
|
|
115
|
+
.trim();
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
description = ret;
|
|
119
|
+
}
|
|
120
|
+
let skipText = "";
|
|
121
|
+
if (ownSkip) {
|
|
122
|
+
try {
|
|
123
|
+
skipText = markdownMessageGenerator(ownSkip, test, name, undefined)
|
|
124
|
+
.replace(/^#{1,6}\s+\*\*[^*]+\*\*\s*\n\n?/, "")
|
|
125
|
+
.trim();
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
skipText = ownSkip;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
acc.push({
|
|
132
|
+
index: acc.length + 1,
|
|
133
|
+
rowType: "leaf",
|
|
134
|
+
name,
|
|
135
|
+
group: parentPath,
|
|
136
|
+
scope: scope ? `\`${scope}\`` : "",
|
|
137
|
+
description: this.sanitizeCell(description),
|
|
138
|
+
skipIf: this.sanitizeCell(skipText),
|
|
139
|
+
errorCode: errorCode !== undefined ? String(errorCode) : "",
|
|
140
|
+
successCode: successCode !== undefined ? String(successCode) : "",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
// ── Group row ─────────────────────────────────────────────
|
|
145
|
+
const childNames = ret
|
|
146
|
+
.map((c) => c[TestObjectSyntax.Name] ?? "?")
|
|
147
|
+
.join(", ");
|
|
148
|
+
let skipText = "";
|
|
149
|
+
if (ownSkip) {
|
|
150
|
+
try {
|
|
151
|
+
skipText = markdownMessageGenerator(ownSkip, test, name, undefined)
|
|
152
|
+
.replace(/^#{1,6}\s+\*\*[^*]+\*\*\s*\n\n?/, "")
|
|
153
|
+
.trim();
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
skipText = ownSkip;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
acc.push({
|
|
160
|
+
index: acc.length + 1,
|
|
161
|
+
rowType: "group",
|
|
162
|
+
name: `**${name}**`,
|
|
163
|
+
group: parentPath,
|
|
164
|
+
scope: "",
|
|
165
|
+
description: this.sanitizeCell(`Sub-tests: ${childNames}`),
|
|
166
|
+
skipIf: this.sanitizeCell(skipText),
|
|
167
|
+
errorCode: "",
|
|
168
|
+
successCode: "",
|
|
169
|
+
});
|
|
170
|
+
// Recurse — children follow immediately after the group row
|
|
171
|
+
const newPath = parentPath ? `${parentPath} > ${name}` : name;
|
|
172
|
+
this.collectRows(ret, acc, newPath);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Renders the GFM table with all rows.
|
|
178
|
+
*
|
|
179
|
+
* Columns shown depend on whether *any* row has a value:
|
|
180
|
+
* - `Group` column hidden when no tests have a group (flat config)
|
|
181
|
+
* - `Scope`, `Skip If`, `Error Code`, `Success Code` similarly pruned
|
|
182
|
+
*/
|
|
183
|
+
renderTable(rows) {
|
|
184
|
+
const hasGroup = rows.some((r) => r.group !== "");
|
|
185
|
+
const hasScope = rows.some((r) => r.scope !== "");
|
|
186
|
+
const hasSkip = rows.some((r) => r.skipIf !== "");
|
|
187
|
+
const hasSuccess = rows.some((r) => r.successCode !== "");
|
|
188
|
+
const cols = [
|
|
189
|
+
{ header: "#", align: "r", value: (r) => String(r.index) },
|
|
190
|
+
{
|
|
191
|
+
header: "Type",
|
|
192
|
+
align: "c",
|
|
193
|
+
value: (r) => (r.rowType === "group" ? "GRP" : "LF"),
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
header: "Test Name",
|
|
197
|
+
align: "l",
|
|
198
|
+
// Group rows already have **bold** markers; leaf rows get backticks
|
|
199
|
+
value: (r) => r.rowType === "group" ? r.name : `\`${r.name}\``,
|
|
200
|
+
},
|
|
201
|
+
...(hasGroup
|
|
202
|
+
? [
|
|
203
|
+
{
|
|
204
|
+
header: "Group",
|
|
205
|
+
align: "l",
|
|
206
|
+
value: (r) => r.group,
|
|
207
|
+
},
|
|
208
|
+
]
|
|
209
|
+
: []),
|
|
210
|
+
...(hasScope
|
|
211
|
+
? [
|
|
212
|
+
{
|
|
213
|
+
header: "Scope",
|
|
214
|
+
align: "l",
|
|
215
|
+
value: (r) => r.scope,
|
|
216
|
+
},
|
|
217
|
+
]
|
|
218
|
+
: []),
|
|
219
|
+
{ header: "Description", align: "l", value: (r) => r.description },
|
|
220
|
+
...(hasSkip
|
|
221
|
+
? [
|
|
222
|
+
{
|
|
223
|
+
header: "Skip If",
|
|
224
|
+
align: "l",
|
|
225
|
+
value: (r) => r.skipIf,
|
|
226
|
+
},
|
|
227
|
+
]
|
|
228
|
+
: []),
|
|
229
|
+
{
|
|
230
|
+
header: "Error Code",
|
|
231
|
+
align: "c",
|
|
232
|
+
value: (r) => r.errorCode,
|
|
233
|
+
},
|
|
234
|
+
...(hasSuccess
|
|
235
|
+
? [
|
|
236
|
+
{
|
|
237
|
+
header: "Success Code",
|
|
238
|
+
align: "c",
|
|
239
|
+
value: (r) => r.successCode,
|
|
240
|
+
},
|
|
241
|
+
]
|
|
242
|
+
: []),
|
|
243
|
+
];
|
|
244
|
+
const alignChar = (a) => a === "r" ? "---:" : a === "c" ? ":---:" : ":---";
|
|
245
|
+
const headerRow = `| ${cols.map((c) => c.header).join(" | ")} |`;
|
|
246
|
+
const sepRow = `| ${cols.map((c) => alignChar(c.align)).join(" | ")} |`;
|
|
247
|
+
const dataRows = rows.map((r) => `| ${cols.map((c) => c.value(r) || "—").join(" | ")} |`);
|
|
248
|
+
return [headerRow, sepRow, ...dataRows].join("\n");
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Sanitises a string for safe use inside a GFM table cell:
|
|
252
|
+
* - Collapses newlines and excess whitespace to a single space
|
|
253
|
+
* - Escapes pipe characters
|
|
254
|
+
* - Strips any leading `####` heading markers left by the compiler
|
|
255
|
+
*/
|
|
256
|
+
sanitizeCell(text) {
|
|
257
|
+
return text
|
|
258
|
+
.replace(/\r?\n/g, " ")
|
|
259
|
+
.replace(/\s{2,}/g, " ")
|
|
260
|
+
.replace(/\|/g, "\\|")
|
|
261
|
+
.trim();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
@@ -4,4 +4,7 @@ export var SupportedLanguages;
|
|
|
4
4
|
SupportedLanguages["Python"] = "python";
|
|
5
5
|
SupportedLanguages["Javascript"] = "javascript";
|
|
6
6
|
SupportedLanguages["Golang"] = "go";
|
|
7
|
+
SupportedLanguages["Markdown"] = "md";
|
|
8
|
+
SupportedLanguages["RAG"] = "rag";
|
|
9
|
+
SupportedLanguages["RAG_TABLE"] = "rag_table";
|
|
7
10
|
})(SupportedLanguages || (SupportedLanguages = {}));
|