@stackql/provider-utils 0.1.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.
@@ -0,0 +1,121 @@
1
+ // src/docgen/resource/examples/exec-example.js
2
+ import {
3
+ getSqlMethodsWithOrderedFields,
4
+ } from '../../helpers.js';
5
+
6
+ export function createExecExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI) {
7
+ const execMethods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, 'exec');
8
+
9
+ // if there are no exec methods, return empty content
10
+ if (Object.keys(execMethods).length === 0) {
11
+ return '';
12
+ }
13
+
14
+ let content = '\n\n## Lifecycle Methods\n\n';
15
+
16
+ // Create tab structure with values array
17
+ content += '<Tabs\n defaultValue="' + Object.keys(execMethods)[0] + '"\n values={[\n';
18
+
19
+ // Add each method as a tab option
20
+ Object.keys(execMethods).forEach((methodName, index, arr) => {
21
+ content += ' { label: \'' + methodName + '\', value: \'' + methodName + '\' }';
22
+ content += index < arr.length - 1 ? ',\n' : '\n';
23
+ });
24
+
25
+ content += ' ]}\n>\n';
26
+
27
+ // Create each method tab content
28
+ Object.entries(execMethods).forEach(([methodName, methodDetails]) => {
29
+ content += '<TabItem value="' + methodName + '">\n\n';
30
+
31
+ // Add method description
32
+ content += methodDetails.opDescription || methodDetails.respDescription || 'No description available.';
33
+
34
+ // Create SQL example
35
+ content += '\n\n```sql\nEXEC ' + providerName + '.' + serviceName + '.' + resourceName + '.' + methodName + ' \n';
36
+
37
+ // Add required and optional parameters with @ prefix
38
+ const requiredParams = Object.keys(methodDetails.requiredParams || {});
39
+ const optionalParams = Object.keys(methodDetails.optionalParams || {});
40
+
41
+ // Add parameters
42
+ let hasParams = false;
43
+
44
+ // Add required parameters
45
+ requiredParams.forEach((param, index) => {
46
+ content += '@' + param + '=\'{{ ' + param + ' }}\' --required';
47
+ hasParams = true;
48
+
49
+ if (index < requiredParams.length - 1 || optionalParams.length > 0) {
50
+ content += ', \n';
51
+ }
52
+ });
53
+
54
+ // Add optional parameters
55
+ optionalParams.forEach((param, index) => {
56
+ const paramDetails = methodDetails.optionalParams[param];
57
+ const isBoolean = paramDetails.type === 'boolean';
58
+
59
+ content += '@' + param + '=';
60
+
61
+ if (isBoolean) {
62
+ content += '{{ ' + param + ' }}';
63
+ } else {
64
+ content += '\'{{ ' + param + ' }}\'';
65
+ }
66
+
67
+ hasParams = true;
68
+
69
+ if (index < optionalParams.length - 1) {
70
+ content += ', \n';
71
+ }
72
+ });
73
+
74
+ // Add request body if present
75
+ if (methodDetails.requestBody && methodDetails.requestBody.properties &&
76
+ Object.keys(methodDetails.requestBody.properties).length > 0) {
77
+
78
+ if (hasParams) {
79
+ content += ' \n';
80
+ }
81
+
82
+ content += '@@json=\n\'{\n';
83
+
84
+ // Format request body properties as JSON
85
+ // Filter out read-only properties based on OpenAPI readOnly flag
86
+ const bodyProps = Object.entries(methodDetails.requestBody.properties)
87
+ .filter(([_, propDetails]) => propDetails.readOnly !== true)
88
+ .map(([propName]) => propName);
89
+
90
+ bodyProps.forEach((prop, index) => {
91
+ const propDetails = methodDetails.requestBody.properties[prop];
92
+ const isString = propDetails.type !== 'number' &&
93
+ propDetails.type !== 'integer' &&
94
+ propDetails.type !== 'boolean';
95
+
96
+ content += '"' + prop + '": ';
97
+
98
+ if (isString) {
99
+ content += '"{{ ' + prop + ' }}"';
100
+ } else {
101
+ content += '{{ ' + prop + ' }}';
102
+ }
103
+
104
+ if (index < bodyProps.length - 1) {
105
+ content += ', \n';
106
+ } else {
107
+ content += '\n';
108
+ }
109
+ });
110
+
111
+ content += '}\'';
112
+ }
113
+
114
+ content += ';\n```\n</TabItem>\n';
115
+ });
116
+
117
+ // Close tabs
118
+ content += '</Tabs>\n';
119
+
120
+ return content;
121
+ }
@@ -0,0 +1,211 @@
1
+ // src/docgen/resource/examples/insert-example.js
2
+ import {
3
+ getSqlMethodsWithOrderedFields,
4
+ } from '../../helpers.js';
5
+
6
+ export function createInsertExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI) {
7
+ const insertMethods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, 'insert');
8
+
9
+ // if there are no insert methods, return empty content
10
+ if (Object.keys(insertMethods).length === 0) {
11
+ return '';
12
+ }
13
+
14
+ let content = '\n\n## `INSERT` examples\n\n';
15
+
16
+ // Create tab structure with values array
17
+ content += '<Tabs\n defaultValue="' + Object.keys(insertMethods)[0] + '"\n values={[\n';
18
+
19
+ // Add each method as a tab option
20
+ Object.keys(insertMethods).forEach((methodName, index) => {
21
+ content += ' { label: \'' + methodName + '\', value: \'' + methodName + '\' }';
22
+ if (index < Object.keys(insertMethods).length - 1 || true) { // Always add comma for manifest tab
23
+ content += ',\n';
24
+ }
25
+ });
26
+
27
+ // Add manifest tab
28
+ content += ' { label: \'Manifest\', value: \'manifest\' }\n';
29
+ content += ' ]}\n>\n';
30
+
31
+ // Create each method tab content
32
+ Object.entries(insertMethods).forEach(([methodName, methodDetails]) => {
33
+ content += '<TabItem value="' + methodName + '">\n\n';
34
+ content += methodDetails.opDescription || 'No description available.';
35
+
36
+ // Create SQL example
37
+ content += '\n\n```sql\nINSERT INTO ' + providerName + '.' + serviceName + '.' + resourceName + ' (\n';
38
+
39
+ // Add requestBody fields prefixed with data__ (excluding read-only props)
40
+ const reqBodyProps = methodDetails.requestBody?.properties
41
+ ? Object.entries(methodDetails.requestBody.properties)
42
+ .filter(([_, propDetails]) => propDetails.readOnly !== true)
43
+ .map(([propName]) => propName)
44
+ : [];
45
+
46
+ const requiredBodyProps = methodDetails.requestBody?.required ? methodDetails.requestBody.required : [];
47
+
48
+ const dataProps = reqBodyProps.map(prop => 'data__' + prop);
49
+
50
+ // Combine data props with params
51
+ const requiredParams = Object.keys(methodDetails.requiredParams || {});
52
+ const optionalParams = Object.keys(methodDetails.optionalParams || {});
53
+ const allFields = [...dataProps, ...requiredParams, ...optionalParams];
54
+
55
+ // Add fields to INSERT
56
+ content += allFields.join(',\n');
57
+
58
+ // Start SELECT statement
59
+ content += '\n)\nSELECT \n';
60
+
61
+ // Add values placeholders
62
+ const valueLines = allFields.map(field => {
63
+ const isDataField = field.startsWith('data__');
64
+ const paramName = isDataField ? field.substring(6) : field;
65
+
66
+ // Check for required body props
67
+ let isRequiredBodyParam = false;
68
+ if(isDataField){
69
+ if (requiredBodyProps.includes(paramName)) {
70
+ isRequiredBodyParam = true;
71
+ }
72
+ }
73
+
74
+ // Check if it's a number or boolean type
75
+ let isNumber = false;
76
+ let isBoolean = false;
77
+
78
+ if (isDataField && methodDetails.requestBody?.properties?.[paramName]) {
79
+ const propType = methodDetails.requestBody.properties[paramName].type;
80
+ isNumber = propType === 'number' || propType === 'integer';
81
+ isBoolean = propType === 'boolean';
82
+ }
83
+
84
+ if (isNumber || isBoolean) {
85
+ return '{{ ' + paramName + ' }}' + (isRequiredBodyParam ? ' --required' : '');
86
+ } else {
87
+ return '\'{{ ' + paramName + ' }}\'' + (isRequiredBodyParam ? ' --required' : '');
88
+ }
89
+ });
90
+
91
+ content += valueLines.join(',\n');
92
+
93
+ // returning clause if properties exist
94
+ if (methodDetails.properties && Object.keys(methodDetails.properties).length > 0) {
95
+ content += '\nRETURNING\n';
96
+ const keys = Object.keys(methodDetails.properties);
97
+ keys.forEach((key, index) => {
98
+ if (index === keys.length - 1) {
99
+ // For the last item, don't add a newline after it
100
+ content += `${key}`;
101
+ } else {
102
+ content += `${key},\n`;
103
+ }
104
+ });
105
+ }
106
+
107
+ content += '\n;\n```\n</TabItem>\n';
108
+ });
109
+
110
+
111
+ // {
112
+ // "code": {
113
+ // "type": "string",
114
+ // "description": " (example: 000123)"
115
+ // },
116
+ // "createdOn": {
117
+ // "type": "integer (int64)",
118
+ // "description": "Timestamp that specifies when the statement execution started.‌ The timestamp is expressed in milliseconds since the epoch.‌"
119
+ // },
120
+ // "data": {
121
+ // "type": "array",
122
+ // "description": "Result set data."
123
+ // },
124
+ // }
125
+
126
+ // Create manifest tab
127
+ content += '<TabItem value="manifest">\n\n';
128
+ content += '```yaml\n# Description fields are for documentation purposes\n- name: ' + resourceName + '\n props:\n';
129
+
130
+ // Collect all unique params and request body props across all methods
131
+ const allParams = {};
132
+ const allRequestBodyProps = {};
133
+
134
+ Object.values(insertMethods).forEach(method => {
135
+ // Add required params
136
+ Object.entries(method.requiredParams || {}).forEach(([name, details]) => {
137
+ allParams[name] = { ...details, required: true };
138
+ });
139
+
140
+ // Add optional params
141
+ Object.entries(method.optionalParams || {}).forEach(([name, details]) => {
142
+ if (!allParams[name]) {
143
+ allParams[name] = { ...details, required: false };
144
+ }
145
+ });
146
+
147
+ // Add request body props (excluding read-only props)
148
+ if (method.requestBody && method.requestBody.properties) {
149
+ Object.entries(method.requestBody.properties)
150
+ .filter(([_, propDetails]) => propDetails.readOnly !== true)
151
+ .forEach(([name, details]) => {
152
+ allRequestBodyProps[name] = details;
153
+ });
154
+ }
155
+ });
156
+
157
+ // Add required params first
158
+ Object.entries(allParams)
159
+ .filter(([_, details]) => details.required)
160
+ .forEach(([name, details]) => {
161
+ const type = details.type || 'string';
162
+ content += ' - name: ' + name + '\n';
163
+ content += ' value: ' + type + '\n';
164
+ content += ' description: Required parameter for the ' + resourceName + ' resource.\n';
165
+ });
166
+
167
+ // Add request body props
168
+ Object.entries(allRequestBodyProps).forEach(([name, details]) => {
169
+ const type = details.type || 'string';
170
+ const description = details.description || '';
171
+ content += ' - name: ' + name + '\n';
172
+ content += ' value: ' + type + '\n';
173
+
174
+ if (description) {
175
+ // Format multi-line descriptions
176
+ const wrappedDesc = description.replace(/(.{1,80})(\\s+|$)/g, '$1\n ');
177
+ content += ' description: >\n ' + wrappedDesc + '\n';
178
+ }
179
+
180
+ // Add enum values if available
181
+ if (details.enum) {
182
+ content += ' valid_values: [\'' + details.enum.join('\', \'') + '\']\n';
183
+ }
184
+
185
+ // Add default value if available
186
+ if (details.default !== undefined) {
187
+ content += ' default: ' + details.default + '\n';
188
+ }
189
+ });
190
+
191
+ // Add optional params last
192
+ Object.entries(allParams)
193
+ .filter(([_, details]) => !details.required)
194
+ .forEach(([name, details]) => {
195
+ const type = details.type || 'string';
196
+ const description = details.description || '';
197
+ content += ' - name: ' + name + '\n';
198
+ content += ' value: ' + type + '\n';
199
+
200
+ if (description) {
201
+ content += ' description: ' + description + '\n';
202
+ }
203
+ });
204
+
205
+ content += '```\n</TabItem>\n';
206
+
207
+ // Close tabs
208
+ content += '</Tabs>\n';
209
+
210
+ return content;
211
+ }
@@ -0,0 +1,73 @@
1
+ // src/docgen/resource/examples/select-example.js
2
+ import {
3
+ getSqlMethodsWithOrderedFields,
4
+ } from '../../helpers.js';
5
+
6
+ export function createSelectExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI) {
7
+ const selectMethods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, 'select');
8
+
9
+ // if there are no select methods, return empty content
10
+ if (Object.keys(selectMethods).length === 0) {
11
+ return '';
12
+ }
13
+
14
+ let content = '\n\n## `SELECT` examples\n\n';
15
+
16
+ // Create tab structure with values array
17
+ content += '<Tabs\n defaultValue="' + Object.keys(selectMethods)[0] + '"\n values={[\n';
18
+
19
+ // Add each method as a tab option
20
+ Object.keys(selectMethods).forEach((methodName, index, arr) => {
21
+ content += ' { label: \'' + methodName + '\', value: \'' + methodName + '\' }';
22
+ content += index < arr.length - 1 ? ',\n' : '\n';
23
+ });
24
+
25
+ content += ' ]}\n>\n';
26
+
27
+ // Create each tab content
28
+ Object.entries(selectMethods).forEach(([methodName, methodDetails]) => {
29
+ content += '<TabItem value="' + methodName + '">\n\n';
30
+ content += methodDetails.opDescription || 'No description available.';
31
+
32
+ // Create SQL example
33
+ content += '\n\n```sql\nSELECT\n';
34
+
35
+ // Add fields
36
+ const fieldNames = Object.keys(methodDetails.properties || {});
37
+ if (fieldNames.length > 0) {
38
+ content += fieldNames.join(',\n');
39
+ } else {
40
+ content += '*';
41
+ }
42
+
43
+ // Add FROM clause
44
+ content += '\nFROM ' + providerName + '.' + serviceName + '.' + resourceName;
45
+
46
+ // Add WHERE clause with parameters
47
+ const requiredParams = Object.keys(methodDetails.requiredParams || {});
48
+ const optionalParams = Object.keys(methodDetails.optionalParams || {});
49
+
50
+ if (requiredParams.length > 0 || optionalParams.length > 0) {
51
+ content += '\nWHERE ';
52
+
53
+ // Add required parameters
54
+ requiredParams.forEach((param, index) => {
55
+ content += param + ' = \'{{ ' + param + ' }}\' -- required';
56
+ content += index < requiredParams.length - 1 || optionalParams.length > 0 ? '\nAND ' : '';
57
+ });
58
+
59
+ // Add optional parameters
60
+ optionalParams.forEach((param, index) => {
61
+ content += param + ' = \'{{ ' + param + ' }}\'';
62
+ content += index < optionalParams.length - 1 ? '\nAND ' : '';
63
+ });
64
+ }
65
+
66
+ content += ';\n```\n</TabItem>\n';
67
+ });
68
+
69
+ // Close tabs
70
+ content += '</Tabs>\n';
71
+
72
+ return content;
73
+ }
@@ -0,0 +1,154 @@
1
+ // src/docgen/resource/examples/update-example.js
2
+ import {
3
+ getSqlMethodsWithOrderedFields,
4
+ } from '../../helpers.js';
5
+
6
+ export function createUpdateExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI, isReplace = false) {
7
+ const updateMethods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, isReplace ? 'replace' : 'update');
8
+
9
+ // if there are no update methods, return empty content
10
+ if (Object.keys(updateMethods).length === 0) {
11
+ return '';
12
+ }
13
+
14
+ let content = '';
15
+ if (isReplace) {
16
+ content += '\n\n## `REPLACE` examples\n\n';
17
+ } else {
18
+ content += '\n\n## `UPDATE` examples\n\n';
19
+ }
20
+
21
+ // Create tab structure with values array
22
+ content += '<Tabs\n defaultValue="' + Object.keys(updateMethods)[0] + '"\n values={[\n';
23
+
24
+ // Add each method as a tab option
25
+ Object.keys(updateMethods).forEach((methodName, index, arr) => {
26
+ content += ' { label: \'' + methodName + '\', value: \'' + methodName + '\' }';
27
+ content += index < arr.length - 1 ? ',\n' : '\n';
28
+ });
29
+
30
+ content += ' ]}\n>\n';
31
+
32
+ // Create each method tab content
33
+ Object.entries(updateMethods).forEach(([methodName, methodDetails]) => {
34
+ content += '<TabItem value="' + methodName + '">\n\n';
35
+
36
+ // Add method description
37
+ content += methodDetails.opDescription || methodDetails.respDescription || 'No description available.';
38
+
39
+ // Create SQL example
40
+ content += '\n\n```sql\n';
41
+ content += (isReplace ? 'REPLACE ' : 'UPDATE ') + providerName + '.' + serviceName + '.' + resourceName;
42
+
43
+ // Add SET clause with requestBody fields (excluding read-only props)
44
+ content += '\nSET \n';
45
+
46
+ // Get request body fields (excluding read-only props)
47
+ const reqBodyProps = methodDetails.requestBody?.properties
48
+ ? Object.entries(methodDetails.requestBody.properties)
49
+ .filter(([_, propDetails]) => propDetails.readOnly !== true)
50
+ .map(([propName]) => propName)
51
+ : [];
52
+
53
+ // Add data__ prefixed fields to SET clause
54
+ if (reqBodyProps.length > 0) {
55
+ const setLines = reqBodyProps.map(prop => {
56
+ const propDetails = methodDetails.requestBody.properties[prop];
57
+ const isNumber = propDetails.type === 'number' || propDetails.type === 'integer';
58
+ const isBoolean = propDetails.type === 'boolean';
59
+
60
+ if (isNumber || isBoolean) {
61
+ return 'data__' + prop + ' = {{ ' + prop + ' }}';
62
+ } else {
63
+ return 'data__' + prop + ' = \'{{ ' + prop + ' }}\'';
64
+ }
65
+ });
66
+
67
+ content += setLines.join(',\n');
68
+ } else {
69
+ content += '-- No updatable properties';
70
+ }
71
+
72
+ // Add WHERE clause with parameters
73
+ const requiredParams = Object.keys(methodDetails.requiredParams || {});
74
+ const optionalParams = Object.keys(methodDetails.optionalParams || {});
75
+
76
+ // Get required body props (excluding read-only props)
77
+ const requiredBodyProps = methodDetails.requestBody?.required
78
+ ? methodDetails.requestBody.required.filter(prop =>
79
+ methodDetails.requestBody.properties[prop] &&
80
+ methodDetails.requestBody.properties[prop].readOnly !== true)
81
+ : [];
82
+
83
+ content += '\nWHERE \n';
84
+
85
+ // Add required parameters
86
+ let clauseCount = 0;
87
+
88
+ // Add required query/path/header params
89
+ requiredParams.forEach(param => {
90
+ if (clauseCount > 0) content += '\nAND ';
91
+ content += param + ' = \'{{ ' + param + ' }}\' --required';
92
+ clauseCount++;
93
+ });
94
+
95
+ // Add required body params (only non-readonly ones)
96
+ requiredBodyProps.forEach(prop => {
97
+ if (clauseCount > 0) content += '\nAND ';
98
+
99
+ const propDetails = methodDetails.requestBody.properties[prop];
100
+ const isBoolean = propDetails.type === 'boolean';
101
+
102
+ if (isBoolean) {
103
+ content += 'data__' + prop + ' = {{ ' + prop + ' }} --required';
104
+ } else {
105
+ content += 'data__' + prop + ' = \'{{ ' + prop + ' }}\' --required';
106
+ }
107
+
108
+ clauseCount++;
109
+ });
110
+
111
+ // Add optional parameters
112
+ optionalParams.forEach(param => {
113
+ if (clauseCount > 0) content += '\nAND ';
114
+
115
+ // For boolean parameters, we can add a comment about their default value
116
+ const paramDetails = methodDetails.optionalParams[param];
117
+ const isBoolean = paramDetails.type === 'boolean';
118
+ const defaultValue = paramDetails.default;
119
+
120
+ if (isBoolean) {
121
+ content += param + ' = {{ ' + param + '}}';
122
+ } else {
123
+ content += param + ' = \'{{ ' + param + '}}\'';
124
+ }
125
+
126
+ if (isBoolean && defaultValue !== undefined) {
127
+ content += ' -- default: ' + defaultValue;
128
+ }
129
+
130
+ clauseCount++;
131
+ });
132
+
133
+ // returning clause if properties exist
134
+ if (methodDetails.properties && Object.keys(methodDetails.properties).length > 0) {
135
+ content += '\nRETURNING\n';
136
+ const keys = Object.keys(methodDetails.properties);
137
+ keys.forEach((key, index) => {
138
+ if (index === keys.length - 1) {
139
+ // For the last item, don't add a newline after it
140
+ content += `${key}`;
141
+ } else {
142
+ content += `${key},\n`;
143
+ }
144
+ });
145
+ }
146
+
147
+ content += ';\n```\n</TabItem>\n';
148
+ });
149
+
150
+ // Close tabs
151
+ content += '</Tabs>\n';
152
+
153
+ return content;
154
+ }
@@ -0,0 +1,31 @@
1
+ // src/docgen/resource/examples.js
2
+
3
+ import { createSelectExamples } from './examples/select-example.js';
4
+ import { createInsertExamples } from './examples/insert-example.js';
5
+ import { createUpdateExamples } from './examples/update-example.js';
6
+ import { createDeleteExamples } from './examples/delete-example.js';
7
+ import { createExecExamples } from './examples/exec-example.js';
8
+
9
+ export function createExamplesSection(providerName, serviceName, resourceName, resourceData, dereferencedAPI) {
10
+ let content = '';
11
+
12
+ // Add SELECT examples
13
+ content += createSelectExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI);
14
+
15
+ // Add INSERT examples
16
+ content += createInsertExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI);
17
+
18
+ // Add UPDATE examples
19
+ content += createUpdateExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI, false);
20
+
21
+ // Add REPLACE examples
22
+ content += createUpdateExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI, true);
23
+
24
+ // Add DELETE examples
25
+ content += createDeleteExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI);
26
+
27
+ // Add EXEC examples
28
+ content += createExecExamples(providerName, serviceName, resourceName, resourceData, dereferencedAPI);
29
+
30
+ return content;
31
+ }
@@ -0,0 +1,82 @@
1
+ // src/docgen/resource/fields.js
2
+ import {
3
+ getSqlMethodsWithOrderedFields,
4
+ } from '../helpers.js';
5
+
6
+ const mdCodeAnchor = "`";
7
+
8
+ export function createFieldsSection(resourceData, dereferencedAPI) {
9
+ let content = '## Fields\n\n';
10
+
11
+ content += 'The following fields are returned by `SELECT` queries:\n\n';
12
+
13
+ // Use the reusable function to get methods with ordered fields
14
+ const methods = getSqlMethodsWithOrderedFields(resourceData, dereferencedAPI, 'select');
15
+
16
+ if (Object.keys(methods).length > 0) {
17
+ // Create the tabs and markdown content
18
+ const methodNames = Object.keys(methods);
19
+
20
+ // Create the tab values array for the Tabs component
21
+ const tabValues = methodNames.map(methodName => {
22
+ return `{ label: '${methodName}', value: '${methodName}' }`;
23
+ }).join(',\n ');
24
+
25
+ // Start building the Tabs component
26
+ content += `<Tabs
27
+ defaultValue="${methodNames[0]}"
28
+ values={[
29
+ ${tabValues}
30
+ ]}
31
+ >\n`;
32
+
33
+ // Create the TabItems with table content
34
+ for (const methodName of methodNames) {
35
+ const methodData = methods[methodName];
36
+
37
+ // Start the TabItem
38
+ content += `<TabItem value="${methodName}">\n\n`;
39
+
40
+ // Add the method description if available
41
+ if (methodData.respDescription) {
42
+ content += `${methodData.respDescription}\n\n`;
43
+ }
44
+
45
+ // Add the table header
46
+ content += `<table>
47
+ <thead>
48
+ <tr>
49
+ <th>Name</th>
50
+ <th>Datatype</th>
51
+ <th>Description</th>
52
+ </tr>
53
+ </thead>
54
+ <tbody>`;
55
+
56
+ // Add each property as a row in the table
57
+ for (const [propName, propData] of Object.entries(methodData.properties)) {
58
+ content += `\n<tr>
59
+ <td><CopyableCode code="${propName}" /></td>
60
+ <td><code>${propData.type}</code></td>
61
+ <td>${propData.description}</td>
62
+ </tr>`;
63
+ }
64
+
65
+ content += `\n</tbody>
66
+ </table>
67
+ `;
68
+
69
+ // Close the TabItem
70
+ content += `</TabItem>\n`;
71
+ }
72
+
73
+ // Close the Tabs component
74
+ content += `</Tabs>\n`;
75
+ } else {
76
+ // no fields
77
+ content += `${mdCodeAnchor}SELECT${mdCodeAnchor} not supported for this resource, use ${mdCodeAnchor}SHOW METHODS${mdCodeAnchor} to view available operations for the resource.\n\n`;
78
+ }
79
+
80
+ return content;
81
+ }
82
+