@stackql/provider-utils 0.4.0 → 0.4.2
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 +60 -242
- package/package.json +1 -1
- package/src/docgen/resource/fields.js +12 -5
- package/src/docgen/resource/methods.js +28 -4
- package/src/providerdev/analyze.js +37 -8
- package/src/providerdev/split.js +30 -44
package/README.md
CHANGED
|
@@ -1,42 +1,33 @@
|
|
|
1
1
|
# StackQL Provider Utils
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+
|
|
6
|
+
A comprehensive toolkit for transforming OpenAPI specifications into StackQL providers. This library streamlines the process of parsing, mapping, validating, testing, and generating documentation for StackQL providers.
|
|
4
7
|
|
|
5
8
|
## Table of Contents
|
|
6
9
|
|
|
7
10
|
- [Prerequisites](#prerequisites)
|
|
8
11
|
- [Installation](#installation)
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
11
|
-
- [
|
|
12
|
-
- [
|
|
12
|
+
- [Directory Structure](#directory-structure)
|
|
13
|
+
- [Provider Development Workflow](#provider-development-workflow)
|
|
14
|
+
- [`providerdev.split`](docs/split.md) - Divide a large OpenAPI specification into smaller, service-specific files
|
|
15
|
+
- [`providerdev.analyze`](docs/analyze.md) - Examine split API specifications to generate mapping recommendations
|
|
16
|
+
- [`providerdev.generate`](docs/generate.md) - Create StackQL provider extensions from specifications and mappings
|
|
17
|
+
- [`docgen.generateDocs`](docs/docgen.md) - Generate comprehensive documentation for StackQL providers
|
|
13
18
|
- [Contributing](#contributing)
|
|
19
|
+
- [License](#license)
|
|
20
|
+
- [Support](#support)
|
|
14
21
|
|
|
15
22
|
## Prerequisites
|
|
16
23
|
|
|
17
|
-
### For Node.js
|
|
18
24
|
- Node.js >= 20
|
|
19
|
-
- npm or yarn
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
### Installing StackQL
|
|
23
|
-
|
|
24
|
-
Download and install StackQL from [stackql.io/downloads](https://stackql.io/downloads)
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
# macOS
|
|
28
|
-
brew install stackql
|
|
29
|
-
|
|
30
|
-
# Linux
|
|
31
|
-
curl -L https://bit.ly/stackql-zip -O && unzip stackql-zip
|
|
32
|
-
|
|
33
|
-
# Windows
|
|
34
|
-
# Download from https://stackql.io/downloads
|
|
35
|
-
```
|
|
25
|
+
- `npm` or `yarn`
|
|
26
|
+
- [`stackql`](https://stackql.io/docs/installing-stackql) for testing
|
|
36
27
|
|
|
37
28
|
## Installation
|
|
38
29
|
|
|
39
|
-
|
|
30
|
+
Add `@stackql/provider-utils` to your `package.json`:
|
|
40
31
|
|
|
41
32
|
```bash
|
|
42
33
|
npm install @stackql/provider-utils
|
|
@@ -44,229 +35,55 @@ npm install @stackql/provider-utils
|
|
|
44
35
|
yarn add @stackql/provider-utils
|
|
45
36
|
```
|
|
46
37
|
|
|
47
|
-
##
|
|
48
|
-
|
|
49
|
-
1. Clone the repository:
|
|
50
|
-
```bash
|
|
51
|
-
git clone https://github.com/stackql/stackql-provider-utils.git
|
|
52
|
-
cd stackql-provider-utils
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
2. Install dependencies (Node.js):
|
|
56
|
-
```bash
|
|
57
|
-
npm install
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## Testing with Node.js
|
|
61
|
-
|
|
62
|
-
### 1. Create a Test Script
|
|
63
|
-
|
|
64
|
-
Create a file `test-docgen.js`:
|
|
65
|
-
|
|
66
|
-
```javascript
|
|
67
|
-
import { docgen } from './src/index.js';
|
|
68
|
-
|
|
69
|
-
// Test the documentation generator
|
|
70
|
-
async function testDocGen() {
|
|
71
|
-
try {
|
|
72
|
-
const result = await docgen.generateDocs({
|
|
73
|
-
providerName: 'myservice',
|
|
74
|
-
providerDir: './test-data/output/src/myservice/v00.00.00000',
|
|
75
|
-
outputDir: './test-output',
|
|
76
|
-
providerDataDir: './test-data/provider-data',
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
console.log('Documentation generated successfully:', result);
|
|
80
|
-
} catch (error) {
|
|
81
|
-
console.error('Error generating documentation:', error);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
testDocGen();
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 2. Set Up Test Data
|
|
89
|
-
|
|
90
|
-
Create the required directory structure:
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
mkdir -p test-data/output/src/myservice/v00.00.00000/services
|
|
94
|
-
mkdir -p test-data/provider-data
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Add test files:
|
|
98
|
-
|
|
99
|
-
`test-data/provider-data/headerContent1.txt`:
|
|
100
|
-
```
|
|
101
|
-
---
|
|
102
|
-
title: myservice
|
|
103
|
-
hide_title: false
|
|
104
|
-
hide_table_of_contents: false
|
|
105
|
-
keywords:
|
|
106
|
-
- myservice
|
|
107
|
-
- stackql
|
|
108
|
-
- infrastructure-as-code
|
|
109
|
-
- configuration-as-data
|
|
110
|
-
description: Query and manage myservice resources using SQL
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
# myservice Provider
|
|
114
|
-
|
|
115
|
-
The myservice provider for StackQL allows you to query, deploy, and manage myservice resources using SQL.
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
`test-data/provider-data/headerContent2.txt`:
|
|
119
|
-
```
|
|
120
|
-
See the [myservice provider documentation](https://myservice.com/docs) for more information.
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
`test-data/output/src/myservice/v00.00.00000/services/example.yaml`:
|
|
124
|
-
```yaml
|
|
125
|
-
openapi: 3.0.0
|
|
126
|
-
info:
|
|
127
|
-
title: Example Service
|
|
128
|
-
version: 1.0.0
|
|
129
|
-
paths:
|
|
130
|
-
/examples:
|
|
131
|
-
get:
|
|
132
|
-
operationId: listExamples
|
|
133
|
-
responses:
|
|
134
|
-
'200':
|
|
135
|
-
description: Success
|
|
136
|
-
components:
|
|
137
|
-
x-stackQL-resources:
|
|
138
|
-
examples:
|
|
139
|
-
id: myservice.example.examples
|
|
140
|
-
name: examples
|
|
141
|
-
title: Examples
|
|
142
|
-
methods:
|
|
143
|
-
list:
|
|
144
|
-
operation:
|
|
145
|
-
$ref: '#/paths/~1examples/get'
|
|
146
|
-
response:
|
|
147
|
-
mediaType: application/json
|
|
148
|
-
openAPIDocKey: '200'
|
|
149
|
-
sqlVerbs:
|
|
150
|
-
select:
|
|
151
|
-
- $ref: '#/components/x-stackQL-resources/examples/methods/list'
|
|
152
|
-
```
|
|
38
|
+
## Directory Structure
|
|
153
39
|
|
|
154
|
-
|
|
40
|
+
A typical project structure for the development of a `stackql` provider would be...
|
|
155
41
|
|
|
156
42
|
```bash
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
### Provider Data Directory
|
|
198
|
-
```
|
|
199
|
-
provider-data/
|
|
200
|
-
├── headerContent1.txt # Provider introduction
|
|
201
|
-
├── headerContent2.txt # Additional provider info
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
### Provider Spec Directory
|
|
205
|
-
```
|
|
206
|
-
output/src/{provider}/v00.00.00000/
|
|
207
|
-
├── provider.yaml
|
|
208
|
-
└── services/
|
|
209
|
-
├── service1.yaml
|
|
210
|
-
├── service2.yaml
|
|
211
|
-
└── ...
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### Generated Output
|
|
215
|
-
```
|
|
216
|
-
docs/{provider}-docs/
|
|
217
|
-
├── index.md
|
|
218
|
-
└── {service}/
|
|
219
|
-
├── index.md
|
|
220
|
-
└── {resource}/
|
|
221
|
-
└── index.md
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
## Troubleshooting
|
|
225
|
-
|
|
226
|
-
### Missing Provider Data
|
|
227
|
-
- Ensure `headerContent1.txt` and `headerContent2.txt` exist in provider data directory
|
|
228
|
-
- Check file permissions
|
|
229
|
-
|
|
230
|
-
### Empty Documentation
|
|
231
|
-
- Verify provider specs have `x-stackQL-resources` components
|
|
232
|
-
- Check that resources have proper method definitions
|
|
233
|
-
|
|
234
|
-
## API Reference
|
|
235
|
-
|
|
236
|
-
### `docgen.generateDocs(options)`
|
|
237
|
-
|
|
238
|
-
Generates documentation for a StackQL provider.
|
|
239
|
-
|
|
240
|
-
**Parameters:**
|
|
241
|
-
- `options` (Object): Configuration options
|
|
242
|
-
|
|
243
|
-
**Returns:**
|
|
244
|
-
- Promise<Object>: Result object containing:
|
|
245
|
-
- `totalServices`: Number of services processed
|
|
246
|
-
- `totalResources`: Number of resources documented
|
|
247
|
-
- `outputPath`: Path to generated documentation
|
|
248
|
-
|
|
249
|
-
**Example:**
|
|
250
|
-
```javascript
|
|
251
|
-
const result = await docgen.generateDocs({
|
|
252
|
-
providerName: 'aws',
|
|
253
|
-
providerDir: './providers/src/aws/v00.00.00000',
|
|
254
|
-
outputDir: './documentation',
|
|
255
|
-
providerDataDir: './config/aws',
|
|
256
|
-
});
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
### `docgen.createResourceIndexContent(...)`
|
|
260
|
-
|
|
261
|
-
Creates markdown content for a single resource. This is a lower-level function used internally by `generateDocs`.
|
|
43
|
+
.
|
|
44
|
+
├── bin # convinience scripts
|
|
45
|
+
│ ├── ...
|
|
46
|
+
├── provider-dev
|
|
47
|
+
│ ├── config
|
|
48
|
+
│ │ └── all_services.csv # mappings generated or updated by the `providerdev.analyze` function, used by `providerdev.generate`
|
|
49
|
+
│ ├── docgen
|
|
50
|
+
│ │ └── provider-data # provider metadata used by `docgen.generateDocs`
|
|
51
|
+
│ │ ├── headerContent1.txt
|
|
52
|
+
│ │ └── headerContent2.txt
|
|
53
|
+
│ ├── downloaded # used to store the original spec for the provider
|
|
54
|
+
│ │ └── management-minimal.yaml
|
|
55
|
+
│ ├── openapi # output from `providerdev.generate`, this is the stackql provider
|
|
56
|
+
│ │ └── src
|
|
57
|
+
│ │ └── okta
|
|
58
|
+
│ │ └── v00.00.00000
|
|
59
|
+
│ │ ├── provider.yaml
|
|
60
|
+
│ │ └── services
|
|
61
|
+
│ │ ├── agentpools.yaml
|
|
62
|
+
│ │ ├── ...
|
|
63
|
+
│ ├── scripts # optional scripts for pre or post processing if required
|
|
64
|
+
│ │ └── post_processing.sh
|
|
65
|
+
│ └── source # output from `providerdev.split` if used, this is the source used with the mappings to generate the provider
|
|
66
|
+
│ ├── agentpools.yaml
|
|
67
|
+
│ ├── ...
|
|
68
|
+
└── website # docusaurus site
|
|
69
|
+
├── docs # output from `docgen.generateDocs`
|
|
70
|
+
│ ├── ...
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
> see [__stackql-provider-okta__](https://github.com/stackql/stackql-provider-okta) for a working example.
|
|
74
|
+
|
|
75
|
+
## Provider Development Workflow
|
|
76
|
+
|
|
77
|
+
The library provides a streamlined workflow for creating StackQL providers from OpenAPI specifications:
|
|
78
|
+
|
|
79
|
+
1. [`providerdev.split`](docs/split.md) - Divide a large OpenAPI specification into smaller, service-specific files
|
|
80
|
+
2. [`providerdev.analyze`](docs/analyze.md) - Examine split API specifications to generate mapping recommendations
|
|
81
|
+
3. [`providerdev.generate`](docs/generate.md) - Create StackQL provider extensions from specifications and mappings
|
|
82
|
+
4. [`docgen.generateDocs`](docs/docgen.md) - Generate comprehensive documentation for StackQL providers
|
|
262
83
|
|
|
263
84
|
## Contributing
|
|
264
85
|
|
|
265
|
-
|
|
266
|
-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
267
|
-
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
268
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
269
|
-
5. Open a Pull Request
|
|
86
|
+
Contributions are welcome!
|
|
270
87
|
|
|
271
88
|
## License
|
|
272
89
|
|
|
@@ -276,4 +93,5 @@ MIT
|
|
|
276
93
|
|
|
277
94
|
- [StackQL Documentation](https://stackql.io/docs)
|
|
278
95
|
- [GitHub Issues](https://github.com/stackql/stackql-provider-utils/issues)
|
|
279
|
-
- [StackQL
|
|
96
|
+
- [StackQL Community Slack](https://stackqlcommunity.slack.com/join/shared_invite/zt-1cbdq9s5v-CkY65IMAesCgFqjN6FU6hg)
|
|
97
|
+
- [StackQL Discord](https://discord.com/invite/xVXZ9d5NxN)
|
package/package.json
CHANGED
|
@@ -7,6 +7,13 @@ import { docView } from './view.js';
|
|
|
7
7
|
|
|
8
8
|
const mdCodeAnchor = "`";
|
|
9
9
|
|
|
10
|
+
// List of meaningless descriptions to filter out (all lowercase)
|
|
11
|
+
const meaninglessDescriptions = [
|
|
12
|
+
'ok',
|
|
13
|
+
'successful response',
|
|
14
|
+
'success'
|
|
15
|
+
];
|
|
16
|
+
|
|
10
17
|
export function createFieldsSection(resourceType, resourceData, dereferencedAPI) {
|
|
11
18
|
let content = '## Fields\n\n';
|
|
12
19
|
|
|
@@ -41,14 +48,14 @@ export function createFieldsSection(resourceType, resourceData, dereferencedAPI)
|
|
|
41
48
|
// Start the TabItem
|
|
42
49
|
content += `<TabItem value="${methodName}">\n\n`;
|
|
43
50
|
|
|
44
|
-
// Add the method description if available
|
|
45
|
-
if (methodData.respDescription
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
) {
|
|
51
|
+
// Add the method description if available and not in the meaningless list
|
|
52
|
+
if (methodData.respDescription &&
|
|
53
|
+
!meaninglessDescriptions.includes(methodData.respDescription.trim().toLowerCase()) &&
|
|
54
|
+
methodData.respDescription.trim().length > 0) {
|
|
49
55
|
content += `${sanitizeHtml(methodData.respDescription)}\n\n`;
|
|
50
56
|
}
|
|
51
57
|
|
|
58
|
+
|
|
52
59
|
// Add the table header
|
|
53
60
|
content += `<table>
|
|
54
61
|
<thead>
|
|
@@ -4,6 +4,24 @@ import {
|
|
|
4
4
|
sanitizeHtml
|
|
5
5
|
} from '../helpers.js';
|
|
6
6
|
|
|
7
|
+
const getRequiredBodyParams = (methodDetails, accessType) => {
|
|
8
|
+
// Only process request body for insert, update, replace, and exec
|
|
9
|
+
if (!['insert', 'update', 'replace', 'exec'].includes(accessType)) {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Get required body params if they exist
|
|
14
|
+
const requiredBodyProps = methodDetails.requestBody?.required ? methodDetails.requestBody.required : [];
|
|
15
|
+
|
|
16
|
+
// For insert, update, and replace, prefix with data__
|
|
17
|
+
if (['insert', 'update', 'replace'].includes(accessType)) {
|
|
18
|
+
return requiredBodyProps.map(prop => `data__${prop}`);
|
|
19
|
+
} else {
|
|
20
|
+
// For exec, don't prefix
|
|
21
|
+
return requiredBodyProps;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
7
25
|
export function createMethodsSection(resourceData, dereferencedAPI) {
|
|
8
26
|
|
|
9
27
|
let content = `\n## Methods\n\n`;
|
|
@@ -37,10 +55,16 @@ export function createMethodsSection(resourceData, dereferencedAPI) {
|
|
|
37
55
|
for (const [methodName, methodDetails] of Object.entries(methods)) {
|
|
38
56
|
console.info(`Adding ${accessType} method to table: ${methodName}`);
|
|
39
57
|
|
|
58
|
+
// Get required params from both the standard params and the request body
|
|
59
|
+
const reqParamsArr = Object.keys(methodDetails.requiredParams || {});
|
|
60
|
+
const reqBodyParamsArr = getRequiredBodyParams(methodDetails, accessType);
|
|
61
|
+
|
|
62
|
+
// Combine both types of required parameters
|
|
63
|
+
const allReqParamsArr = [...reqParamsArr, ...reqBodyParamsArr];
|
|
64
|
+
|
|
40
65
|
// Format required params as comma-delimited list with hyperlinks
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
? requiredParamsArr.map(param => `<a href="#parameter-${param}"><code>${param}</code></a>`).join(', ')
|
|
66
|
+
const requiredParamsStr = allReqParamsArr.length > 0
|
|
67
|
+
? allReqParamsArr.map(param => `<a href="#parameter-${param}"><code>${param}</code></a>`).join(', ')
|
|
44
68
|
: '';
|
|
45
69
|
|
|
46
70
|
// Format optional params as comma-delimited list with hyperlinks
|
|
@@ -48,7 +72,7 @@ export function createMethodsSection(resourceData, dereferencedAPI) {
|
|
|
48
72
|
const optionalParamsStr = optionalParamsArr.length > 0
|
|
49
73
|
? optionalParamsArr.map(param => `<a href="#parameter-${param}"><code>${param}</code></a>`).join(', ')
|
|
50
74
|
: '';
|
|
51
|
-
|
|
75
|
+
|
|
52
76
|
// Add the method row to the table
|
|
53
77
|
content += `
|
|
54
78
|
<tr>
|
|
@@ -95,6 +95,23 @@ function findExistingMapping(spec, pathRef) {
|
|
|
95
95
|
};
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Escape and sanitize a CSV field value
|
|
100
|
+
* @param {string} value - Field value to escape
|
|
101
|
+
* @returns {string} - Escaped value
|
|
102
|
+
*/
|
|
103
|
+
function escapeCsvField(value) {
|
|
104
|
+
if (!value) return '';
|
|
105
|
+
|
|
106
|
+
// If the value contains commas, double quotes, or newlines, wrap it in quotes
|
|
107
|
+
// and escape any existing double quotes by doubling them
|
|
108
|
+
if (value.includes(',') || value.includes('"') || value.includes('\n')) {
|
|
109
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
|
|
98
115
|
/**
|
|
99
116
|
* Analyze OpenAPI specs and generate mapping CSV
|
|
100
117
|
* @param {Object} options - Options for analysis
|
|
@@ -159,7 +176,7 @@ export async function analyze(options) {
|
|
|
159
176
|
|
|
160
177
|
// Only write header if creating a new file
|
|
161
178
|
if (!fileExists) {
|
|
162
|
-
writer.write('filename,path,operationId,formatted_op_id,verb,response_object,tags,formatted_tags,stackql_resource_name,stackql_method_name,stackql_verb\n');
|
|
179
|
+
writer.write('filename,path,operationId,formatted_op_id,verb,response_object,tags,formatted_tags,stackql_resource_name,stackql_method_name,stackql_verb,op_description\n');
|
|
163
180
|
}
|
|
164
181
|
|
|
165
182
|
const files = fs.readdirSync(inputDir);
|
|
@@ -216,15 +233,27 @@ export async function analyze(options) {
|
|
|
216
233
|
// Find existing mapping if available
|
|
217
234
|
const { resourceName, methodName, sqlVerb } = findExistingMapping(spec, pathRef);
|
|
218
235
|
|
|
219
|
-
//
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
const
|
|
224
|
-
|
|
236
|
+
// Get operation description
|
|
237
|
+
const opDescription = operation.summary || operation.description || '';
|
|
238
|
+
|
|
239
|
+
// Escape fields that might contain commas, quotes, or other special characters
|
|
240
|
+
const escapedFields = {
|
|
241
|
+
filename: escapeCsvField(filename),
|
|
242
|
+
path: escapeCsvField(pathKey),
|
|
243
|
+
operationId: escapeCsvField(operationId),
|
|
244
|
+
formattedOpId: escapeCsvField(formattedOpId),
|
|
245
|
+
verb: escapeCsvField(verb),
|
|
246
|
+
responseRef: escapeCsvField(responseRef),
|
|
247
|
+
tagsStr: escapeCsvField(tagsStr),
|
|
248
|
+
formattedTags: escapeCsvField(formattedTags),
|
|
249
|
+
resourceName: escapeCsvField(resourceName),
|
|
250
|
+
methodName: escapeCsvField(methodName),
|
|
251
|
+
sqlVerb: escapeCsvField(sqlVerb),
|
|
252
|
+
opDescription: escapeCsvField(opDescription)
|
|
253
|
+
};
|
|
225
254
|
|
|
226
255
|
// Write row
|
|
227
|
-
writer.write(`${filename},${
|
|
256
|
+
writer.write(`${escapedFields.filename},${escapedFields.path},${escapedFields.operationId},${escapedFields.formattedOpId},${escapedFields.verb},${escapedFields.responseRef},${escapedFields.tagsStr},${escapedFields.formattedTags},${escapedFields.resourceName},${escapedFields.methodName},${escapedFields.sqlVerb},${escapedFields.opDescription}\n`);
|
|
228
257
|
}
|
|
229
258
|
}
|
|
230
259
|
}
|
package/src/providerdev/split.js
CHANGED
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
|
|
12
12
|
// Constants
|
|
13
13
|
const OPERATIONS = ["get", "post", "put", "delete", "patch", "options", "head", "trace"];
|
|
14
|
-
const NON_OPERATIONS = ["parameters", "servers", "summary", "description"];
|
|
15
14
|
const COMPONENTS_CHILDREN = ["schemas", "responses", "parameters", "examples", "requestBodies", "headers", "securitySchemes", "links", "callbacks"];
|
|
16
15
|
|
|
17
16
|
/**
|
|
@@ -42,9 +41,10 @@ function isOperationExcluded(exclude, opItem) {
|
|
|
42
41
|
* @param {string} svcDiscriminator - Service discriminator
|
|
43
42
|
* @param {Object[]} allTags - All tags from API doc
|
|
44
43
|
* @param {boolean} debug - Debug flag
|
|
44
|
+
* @param {Object} svcNameOverrides - Service name overrides
|
|
45
45
|
* @returns {[string, string]} - [service name, service description]
|
|
46
46
|
*/
|
|
47
|
-
function retServiceNameAndDesc(providerName, opItem, pathKey, svcDiscriminator, allTags, debug) {
|
|
47
|
+
function retServiceNameAndDesc(providerName, opItem, pathKey, svcDiscriminator, allTags, debug, svcNameOverrides) {
|
|
48
48
|
let service = "default";
|
|
49
49
|
let serviceDesc = `${providerName} API`;
|
|
50
50
|
|
|
@@ -84,9 +84,25 @@ function retServiceNameAndDesc(providerName, opItem, pathKey, svcDiscriminator,
|
|
|
84
84
|
return ["skip", ""];
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
// Apply service name overrides if present
|
|
88
|
+
if (svcNameOverrides && svcNameOverrides[service]) {
|
|
89
|
+
const newName = svcNameOverrides[service];
|
|
90
|
+
if (debug) {
|
|
91
|
+
logger.debug(`Overriding service name: ${service} -> ${newName}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Update service description for path-based services
|
|
95
|
+
if (svcDiscriminator === "path") {
|
|
96
|
+
serviceDesc = `${providerName} ${newName} API`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
service = newName;
|
|
100
|
+
}
|
|
101
|
+
|
|
87
102
|
return [service, serviceDesc];
|
|
88
103
|
}
|
|
89
104
|
|
|
105
|
+
|
|
90
106
|
/**
|
|
91
107
|
* Initialize service map
|
|
92
108
|
* @param {Object} services - Services map
|
|
@@ -192,43 +208,6 @@ function getPathLevelRefs(pathItem) {
|
|
|
192
208
|
return refs;
|
|
193
209
|
}
|
|
194
210
|
|
|
195
|
-
/**
|
|
196
|
-
* Add referenced components to service
|
|
197
|
-
* @param {Set<string>} refs - Set of refs
|
|
198
|
-
* @param {Object} service - Service object
|
|
199
|
-
* @param {Object} components - Components from API doc
|
|
200
|
-
* @param {boolean} debug - Debug flag
|
|
201
|
-
*/
|
|
202
|
-
function addRefsToComponents(refs, service, components, debug) {
|
|
203
|
-
for (const ref of refs) {
|
|
204
|
-
const parts = ref.split('/');
|
|
205
|
-
|
|
206
|
-
// Only process refs that point to components
|
|
207
|
-
if (parts.length >= 4 && parts[1] === "components") {
|
|
208
|
-
const componentType = parts[2];
|
|
209
|
-
const componentName = parts[3];
|
|
210
|
-
|
|
211
|
-
// Check if component type exists in service
|
|
212
|
-
if (!service.components[componentType]) {
|
|
213
|
-
service.components[componentType] = {};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// Skip if component already added
|
|
217
|
-
if (service.components[componentType][componentName]) {
|
|
218
|
-
continue;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Add component if it exists in source document
|
|
222
|
-
if (components[componentType] && components[componentType][componentName]) {
|
|
223
|
-
service.components[componentType][componentName] = components[componentType][componentName];
|
|
224
|
-
if (debug) {
|
|
225
|
-
logger.debug(`Added component ${componentType}/${componentName}`);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
211
|
/**
|
|
233
212
|
* Add missing type: object to schema objects
|
|
234
213
|
* @param {any} obj - Object to process
|
|
@@ -338,7 +317,8 @@ export async function split(options) {
|
|
|
338
317
|
svcDiscriminator = "tag",
|
|
339
318
|
exclude = null,
|
|
340
319
|
overwrite = true,
|
|
341
|
-
verbose = false
|
|
320
|
+
verbose = false,
|
|
321
|
+
svcNameOverrides = {} // Add this new parameter with default empty object
|
|
342
322
|
} = options;
|
|
343
323
|
|
|
344
324
|
// Setup logging based on verbosity
|
|
@@ -351,6 +331,13 @@ export async function split(options) {
|
|
|
351
331
|
logger.info(`Output: ${outputDir}`);
|
|
352
332
|
logger.info(`Service Discriminator: ${svcDiscriminator}`);
|
|
353
333
|
|
|
334
|
+
if (Object.keys(svcNameOverrides).length > 0) {
|
|
335
|
+
logger.info(`Using ${Object.keys(svcNameOverrides).length} service name overrides`);
|
|
336
|
+
if (verbose) {
|
|
337
|
+
logger.debug(`Service name overrides: ${JSON.stringify(svcNameOverrides, null, 2)}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
354
341
|
// Process exclude list
|
|
355
342
|
const excludeList = exclude ? exclude.split(",") : [];
|
|
356
343
|
|
|
@@ -409,12 +396,11 @@ export async function split(options) {
|
|
|
409
396
|
continue;
|
|
410
397
|
}
|
|
411
398
|
|
|
412
|
-
// Determine service name
|
|
413
399
|
const [service, serviceDesc] = retServiceNameAndDesc(
|
|
414
400
|
providerName, opItem, pathKey, svcDiscriminator,
|
|
415
|
-
apiDocObj.tags || [], verbose
|
|
416
|
-
);
|
|
417
|
-
|
|
401
|
+
apiDocObj.tags || [], verbose, svcNameOverrides
|
|
402
|
+
);
|
|
403
|
+
|
|
418
404
|
// Skip if service is marked to skip
|
|
419
405
|
if (service === 'skip') {
|
|
420
406
|
logger.warn(`⭐️ Skipping service: ${service}`);
|