@jentic/arazzo-parser 1.0.0-alpha.2 → 1.0.0-alpha.21
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/CHANGELOG.md +104 -0
- package/README.md +453 -49
- package/dist/jentic-arazzo-parser.browser.js +70344 -46424
- package/dist/jentic-arazzo-parser.browser.min.js +1 -1
- package/package.json +25 -10
- package/src/index.cjs +7 -152
- package/src/index.mjs +2 -147
- package/src/parse-arazzo.cjs +195 -0
- package/src/parse-arazzo.mjs +188 -0
- package/src/parse-openapi.cjs +234 -0
- package/src/parse-openapi.mjs +227 -0
- package/src/resolve/resolvers/memory/index.cjs +29 -0
- package/src/resolve/resolvers/memory/index.mjs +25 -0
- package/types/arazzo-parser.d.ts +43 -30
- package/dist/937fc7a248317278ae14.wasm +0 -0
package/README.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
`@jentic/arazzo-parser` is a parser for [Arazzo Specification](https://spec.openapis.org/arazzo/latest.html) documents.
|
|
4
4
|
It produces [SpecLynx ApiDOM](https://github.com/speclynx/apidom) data model using the [Arazzo 1.x namespace](https://github.com/speclynx/apidom/tree/main/packages/apidom-ns-arazzo-1#readme).
|
|
5
5
|
|
|
6
|
+
**Supported Arazzo versions:**
|
|
7
|
+
- [Arazzo 1.0.0](https://spec.openapis.org/arazzo/v1.0.0)
|
|
8
|
+
- [Arazzo 1.0.1](https://spec.openapis.org/arazzo/v1.0.1)
|
|
9
|
+
|
|
10
|
+
**Supported OpenAPI versions (for source descriptions):**
|
|
11
|
+
- [OpenAPI 2.0](https://spec.openapis.org/oas/v2.0)
|
|
12
|
+
- [OpenAPI 3.0.x](https://spec.openapis.org/oas/v3.0.4)
|
|
13
|
+
- [OpenAPI 3.1.x](https://spec.openapis.org/oas/v3.1.2)
|
|
14
|
+
|
|
6
15
|
## Installation
|
|
7
16
|
|
|
8
17
|
You can install this package via [npm](https://npmjs.org/) CLI by running the following command:
|
|
@@ -13,17 +22,21 @@ npm install @jentic/arazzo-parser
|
|
|
13
22
|
|
|
14
23
|
## Usage
|
|
15
24
|
|
|
16
|
-
`@jentic/arazzo-parser` provides a
|
|
25
|
+
`@jentic/arazzo-parser` provides a `parseArazzo` function for parsing Arazzo documents.
|
|
26
|
+
|
|
27
|
+
## Parsing Arazzo Documents
|
|
17
28
|
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
The `parseArazzo` function accepts multiple input types:
|
|
30
|
+
|
|
31
|
+
1. **Plain JavaScript object** - converts to JSON and parses (source maps supported with `strict: false`)
|
|
32
|
+
2. **String content** - detects Arazzo content and parses inline JSON or YAML
|
|
20
33
|
3. **File system path** - resolves and parses local Arazzo Documents
|
|
21
34
|
4. **HTTP(S) URL** - fetches and parses remote Arazzo Documents
|
|
22
35
|
|
|
23
|
-
###
|
|
36
|
+
### From object
|
|
24
37
|
|
|
25
38
|
```js
|
|
26
|
-
import {
|
|
39
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
27
40
|
|
|
28
41
|
const arazzoDocument = {
|
|
29
42
|
arazzo: '1.0.1',
|
|
@@ -41,20 +54,20 @@ const arazzoDocument = {
|
|
|
41
54
|
workflows: [],
|
|
42
55
|
};
|
|
43
56
|
|
|
44
|
-
const parseResult = await
|
|
57
|
+
const parseResult = await parseArazzo(arazzoDocument);
|
|
45
58
|
// parseResult is ParseResultElement containing ArazzoSpecification1Element
|
|
46
59
|
```
|
|
47
60
|
|
|
48
|
-
###
|
|
61
|
+
### From string
|
|
49
62
|
|
|
50
63
|
```js
|
|
51
|
-
import {
|
|
64
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
52
65
|
|
|
53
66
|
// JSON string
|
|
54
|
-
const parseResult = await
|
|
67
|
+
const parseResult = await parseArazzo('{"arazzo": "1.0.1", "info": {...}}');
|
|
55
68
|
|
|
56
69
|
// YAML string
|
|
57
|
-
const parseResult = await
|
|
70
|
+
const parseResult = await parseArazzo(`
|
|
58
71
|
arazzo: '1.0.1'
|
|
59
72
|
info:
|
|
60
73
|
title: My API Workflow
|
|
@@ -62,55 +75,63 @@ info:
|
|
|
62
75
|
`);
|
|
63
76
|
```
|
|
64
77
|
|
|
65
|
-
###
|
|
78
|
+
### From file
|
|
66
79
|
|
|
67
80
|
```js
|
|
68
|
-
import {
|
|
81
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
69
82
|
|
|
70
|
-
const parseResult = await
|
|
83
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json');
|
|
71
84
|
```
|
|
72
85
|
|
|
73
|
-
###
|
|
86
|
+
### From URL
|
|
74
87
|
|
|
75
88
|
```js
|
|
76
|
-
import {
|
|
89
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
77
90
|
|
|
78
|
-
const parseResult = await
|
|
91
|
+
const parseResult = await parseArazzo('https://example.com/arazzo.yaml');
|
|
79
92
|
```
|
|
80
93
|
|
|
81
94
|
## Parse options
|
|
82
95
|
|
|
83
|
-
The `
|
|
96
|
+
The `parseArazzo` function accepts an optional second argument with reference options compatible with [SpecLynx ApiDOM Reference Options](https://github.com/speclynx/apidom/blob/main/packages/apidom-reference/src/options/index.ts):
|
|
84
97
|
|
|
85
98
|
```js
|
|
86
|
-
import {
|
|
87
|
-
|
|
88
|
-
const parseResult = await
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
99
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
100
|
+
|
|
101
|
+
const parseResult = await parseArazzo(source, {
|
|
102
|
+
parse: {
|
|
103
|
+
parserOpts: {
|
|
104
|
+
strict: true, // Use strict parsing mode (default: true)
|
|
105
|
+
sourceMap: false, // Include source maps (default: false)
|
|
106
|
+
style: false, // Capture style information for round-trip preservation (default: false)
|
|
107
|
+
},
|
|
108
|
+
},
|
|
93
109
|
});
|
|
94
110
|
```
|
|
95
111
|
|
|
96
|
-
### Options
|
|
97
|
-
|
|
98
|
-
| Option | Type | Default | Description |
|
|
99
|
-
|--------|------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
100
|
-
| `strict` | `boolean` | `true` | Whether to enforce strict parsing mode. Strict mode uses native JSON and YAML parsers without error recovery. |
|
|
101
|
-
| `sourceMap` | `boolean` | `false` | Whether to include [source maps](https://github.com/speclynx/apidom/blob/main/packages/apidom-datamodel/README.md#source-maps) in the parsed result. |
|
|
102
|
-
| `parserOpts` | `Record<string, unknown>` | `{}` | Additional options passed to the underlying parsers. |
|
|
103
|
-
| `resolverOpts` | `Record<string, unknown>` | `{}` | Additional options passed to the underlying resolvers. |
|
|
104
|
-
|
|
105
112
|
### Default options
|
|
106
113
|
|
|
107
114
|
You can import the default options:
|
|
108
115
|
|
|
109
116
|
```js
|
|
110
|
-
import {
|
|
111
|
-
|
|
112
|
-
console.log(
|
|
113
|
-
// {
|
|
117
|
+
import { defaultOptions } from '@jentic/arazzo-parser';
|
|
118
|
+
|
|
119
|
+
console.log(defaultOptions);
|
|
120
|
+
// {
|
|
121
|
+
// parse: {
|
|
122
|
+
// parsers: [
|
|
123
|
+
// ArazzoJSON1Parser, ArazzoYAML1Parser,
|
|
124
|
+
// OpenApiJSON2Parser, OpenApiYAML2Parser,
|
|
125
|
+
// OpenApiJSON3_0Parser, OpenApiYAML3_0Parser,
|
|
126
|
+
// OpenApiJSON3_1Parser, OpenApiYAML3_1Parser,
|
|
127
|
+
// ],
|
|
128
|
+
// parserOpts: { sourceMap: false, strict: true, sourceDescriptions: false },
|
|
129
|
+
// },
|
|
130
|
+
// resolve: {
|
|
131
|
+
// resolvers: [MemoryResolver, FileResolver, HTTPResolverAxios],
|
|
132
|
+
// resolverOpts: {},
|
|
133
|
+
// },
|
|
134
|
+
// }
|
|
114
135
|
```
|
|
115
136
|
|
|
116
137
|
## Error handling
|
|
@@ -118,10 +139,10 @@ console.log(defaultParseOptions);
|
|
|
118
139
|
When parsing fails, a `ParseError` is thrown. The original error is available via the `cause` property:
|
|
119
140
|
|
|
120
141
|
```js
|
|
121
|
-
import {
|
|
142
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
122
143
|
|
|
123
144
|
try {
|
|
124
|
-
await
|
|
145
|
+
await parseArazzo('invalid content');
|
|
125
146
|
} catch (error) {
|
|
126
147
|
console.error(error.message); // 'Failed to parse Arazzo Document'
|
|
127
148
|
console.error(error.cause); // Original error from underlying parser
|
|
@@ -130,12 +151,12 @@ try {
|
|
|
130
151
|
|
|
131
152
|
## Working with the result
|
|
132
153
|
|
|
133
|
-
The `
|
|
154
|
+
The `parseArazzo` function returns a [ParseResultElement](https://github.com/speclynx/apidom/blob/main/packages/apidom-datamodel/README.md#parseresultelement) representing the result of the parsing operation.
|
|
134
155
|
|
|
135
156
|
```js
|
|
136
|
-
import {
|
|
157
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
137
158
|
|
|
138
|
-
const parseResult = await
|
|
159
|
+
const parseResult = await parseArazzo(source);
|
|
139
160
|
|
|
140
161
|
// Access the main Arazzo specification element
|
|
141
162
|
const arazzoSpec = parseResult.api;
|
|
@@ -147,6 +168,387 @@ const hasErrors = parseResult.errors.length > 0;
|
|
|
147
168
|
const isEmpty = parseResult.isEmpty;
|
|
148
169
|
```
|
|
149
170
|
|
|
171
|
+
### Retrieval URI metadata
|
|
172
|
+
|
|
173
|
+
When parsing from a file system path or HTTP(S) URL, the `retrievalURI` metadata is set on the parse result:
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
177
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
178
|
+
|
|
179
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json');
|
|
180
|
+
|
|
181
|
+
// Get the URI from which the document was retrieved
|
|
182
|
+
const uri = toValue(parseResult.meta.get('retrievalURI'));
|
|
183
|
+
// '/path/to/arazzo.json'
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Note: `retrievalURI` is not set when parsing from inline content (string) or plain objects.
|
|
187
|
+
|
|
188
|
+
### Source maps
|
|
189
|
+
|
|
190
|
+
Source maps allow you to track the original position (line, column) of each element in the parsed document. This is useful for error reporting, IDE integrations, linting, and any tooling that needs to show precise locations in the original source.
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
To enable source maps, set `sourceMap: true` and `strict: false` in the parser options:
|
|
194
|
+
|
|
195
|
+
```js
|
|
196
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
197
|
+
|
|
198
|
+
const parseResult = await parseArazzo('/path/to/arazzo.yaml', {
|
|
199
|
+
parse: {
|
|
200
|
+
parserOpts: {
|
|
201
|
+
sourceMap: true,
|
|
202
|
+
strict: false,
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
When source maps are enabled, each element in the parsed result contains positional properties stored directly on the element. Position values use UTF-16 code units for compatibility with Language Server Protocol (LSP) and JavaScript string indexing:
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
212
|
+
|
|
213
|
+
const parseResult = await parseArazzo('/path/to/arazzo.yaml', {
|
|
214
|
+
parse: { parserOpts: { sourceMap: true, strict: false } },
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const arazzoSpec = parseResult.api;
|
|
218
|
+
|
|
219
|
+
// Access source map properties directly on the element
|
|
220
|
+
arazzoSpec.startLine; // 0-based line number where element begins
|
|
221
|
+
arazzoSpec.startCharacter; // 0-based column number where element begins
|
|
222
|
+
arazzoSpec.startOffset; // 0-based character offset from document start
|
|
223
|
+
arazzoSpec.endLine; // 0-based line number where element ends
|
|
224
|
+
arazzoSpec.endCharacter; // 0-based column number where element ends
|
|
225
|
+
arazzoSpec.endOffset; // 0-based character offset where element ends
|
|
226
|
+
|
|
227
|
+
// Access source map on nested elements
|
|
228
|
+
const workflow = arazzoSpec.workflows.get(0);
|
|
229
|
+
console.log(`Workflow starts at line ${workflow.startLine}, column ${workflow.startCharacter}`);
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
For more details about source maps, see the [SpecLynx ApiDOM Data Model documentation](https://github.com/speclynx/apidom/tree/main/packages/apidom-datamodel#source-maps).
|
|
233
|
+
|
|
234
|
+
**Note:** Source maps require `strict: false` to be set. When parsing from objects, they are converted to pretty-printed JSON strings internally (2-space indentation), so source map positions refer to this generated JSON representation, not the original object structure:
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
// Source maps with objects (requires strict: false)
|
|
238
|
+
// Positions will reference the internally generated JSON string
|
|
239
|
+
await parseArazzo({ arazzo: '1.0.1', ... }, {
|
|
240
|
+
parse: {
|
|
241
|
+
parserOpts: {
|
|
242
|
+
sourceMap: true,
|
|
243
|
+
strict: false
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Style preservation
|
|
250
|
+
|
|
251
|
+
Style preservation captures format-specific style information for round-trip preservation. When enabled, the parser records formatting details (e.g., YAML quoting styles, flow/block indicators, comments, indentation; JSON indentation, raw number representation) on each parsed element. These details can then be used by [`toYAML`](https://github.com/speclynx/apidom/tree/main/packages/apidom-core#toyaml) and [`toJSON`](https://github.com/speclynx/apidom/tree/main/packages/apidom-core#tojson) from `@speclynx/apidom-core` to reproduce the original formatting.
|
|
252
|
+
|
|
253
|
+
To enable style preservation, set `style: true` and `strict: false` in the parser options:
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
257
|
+
import { toYAML } from '@speclynx/apidom-core';
|
|
258
|
+
|
|
259
|
+
const parseResult = await parseArazzo('/path/to/arazzo.yaml', {
|
|
260
|
+
parse: {
|
|
261
|
+
parserOpts: {
|
|
262
|
+
style: true,
|
|
263
|
+
strict: false,
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
// round-trip back to YAML preserving original formatting
|
|
269
|
+
const yaml = toYAML(parseResult.api, { preserveStyle: true });
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
274
|
+
import { toJSON } from '@speclynx/apidom-core';
|
|
275
|
+
|
|
276
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json', {
|
|
277
|
+
parse: {
|
|
278
|
+
parserOpts: {
|
|
279
|
+
style: true,
|
|
280
|
+
strict: false,
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// round-trip back to JSON preserving original formatting
|
|
286
|
+
const json = toJSON(parseResult.api, undefined, undefined, { preserveStyle: true });
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
**Note:** Style preservation requires `strict: false`. Both `style` and `sourceMap` can be enabled simultaneously — they are independent features.
|
|
290
|
+
|
|
291
|
+
## Parsing source descriptions
|
|
292
|
+
|
|
293
|
+
Arazzo documents can reference external API specifications (OpenAPI, Arazzo) through [Source Descriptions](https://spec.openapis.org/arazzo/latest.html#source-description-object). The parser can automatically fetch and parse these referenced documents.
|
|
294
|
+
|
|
295
|
+
**Note:** Source descriptions parsing is disabled by default for performance reasons. Enable it explicitly when you need to resolve and parse referenced API specifications.
|
|
296
|
+
|
|
297
|
+
### Enabling source descriptions parsing
|
|
298
|
+
|
|
299
|
+
To parse source descriptions, enable the `sourceDescriptions` option in `parserOpts`:
|
|
300
|
+
|
|
301
|
+
```js
|
|
302
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
303
|
+
|
|
304
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json', {
|
|
305
|
+
parse: {
|
|
306
|
+
parserOpts: {
|
|
307
|
+
sourceDescriptions: true,
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Alternatively, you can configure it per parser for more granular control:
|
|
314
|
+
|
|
315
|
+
```js
|
|
316
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json', {
|
|
317
|
+
parse: {
|
|
318
|
+
parserOpts: {
|
|
319
|
+
'arazzo-json-1': { sourceDescriptions: true },
|
|
320
|
+
'arazzo-yaml-1': { sourceDescriptions: true },
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
});
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Selective parsing
|
|
327
|
+
|
|
328
|
+
You can selectively parse only specific source descriptions by providing an array of names:
|
|
329
|
+
|
|
330
|
+
```js
|
|
331
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json', {
|
|
332
|
+
parse: {
|
|
333
|
+
parserOpts: {
|
|
334
|
+
sourceDescriptions: ['petStoreApi', 'paymentApi'],
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Result structure
|
|
341
|
+
|
|
342
|
+
When source descriptions are parsed, each parsed document that is a *direct* source description of the main Arazzo document is added to the main `ParseResultElement` as an additional top-level element. The first element is always the main Arazzo document, and subsequent top-level elements are these directly parsed source descriptions. When recursive parsing discovers further source descriptions from within an already parsed source description, those recursively parsed documents are attached as nested `ParseResultElement` instances beneath the source-description element that referenced them (they are not duplicated at the top level). Consumers that need to see all documents should traverse both the top-level elements and any nested `ParseResultElement`s reachable from source-description elements.
|
|
343
|
+
|
|
344
|
+
Source descriptions are parsed into their appropriate SpecLynx ApiDOM namespace data models based on document type:
|
|
345
|
+
|
|
346
|
+
- [Arazzo 1.x](https://spec.openapis.org/arazzo/latest.html) → [@speclynx/apidom-ns-arazzo-1](https://github.com/speclynx/apidom/tree/main/packages/apidom-ns-arazzo-1)
|
|
347
|
+
- [OpenAPI 2.0 (Swagger)](https://spec.openapis.org/oas/v2.0) → [@speclynx/apidom-ns-openapi-2](https://github.com/speclynx/apidom/tree/main/packages/apidom-ns-openapi-2)
|
|
348
|
+
- [OpenAPI 3.0.x](https://spec.openapis.org/oas/v3.0.4) → [@speclynx/apidom-ns-openapi-3-0](https://github.com/speclynx/apidom/tree/main/packages/apidom-ns-openapi-3-0)
|
|
349
|
+
- [OpenAPI 3.1.x](https://spec.openapis.org/oas/v3.1.2) → [@speclynx/apidom-ns-openapi-3-1](https://github.com/speclynx/apidom/tree/main/packages/apidom-ns-openapi-3-1)
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
ParseResultElement
|
|
353
|
+
├── .api: ArazzoSpecification1Element
|
|
354
|
+
│
|
|
355
|
+
├── ParseResultElement (petStoreApi) ─┐
|
|
356
|
+
│ └── .api: OpenApi3_1Element │ source
|
|
357
|
+
│ │ descriptions
|
|
358
|
+
└── ParseResultElement (legacyApi) ─┘
|
|
359
|
+
├── .errors
|
|
360
|
+
└── .warnings
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
```js
|
|
364
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
365
|
+
|
|
366
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json', {
|
|
367
|
+
parse: {
|
|
368
|
+
parserOpts: {
|
|
369
|
+
sourceDescriptions: true,
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// Main Arazzo document
|
|
375
|
+
const arazzoSpec = parseResult.api;
|
|
376
|
+
|
|
377
|
+
// Number of elements (1 main + N source descriptions)
|
|
378
|
+
console.log(parseResult.length);
|
|
379
|
+
|
|
380
|
+
// Access parsed source descriptions (filter by 'source-description' class)
|
|
381
|
+
for (let i = 0; i < parseResult.length; i++) {
|
|
382
|
+
const element = parseResult.get(i);
|
|
383
|
+
|
|
384
|
+
if (element.classes.includes('source-description')) {
|
|
385
|
+
// Source description metadata
|
|
386
|
+
const name = element.meta.get('name')?.toValue();
|
|
387
|
+
const type = element.meta.get('type')?.toValue();
|
|
388
|
+
|
|
389
|
+
console.log(`Source description "${name}" (${type})`);
|
|
390
|
+
|
|
391
|
+
// The parsed API document
|
|
392
|
+
const api = element.api;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Accessing via SourceDescriptionElement
|
|
398
|
+
|
|
399
|
+
An alternative way to access parsed source descriptions is through the `SourceDescriptionElement` metadata.
|
|
400
|
+
When source descriptions are parsed, a `ParseResultElement` is attached to each `SourceDescriptionElement`'s metadata under the key `'parseResult'`.
|
|
401
|
+
|
|
402
|
+
```js
|
|
403
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
404
|
+
import { toValue } from '@speclynx/apidom-core';
|
|
405
|
+
|
|
406
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json', {
|
|
407
|
+
parse: {
|
|
408
|
+
parserOpts: {
|
|
409
|
+
sourceDescriptions: true,
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
const arazzoSpec = parseResult.api;
|
|
415
|
+
|
|
416
|
+
// Access parsed document via SourceDescriptionElement
|
|
417
|
+
const sourceDesc = arazzoSpec.sourceDescriptions.get(0);
|
|
418
|
+
const sdParseResult = sourceDesc.meta.get('parseResult');
|
|
419
|
+
|
|
420
|
+
// Check for errors before using
|
|
421
|
+
if (sdParseResult.errors.length === 0) {
|
|
422
|
+
// Access the parsed API
|
|
423
|
+
const api = sdParseResult.api;
|
|
424
|
+
console.log(`API type: ${api.element}`); // e.g., 'openApi3_1'
|
|
425
|
+
|
|
426
|
+
// Get the retrieval URI
|
|
427
|
+
const retrievalURI = toValue(sdParseResult.meta.get('retrievalURI'));
|
|
428
|
+
console.log(`Loaded from: ${retrievalURI}`);
|
|
429
|
+
}
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
This approach is useful when you need to:
|
|
433
|
+
- Access a specific source description by its position in the `sourceDescriptions` array
|
|
434
|
+
- Get the `retrievalURI` metadata indicating where the document was fetched from
|
|
435
|
+
- Correlate parsed documents with their source description definitions
|
|
436
|
+
|
|
437
|
+
### Recursive parsing
|
|
438
|
+
|
|
439
|
+
When a source description is of type `arazzo`, the parser recursively parses that document's source descriptions as well. This allows you to parse entire dependency trees of Arazzo documents.
|
|
440
|
+
|
|
441
|
+
### Limiting recursion depth
|
|
442
|
+
|
|
443
|
+
To prevent excessive recursion or handle deeply nested documents, use the `sourceDescriptionsMaxDepth` option:
|
|
444
|
+
|
|
445
|
+
```js
|
|
446
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json', {
|
|
447
|
+
parse: {
|
|
448
|
+
parserOpts: {
|
|
449
|
+
sourceDescriptions: true,
|
|
450
|
+
sourceDescriptionsMaxDepth: 2, // Only parse 2 levels deep
|
|
451
|
+
},
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
The default value is `+Infinity` (no limit). Setting it to `0` will create error annotations instead of parsing any source descriptions.
|
|
457
|
+
|
|
458
|
+
### Cycle detection
|
|
459
|
+
|
|
460
|
+
The parser automatically detects circular references between Arazzo documents. When a cycle is detected, a warning annotation is added instead of causing infinite recursion:
|
|
461
|
+
|
|
462
|
+
```js
|
|
463
|
+
// arazzo-a.json references arazzo-b.json
|
|
464
|
+
// arazzo-b.json references arazzo-a.json (cycle!)
|
|
465
|
+
|
|
466
|
+
const parseResult = await parseArazzo('/path/to/arazzo-a.json', {
|
|
467
|
+
parse: {
|
|
468
|
+
parserOpts: {
|
|
469
|
+
sourceDescriptions: true,
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
// The cycle is handled gracefully - check for warning annotations
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### Error and warning handling
|
|
478
|
+
|
|
479
|
+
When issues occur during source description parsing, the parser does not throw errors. Instead, it adds annotation elements to the source description's parse result:
|
|
480
|
+
|
|
481
|
+
- **`error`** class - Parsing failed (e.g., file not found, invalid document, max depth exceeded)
|
|
482
|
+
- **`warning`** class - Non-fatal issues (e.g., cycle detected, type mismatch between declared and actual)
|
|
483
|
+
|
|
484
|
+
This allows partial parsing to succeed even if some source descriptions have issues:
|
|
485
|
+
|
|
486
|
+
```js
|
|
487
|
+
const parseResult = await parseArazzo('/path/to/arazzo.json', {
|
|
488
|
+
parse: {
|
|
489
|
+
parserOpts: {
|
|
490
|
+
sourceDescriptions: true,
|
|
491
|
+
},
|
|
492
|
+
},
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
// Check each source description for errors and warnings
|
|
496
|
+
for (let i = 0; i < parseResult.length; i++) {
|
|
497
|
+
const element = parseResult.get(i);
|
|
498
|
+
|
|
499
|
+
if (element.classes.includes('source-description')) {
|
|
500
|
+
const name = element.meta.get('name')?.toValue();
|
|
501
|
+
|
|
502
|
+
// Use built-in accessors for errors and warnings
|
|
503
|
+
element.errors.forEach((error) => {
|
|
504
|
+
console.error(`Error in "${name}": ${error.toValue()}`);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
element.warnings.forEach((warning) => {
|
|
508
|
+
console.warn(`Warning in "${name}": ${warning.toValue()}`);
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
## Parsing OpenAPI Documents
|
|
515
|
+
|
|
516
|
+
The `parseOpenAPI` function provides complete control for parsing OpenAPI documents manually.
|
|
517
|
+
This is useful when you need to parse source descriptions independently or implement custom source description resolution logic.
|
|
518
|
+
|
|
519
|
+
The function accepts the same input types as `parseArazzo`:
|
|
520
|
+
|
|
521
|
+
1. **Plain JavaScript object** - converts to JSON and parses
|
|
522
|
+
2. **String content** - detects OpenAPI content and parses inline JSON or YAML
|
|
523
|
+
3. **File system path** - resolves and parses local OpenAPI Documents
|
|
524
|
+
4. **HTTP(S) URL** - fetches and parses remote OpenAPI Documents
|
|
525
|
+
|
|
526
|
+
Documents are parsed into their appropriate SpecLynx ApiDOM namespace data models:
|
|
527
|
+
|
|
528
|
+
- [OpenAPI 2.0 (Swagger)](https://spec.openapis.org/oas/v2.0) → [@speclynx/apidom-ns-openapi-2](https://github.com/speclynx/apidom/tree/main/packages/apidom-ns-openapi-2)
|
|
529
|
+
- [OpenAPI 3.0.x](https://spec.openapis.org/oas/v3.0.4) → [@speclynx/apidom-ns-openapi-3-0](https://github.com/speclynx/apidom/tree/main/packages/apidom-ns-openapi-3-0)
|
|
530
|
+
- [OpenAPI 3.1.x](https://spec.openapis.org/oas/v3.1.2) → [@speclynx/apidom-ns-openapi-3-1](https://github.com/speclynx/apidom/tree/main/packages/apidom-ns-openapi-3-1)
|
|
531
|
+
|
|
532
|
+
```js
|
|
533
|
+
import { parseOpenAPI } from '@jentic/arazzo-parser';
|
|
534
|
+
|
|
535
|
+
// From object
|
|
536
|
+
const parseResult = await parseOpenAPI({
|
|
537
|
+
openapi: '3.1.0',
|
|
538
|
+
info: { title: 'My API', version: '1.0.0' },
|
|
539
|
+
paths: {},
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
// From string
|
|
543
|
+
const parseResult = await parseOpenAPI('{"openapi": "3.1.0", ...}');
|
|
544
|
+
|
|
545
|
+
// From file
|
|
546
|
+
const parseResult = await parseOpenAPI('/path/to/openapi.json');
|
|
547
|
+
|
|
548
|
+
// From URL
|
|
549
|
+
const parseResult = await parseOpenAPI('https://example.com/openapi.yaml');
|
|
550
|
+
```
|
|
551
|
+
|
|
150
552
|
## SpecLynx ApiDOM tooling
|
|
151
553
|
|
|
152
554
|
Since `@jentic/arazzo-parser` produces a SpecLynx ApiDOM data model, you have access to the full suite of ApiDOM tools for manipulating, traversing, and transforming the parsed document.
|
|
@@ -156,10 +558,11 @@ Since `@jentic/arazzo-parser` produces a SpecLynx ApiDOM data model, you have ac
|
|
|
156
558
|
The [@speclynx/apidom-core](https://github.com/speclynx/apidom/tree/main/packages/apidom-core) package provides essential utilities for working with ApiDOM elements. Here are just a few examples:
|
|
157
559
|
|
|
158
560
|
```js
|
|
159
|
-
import {
|
|
160
|
-
import {
|
|
561
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
562
|
+
import { cloneDeep, cloneShallow } from '@speclynx/apidom-datamodel';
|
|
563
|
+
import { toValue, toJSON, toYAML, sexprs } from '@speclynx/apidom-core';
|
|
161
564
|
|
|
162
|
-
const parseResult = await
|
|
565
|
+
const parseResult = await parseArazzo(source);
|
|
163
566
|
const arazzoSpec = parseResult.api;
|
|
164
567
|
|
|
165
568
|
// Convert to plain JavaScript object
|
|
@@ -171,8 +574,9 @@ const json = toJSON(arazzoSpec);
|
|
|
171
574
|
// Serialize to YAML string
|
|
172
575
|
const yaml = toYAML(arazzoSpec);
|
|
173
576
|
|
|
174
|
-
//
|
|
175
|
-
const
|
|
577
|
+
// Clone the element
|
|
578
|
+
const clonedShallow = cloneShallow(arazzoSpec);
|
|
579
|
+
const clonedDeep = cloneDeep(arazzoSpec);
|
|
176
580
|
|
|
177
581
|
// Get S-expression representation (useful for debugging)
|
|
178
582
|
const sexpr = sexprs(arazzoSpec);
|
|
@@ -183,10 +587,10 @@ const sexpr = sexprs(arazzoSpec);
|
|
|
183
587
|
The [@speclynx/apidom-traverse](https://github.com/speclynx/apidom/tree/main/packages/apidom-traverse) package provides powerful traversal capabilities. Here is a basic example:
|
|
184
588
|
|
|
185
589
|
```js
|
|
186
|
-
import {
|
|
590
|
+
import { parseArazzo } from '@jentic/arazzo-parser';
|
|
187
591
|
import { traverse } from '@speclynx/apidom-traverse';
|
|
188
592
|
|
|
189
|
-
const parseResult = await
|
|
593
|
+
const parseResult = await parseArazzo(source);
|
|
190
594
|
|
|
191
595
|
// Traverse and collect steps using semantic visitor hook
|
|
192
596
|
const steps = [];
|