@usearazzo/parser 1.0.1-alpha.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/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@usearazzo/parser",
3
+ "version": "1.0.1-alpha.0",
4
+ "description": "Parser for the Arazzo Specification language: documents, runtime expressions, and criterion conditions.",
5
+ "keywords": [
6
+ "arazzo",
7
+ "arazzo-specification",
8
+ "parser",
9
+ "datamodel",
10
+ "workflow",
11
+ "workflows",
12
+ "runtime-expression",
13
+ "criterion"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public",
17
+ "registry": "https://registry.npmjs.org",
18
+ "provenance": false,
19
+ "tag": "latest"
20
+ },
21
+ "type": "module",
22
+ "sideEffects": false,
23
+ "engines": {
24
+ "node": ">=20.10.0"
25
+ },
26
+ "unpkg": "./dist/arazzo-parser.browser.min.js",
27
+ "main": "./src/index.cjs",
28
+ "exports": {
29
+ "types": "./types/parser.d.ts",
30
+ "import": "./src/index.mjs",
31
+ "require": "./src/index.cjs"
32
+ },
33
+ "types": "./types/parser.d.ts",
34
+ "scripts": {
35
+ "build": "npm run clean && run-p --max-parallel ${CPU_CORES:-2} typescript:declaration build:es build:cjs build:umd:browser",
36
+ "build:es": "cross-env BABEL_ENV=es babel src --out-dir src --extensions '.ts' --out-file-extension '.mjs' --root-mode 'upward'",
37
+ "build:cjs": "cross-env BABEL_ENV=cjs babel src --out-dir src --extensions '.ts' --out-file-extension '.cjs' --root-mode 'upward'",
38
+ "build:umd:browser": "cross-env BABEL_ENV=browser webpack --config config/webpack/browser.config.js --progress",
39
+ "lint": "eslint ./",
40
+ "lint:fix": "eslint ./ --fix",
41
+ "clean": "rimraf --glob 'src/**/*.mjs' 'src/**/*.cjs' 'test/**/*.mjs' ./dist ./types",
42
+ "typescript:check-types": "tsc --noEmit",
43
+ "typescript:declaration": "tsc -p tsconfig.declaration.json && api-extractor run -l -c ./config/api-extractor/api-extractor.json",
44
+ "test": "npm run build:es && cross-env BABEL_ENV=es babel test --out-dir test --extensions '.ts' --out-file-extension '.mjs' --root-mode 'upward' && cross-env NODE_ENV=test mocha",
45
+ "prepack": "copyfiles -u 2 ../../LICENSE . && copyfiles -u 2 ../../NOTICE .",
46
+ "postpack": "rimraf NOTICE LICENSE"
47
+ },
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "git+https://github.com/usearazzo/arazzo-toolkit.git"
51
+ },
52
+ "author": "Vladimir Gorej <vladimir.gorej@gmail.com>",
53
+ "license": "Apache-2.0",
54
+ "dependencies": {
55
+ "@babel/runtime-corejs3": "^8.0.0",
56
+ "@speclynx/apidom-datamodel": "^5.2.2",
57
+ "@speclynx/apidom-error": "^5.2.2",
58
+ "@speclynx/apidom-ns-arazzo-1": "^5.2.2",
59
+ "@speclynx/apidom-parser-adapter-arazzo-json-1": "^5.2.2",
60
+ "@speclynx/apidom-parser-adapter-arazzo-yaml-1": "^5.2.2",
61
+ "@speclynx/apidom-parser-adapter-openapi-json-2": "^5.2.2",
62
+ "@speclynx/apidom-parser-adapter-openapi-json-3-0": "^5.2.2",
63
+ "@speclynx/apidom-parser-adapter-openapi-json-3-1": "^5.2.2",
64
+ "@speclynx/apidom-parser-adapter-openapi-yaml-2": "^5.2.2",
65
+ "@speclynx/apidom-parser-adapter-openapi-yaml-3-0": "^5.2.2",
66
+ "@speclynx/apidom-parser-adapter-openapi-yaml-3-1": "^5.2.2",
67
+ "@speclynx/apidom-reference": "^5.2.2",
68
+ "@swaggerexpert/arazzo-criterion": "^1.0.1",
69
+ "@swaggerexpert/arazzo-runtime-expression": "^3.2.0",
70
+ "ramda-adjunct": "^6.0.0",
71
+ "type-fest": "^5.4.4"
72
+ },
73
+ "devDependencies": {
74
+ "@speclynx/apidom-core": "^5.2.2"
75
+ },
76
+ "files": [
77
+ "src/**/*.mjs",
78
+ "src/**/*.cjs",
79
+ "dist/",
80
+ "types/parser.d.ts",
81
+ "LICENSE",
82
+ "NOTICE",
83
+ "README.md",
84
+ "CHANGELOG.md"
85
+ ]
86
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _apidomError = require("@speclynx/apidom-error");
8
+ /**
9
+ * Error thrown by `parseArazzo` and `parseOpenAPI` when parsing fails for any
10
+ * reason. The original error is available via the `cause` property.
11
+ * @public
12
+ */
13
+ class ParseError extends _apidomError.ApiDOMError {
14
+ constructor(message, options) {
15
+ super(message, options);
16
+ }
17
+ }
18
+ var _default = exports.default = ParseError;
@@ -0,0 +1,13 @@
1
+ import { ApiDOMError } from '@speclynx/apidom-error';
2
+
3
+ /**
4
+ * Error thrown by `parseArazzo` and `parseOpenAPI` when parsing fails for any
5
+ * reason. The original error is available via the `cause` property.
6
+ * @public
7
+ */
8
+ class ParseError extends ApiDOMError {
9
+ constructor(message, options) {
10
+ super(message, options);
11
+ }
12
+ }
13
+ export default ParseError;
package/src/index.cjs ADDED
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ Object.defineProperty(exports, "ArazzoCriterionParseError", {
8
+ enumerable: true,
9
+ get: function () {
10
+ return _parseCriterionCondition.ArazzoCriterionParseError;
11
+ }
12
+ });
13
+ Object.defineProperty(exports, "ArazzoRuntimeExpressionParseError", {
14
+ enumerable: true,
15
+ get: function () {
16
+ return _parseRuntimeExpression.ArazzoRuntimeExpressionParseError;
17
+ }
18
+ });
19
+ Object.defineProperty(exports, "ParseError", {
20
+ enumerable: true,
21
+ get: function () {
22
+ return _ParseError.default;
23
+ }
24
+ });
25
+ Object.defineProperty(exports, "defaultParseArazzoOptions", {
26
+ enumerable: true,
27
+ get: function () {
28
+ return _parseArazzo.defaultOptions;
29
+ }
30
+ });
31
+ Object.defineProperty(exports, "defaultParseCriterionConditionOptions", {
32
+ enumerable: true,
33
+ get: function () {
34
+ return _parseCriterionCondition.defaultOptions;
35
+ }
36
+ });
37
+ Object.defineProperty(exports, "defaultParseOpenAPIOptions", {
38
+ enumerable: true,
39
+ get: function () {
40
+ return _parseOpenapi.defaultOptions;
41
+ }
42
+ });
43
+ Object.defineProperty(exports, "defaultParseRuntimeExpressionOptions", {
44
+ enumerable: true,
45
+ get: function () {
46
+ return _parseRuntimeExpression.defaultOptions;
47
+ }
48
+ });
49
+ Object.defineProperty(exports, "parseArazzo", {
50
+ enumerable: true,
51
+ get: function () {
52
+ return _parseArazzo.parse;
53
+ }
54
+ });
55
+ Object.defineProperty(exports, "parseCriterionCondition", {
56
+ enumerable: true,
57
+ get: function () {
58
+ return _parseCriterionCondition.parse;
59
+ }
60
+ });
61
+ Object.defineProperty(exports, "parseOpenAPI", {
62
+ enumerable: true,
63
+ get: function () {
64
+ return _parseOpenapi.parse;
65
+ }
66
+ });
67
+ Object.defineProperty(exports, "parseRuntimeExpression", {
68
+ enumerable: true,
69
+ get: function () {
70
+ return _parseRuntimeExpression.parse;
71
+ }
72
+ });
73
+ var _ParseError = _interopRequireDefault(require("./errors/ParseError.cjs"));
74
+ var _parseArazzo = require("./parse-arazzo.cjs");
75
+ var _parseOpenapi = require("./parse-openapi.cjs");
76
+ var _parseRuntimeExpression = require("./parse-runtime-expression.cjs");
77
+ var _parseCriterionCondition = require("./parse-criterion-condition.cjs");
package/src/index.mjs ADDED
@@ -0,0 +1,5 @@
1
+ export { default as ParseError } from "./errors/ParseError.mjs";
2
+ export { parse as parseArazzo, defaultOptions as defaultParseArazzoOptions } from "./parse-arazzo.mjs";
3
+ export { parse as parseOpenAPI, defaultOptions as defaultParseOpenAPIOptions } from "./parse-openapi.mjs";
4
+ export { parse as parseRuntimeExpression, defaultOptions as defaultParseRuntimeExpressionOptions, ArazzoRuntimeExpressionParseError } from "./parse-runtime-expression.mjs";
5
+ export { parse as parseCriterionCondition, defaultOptions as defaultParseCriterionConditionOptions, ArazzoCriterionParseError } from "./parse-criterion-condition.mjs";
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.mergeOptions = void 0;
7
+ var _empty = require("@speclynx/apidom-reference/configuration/empty");
8
+ const isMemoryResolver = resolver => resolver.name === 'memory';
9
+
10
+ /**
11
+ * Merges reference options the same way apidom-reference does, additionally keeping
12
+ * memory resolvers ahead of every other resolver: they serve in-memory documents and
13
+ * must win over any resolver that could read the same URI from disk or network.
14
+ */
15
+ const mergeOptions = (target, source) => {
16
+ const merged = (0, _empty.mergeOptions)(target, source);
17
+ const {
18
+ resolvers
19
+ } = merged.resolve;
20
+ const memoryResolvers = resolvers.filter(isMemoryResolver);
21
+ if (memoryResolvers.length === 0) return merged;
22
+ return {
23
+ ...merged,
24
+ resolve: {
25
+ ...merged.resolve,
26
+ resolvers: [...memoryResolvers, ...resolvers.filter(r => !isMemoryResolver(r))]
27
+ }
28
+ };
29
+ };
30
+ exports.mergeOptions = mergeOptions;
@@ -0,0 +1,23 @@
1
+ import { mergeOptions as mergeReferenceOptions } from '@speclynx/apidom-reference/configuration/empty';
2
+ const isMemoryResolver = resolver => resolver.name === 'memory';
3
+
4
+ /**
5
+ * Merges reference options the same way apidom-reference does, additionally keeping
6
+ * memory resolvers ahead of every other resolver: they serve in-memory documents and
7
+ * must win over any resolver that could read the same URI from disk or network.
8
+ */
9
+ export const mergeOptions = (target, source) => {
10
+ const merged = mergeReferenceOptions(target, source);
11
+ const {
12
+ resolvers
13
+ } = merged.resolve;
14
+ const memoryResolvers = resolvers.filter(isMemoryResolver);
15
+ if (memoryResolvers.length === 0) return merged;
16
+ return {
17
+ ...merged,
18
+ resolve: {
19
+ ...merged.resolve,
20
+ resolvers: [...memoryResolvers, ...resolvers.filter(r => !isMemoryResolver(r))]
21
+ }
22
+ };
23
+ };
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.defaultOptions = void 0;
8
+ exports.parse = parse;
9
+ var _empty = require("@speclynx/apidom-reference/configuration/empty");
10
+ var _arazzoJson = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/arazzo-json-1"));
11
+ var _arazzoYaml = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/arazzo-yaml-1"));
12
+ var _openapiJson = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-json-2"));
13
+ var _openapiYaml = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-yaml-2"));
14
+ var _openapiJson2 = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-json-3-0"));
15
+ var _openapiYaml2 = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-yaml-3-0"));
16
+ var _openapiJson3 = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-json-3-1"));
17
+ var _openapiYaml3 = _interopRequireDefault(require("@speclynx/apidom-reference/parse/parsers/openapi-yaml-3-1"));
18
+ var _file = _interopRequireDefault(require("@speclynx/apidom-reference/resolve/resolvers/file"));
19
+ var _httpAxios = _interopRequireDefault(require("@speclynx/apidom-reference/resolve/resolvers/http-axios"));
20
+ var _apidomParserAdapterArazzoJson = require("@speclynx/apidom-parser-adapter-arazzo-json-1");
21
+ var _apidomNsArazzo = require("@speclynx/apidom-ns-arazzo-1");
22
+ var _apidomParserAdapterArazzoYaml = require("@speclynx/apidom-parser-adapter-arazzo-yaml-1");
23
+ var _ramdaAdjunct = require("ramda-adjunct");
24
+ var _ParseError = _interopRequireDefault(require("./errors/ParseError.cjs"));
25
+ var _util = require("./options/util.cjs");
26
+ var _index = _interopRequireDefault(require("./resolve/resolvers/memory/index.cjs"));
27
+ /**
28
+ * Options for parsing Arazzo Documents.
29
+ * @public
30
+ */
31
+
32
+ /**
33
+ * Default reference options for parsing Arazzo Documents.
34
+ * @public
35
+ */
36
+ const defaultOptions = exports.defaultOptions = {
37
+ parse: {
38
+ parsers: [new _arazzoJson.default({
39
+ allowEmpty: false
40
+ }), new _arazzoYaml.default({
41
+ allowEmpty: false
42
+ }), new _openapiJson.default({
43
+ allowEmpty: false
44
+ }), new _openapiYaml.default({
45
+ allowEmpty: false
46
+ }), new _openapiJson2.default({
47
+ allowEmpty: false
48
+ }), new _openapiYaml2.default({
49
+ allowEmpty: false
50
+ }), new _openapiJson3.default({
51
+ allowEmpty: false
52
+ }), new _openapiYaml3.default({
53
+ allowEmpty: false
54
+ })],
55
+ parserOpts: {
56
+ sourceMap: false,
57
+ style: false,
58
+ strict: true,
59
+ sourceDescriptions: false
60
+ }
61
+ },
62
+ resolve: {
63
+ resolvers: [
64
+ // regex patterns, not glob strings - picomatch's glob matching never
65
+ // matches a dotfile basename (e.g. .arazzo.yaml) without `dot: true`,
66
+ // which FileResolver does not set.
67
+ new _file.default({
68
+ fileAllowList: [/\.json$/i, /\.ya?ml$/i]
69
+ }), new _httpAxios.default({
70
+ timeout: 15000,
71
+ redirects: 5,
72
+ withCredentials: false
73
+ })],
74
+ resolverOpts: {}
75
+ }
76
+ };
77
+
78
+ /**
79
+ * Parses an Arazzo Document from an object.
80
+ * @param source - The Arazzo Document as a plain object
81
+ * @param options - Reference options (uses defaultOptions when not provided)
82
+ * @returns A promise that resolves to the parsed Arazzo Document as ApiDOM data model
83
+ * @throws ParseError - When parsing fails for any reason. The original error is available via the `cause` property.
84
+ * @public
85
+ */
86
+
87
+ /**
88
+ * Parses an Arazzo Document from a string or URI.
89
+ * @param source - The Arazzo Document as string content, or a file system path / HTTP(S) URL
90
+ * @param options - Reference options (uses defaultOptions when not provided)
91
+ * @returns A promise that resolves to the parsed Arazzo Document as ApiDOM data model
92
+ * @throws ParseError - When parsing fails for any reason. The original error is available via the `cause` property.
93
+ * @public
94
+ */
95
+
96
+ /**
97
+ * Parses an Arazzo Document from a string, object, or URI.
98
+ * @param source - The Arazzo Document as a plain object, string content, or URI
99
+ * @param options - Reference options (uses defaultOptions when not provided)
100
+ * @returns A promise that resolves to the parsed Arazzo Document as ApiDOM data model
101
+ * @throws ParseError - When parsing fails for any reason. The original error is available via the `cause` property.
102
+ * @public
103
+ */
104
+
105
+ /**
106
+ * Parses an Arazzo Document from a string, object, or URI.
107
+ *
108
+ * The function handles three types of input:
109
+ * 1. Object - converts to JSON string and parses (source maps supported with `strict: false`)
110
+ * 2. String content - uses Arazzo detection to identify and parse inline JSON or YAML content
111
+ * 3. URI string - if not detected as Arazzo content, treats as file system path or HTTP(S) URL
112
+ *
113
+ * @param source - The Arazzo Document as an object, string content, or a file system path / HTTP(S) URL
114
+ * @param options - Reference options (uses defaultOptions when not provided)
115
+ * @returns A promise that resolves to the parsed Arazzo Document as ApiDOM data model
116
+ * @throws ParseError - When parsing fails for any reason. The original error is available via the `cause` property.
117
+ *
118
+ * @example
119
+ * Parse from object
120
+ * ```typescript
121
+ * const result = await parseArazzo({ arazzo: '1.0.1', info: {...} });
122
+ * ```
123
+ *
124
+ * @example
125
+ * Parse inline JSON
126
+ * ```typescript
127
+ * const result = await parseArazzo('{"arazzo": "1.0.1", "info": {...}}');
128
+ * ```
129
+ *
130
+ * @example
131
+ * Parse from file
132
+ * ```typescript
133
+ * const result = await parseArazzo('/path/to/arazzo.json');
134
+ * ```
135
+ *
136
+ * @example
137
+ * Parse from URL
138
+ * ```typescript
139
+ * const result = await parseArazzo('https://example.com/arazzo.yaml');
140
+ * ```
141
+ *
142
+ * @example
143
+ * Parse with custom options
144
+ * ```typescript
145
+ * const result = await parseArazzo('/path/to/arazzo.json', customOptions);
146
+ * ```
147
+ * @public
148
+ */
149
+ async function parse(source, options = {}) {
150
+ let mergedOptions = (0, _util.mergeOptions)(defaultOptions, options);
151
+ const strict = mergedOptions.parse?.parserOpts?.strict ?? true;
152
+ let sourceProvenance;
153
+ let document;
154
+ if ((0, _ramdaAdjunct.isPlainObject)(source)) {
155
+ document = JSON.stringify(source, null, 2);
156
+ source = 'memory://arazzo.json';
157
+ sourceProvenance = '[object]';
158
+ } else if (await (0, _apidomParserAdapterArazzoJson.detect)(source, {
159
+ strict
160
+ })) {
161
+ document = source;
162
+ source = 'memory://arazzo.json';
163
+ sourceProvenance = '[inline JSON]';
164
+ } else if (await (0, _apidomParserAdapterArazzoYaml.detect)(source, {
165
+ strict
166
+ })) {
167
+ document = source;
168
+ source = 'memory://arazzo.yaml';
169
+ sourceProvenance = '[inline YAML]';
170
+ } else {
171
+ sourceProvenance = _empty.url.isHttpUrl(source) || _empty.url.getProtocol(source) === 'file' || _empty.url.isURI(`file://${source}`) ? source : '[inline CONTENT]';
172
+ }
173
+
174
+ // in-memory documents are served under their synthetic memory:// URI, or under the
175
+ // caller-supplied base URI so that relative source description URLs resolve against
176
+ // a real location
177
+ if (document !== undefined) {
178
+ // raw options, not merged: mergeOptions defaults baseURI to the current working directory
179
+ source = options.resolve?.baseURI || source;
180
+ mergedOptions = (0, _util.mergeOptions)(mergedOptions, {
181
+ resolve: {
182
+ resolvers: [...mergedOptions.resolve.resolvers, new _index.default({
183
+ document,
184
+ uri: source
185
+ })]
186
+ }
187
+ });
188
+ }
189
+
190
+ // next we assume that source is either file system URI or HTTP(S) URL
191
+ try {
192
+ const parseResult = await (0, _empty.parse)(source, mergedOptions);
193
+
194
+ // set retrievalURI metadata for file/URL sources (not for inline content)
195
+ if (!source.startsWith('memory://')) {
196
+ parseResult.meta.set('retrievalURI', source);
197
+ }
198
+
199
+ // validate that the parsed document is an Arazzo specification
200
+ if (!(0, _apidomNsArazzo.isArazzoSpecification1Element)(parseResult.api)) {
201
+ throw new _empty.UnmatchedParserError(`Could not find a parser that can parse "${sourceProvenance}" as an Arazzo specification`);
202
+ }
203
+ return parseResult;
204
+ } catch (error) {
205
+ throw new _ParseError.default(`Failed to parse Arazzo Document from "${sourceProvenance}"`, {
206
+ cause: error
207
+ });
208
+ }
209
+ }
@@ -0,0 +1,200 @@
1
+ import { url, parse as parseURI, UnmatchedParserError } from '@speclynx/apidom-reference/configuration/empty';
2
+ import ArazzoJSON1Parser from '@speclynx/apidom-reference/parse/parsers/arazzo-json-1';
3
+ import ArazzoYAML1Parser from '@speclynx/apidom-reference/parse/parsers/arazzo-yaml-1';
4
+ import OpenApiJSON2Parser from '@speclynx/apidom-reference/parse/parsers/openapi-json-2';
5
+ import OpenApiYAML2Parser from '@speclynx/apidom-reference/parse/parsers/openapi-yaml-2';
6
+ import OpenApiJSON3_0Parser from '@speclynx/apidom-reference/parse/parsers/openapi-json-3-0';
7
+ import OpenApiYAML3_0Parser from '@speclynx/apidom-reference/parse/parsers/openapi-yaml-3-0';
8
+ import OpenApiJSON3_1Parser from '@speclynx/apidom-reference/parse/parsers/openapi-json-3-1';
9
+ import OpenApiYAML3_1Parser from '@speclynx/apidom-reference/parse/parsers/openapi-yaml-3-1';
10
+ import FileResolver from '@speclynx/apidom-reference/resolve/resolvers/file';
11
+ import HTTPResolverAxios from '@speclynx/apidom-reference/resolve/resolvers/http-axios';
12
+ import { detect as detectArazzoJSON } from '@speclynx/apidom-parser-adapter-arazzo-json-1';
13
+ import { isArazzoSpecification1Element } from '@speclynx/apidom-ns-arazzo-1';
14
+ import { detect as detectArazzoYAML } from '@speclynx/apidom-parser-adapter-arazzo-yaml-1';
15
+ import { isPlainObject } from 'ramda-adjunct';
16
+ import ParseError from "./errors/ParseError.mjs";
17
+ import { mergeOptions } from "./options/util.mjs";
18
+ import MemoryResolver from "./resolve/resolvers/memory/index.mjs";
19
+ /**
20
+ * Options for parsing Arazzo Documents.
21
+ * @public
22
+ */
23
+ /**
24
+ * Default reference options for parsing Arazzo Documents.
25
+ * @public
26
+ */
27
+ export const defaultOptions = {
28
+ parse: {
29
+ parsers: [new ArazzoJSON1Parser({
30
+ allowEmpty: false
31
+ }), new ArazzoYAML1Parser({
32
+ allowEmpty: false
33
+ }), new OpenApiJSON2Parser({
34
+ allowEmpty: false
35
+ }), new OpenApiYAML2Parser({
36
+ allowEmpty: false
37
+ }), new OpenApiJSON3_0Parser({
38
+ allowEmpty: false
39
+ }), new OpenApiYAML3_0Parser({
40
+ allowEmpty: false
41
+ }), new OpenApiJSON3_1Parser({
42
+ allowEmpty: false
43
+ }), new OpenApiYAML3_1Parser({
44
+ allowEmpty: false
45
+ })],
46
+ parserOpts: {
47
+ sourceMap: false,
48
+ style: false,
49
+ strict: true,
50
+ sourceDescriptions: false
51
+ }
52
+ },
53
+ resolve: {
54
+ resolvers: [
55
+ // regex patterns, not glob strings - picomatch's glob matching never
56
+ // matches a dotfile basename (e.g. .arazzo.yaml) without `dot: true`,
57
+ // which FileResolver does not set.
58
+ new FileResolver({
59
+ fileAllowList: [/\.json$/i, /\.ya?ml$/i]
60
+ }), new HTTPResolverAxios({
61
+ timeout: 15000,
62
+ redirects: 5,
63
+ withCredentials: false
64
+ })],
65
+ resolverOpts: {}
66
+ }
67
+ };
68
+
69
+ /**
70
+ * Parses an Arazzo Document from an object.
71
+ * @param source - The Arazzo Document as a plain object
72
+ * @param options - Reference options (uses defaultOptions when not provided)
73
+ * @returns A promise that resolves to the parsed Arazzo Document as ApiDOM data model
74
+ * @throws ParseError - When parsing fails for any reason. The original error is available via the `cause` property.
75
+ * @public
76
+ */
77
+
78
+ /**
79
+ * Parses an Arazzo Document from a string or URI.
80
+ * @param source - The Arazzo Document as string content, or a file system path / HTTP(S) URL
81
+ * @param options - Reference options (uses defaultOptions when not provided)
82
+ * @returns A promise that resolves to the parsed Arazzo Document as ApiDOM data model
83
+ * @throws ParseError - When parsing fails for any reason. The original error is available via the `cause` property.
84
+ * @public
85
+ */
86
+
87
+ /**
88
+ * Parses an Arazzo Document from a string, object, or URI.
89
+ * @param source - The Arazzo Document as a plain object, string content, or URI
90
+ * @param options - Reference options (uses defaultOptions when not provided)
91
+ * @returns A promise that resolves to the parsed Arazzo Document as ApiDOM data model
92
+ * @throws ParseError - When parsing fails for any reason. The original error is available via the `cause` property.
93
+ * @public
94
+ */
95
+
96
+ /**
97
+ * Parses an Arazzo Document from a string, object, or URI.
98
+ *
99
+ * The function handles three types of input:
100
+ * 1. Object - converts to JSON string and parses (source maps supported with `strict: false`)
101
+ * 2. String content - uses Arazzo detection to identify and parse inline JSON or YAML content
102
+ * 3. URI string - if not detected as Arazzo content, treats as file system path or HTTP(S) URL
103
+ *
104
+ * @param source - The Arazzo Document as an object, string content, or a file system path / HTTP(S) URL
105
+ * @param options - Reference options (uses defaultOptions when not provided)
106
+ * @returns A promise that resolves to the parsed Arazzo Document as ApiDOM data model
107
+ * @throws ParseError - When parsing fails for any reason. The original error is available via the `cause` property.
108
+ *
109
+ * @example
110
+ * Parse from object
111
+ * ```typescript
112
+ * const result = await parseArazzo({ arazzo: '1.0.1', info: {...} });
113
+ * ```
114
+ *
115
+ * @example
116
+ * Parse inline JSON
117
+ * ```typescript
118
+ * const result = await parseArazzo('{"arazzo": "1.0.1", "info": {...}}');
119
+ * ```
120
+ *
121
+ * @example
122
+ * Parse from file
123
+ * ```typescript
124
+ * const result = await parseArazzo('/path/to/arazzo.json');
125
+ * ```
126
+ *
127
+ * @example
128
+ * Parse from URL
129
+ * ```typescript
130
+ * const result = await parseArazzo('https://example.com/arazzo.yaml');
131
+ * ```
132
+ *
133
+ * @example
134
+ * Parse with custom options
135
+ * ```typescript
136
+ * const result = await parseArazzo('/path/to/arazzo.json', customOptions);
137
+ * ```
138
+ * @public
139
+ */
140
+ export async function parse(source, options = {}) {
141
+ let mergedOptions = mergeOptions(defaultOptions, options);
142
+ const strict = mergedOptions.parse?.parserOpts?.strict ?? true;
143
+ let sourceProvenance;
144
+ let document;
145
+ if (isPlainObject(source)) {
146
+ document = JSON.stringify(source, null, 2);
147
+ source = 'memory://arazzo.json';
148
+ sourceProvenance = '[object]';
149
+ } else if (await detectArazzoJSON(source, {
150
+ strict
151
+ })) {
152
+ document = source;
153
+ source = 'memory://arazzo.json';
154
+ sourceProvenance = '[inline JSON]';
155
+ } else if (await detectArazzoYAML(source, {
156
+ strict
157
+ })) {
158
+ document = source;
159
+ source = 'memory://arazzo.yaml';
160
+ sourceProvenance = '[inline YAML]';
161
+ } else {
162
+ sourceProvenance = url.isHttpUrl(source) || url.getProtocol(source) === 'file' || url.isURI(`file://${source}`) ? source : '[inline CONTENT]';
163
+ }
164
+
165
+ // in-memory documents are served under their synthetic memory:// URI, or under the
166
+ // caller-supplied base URI so that relative source description URLs resolve against
167
+ // a real location
168
+ if (document !== undefined) {
169
+ // raw options, not merged: mergeOptions defaults baseURI to the current working directory
170
+ source = options.resolve?.baseURI || source;
171
+ mergedOptions = mergeOptions(mergedOptions, {
172
+ resolve: {
173
+ resolvers: [...mergedOptions.resolve.resolvers, new MemoryResolver({
174
+ document,
175
+ uri: source
176
+ })]
177
+ }
178
+ });
179
+ }
180
+
181
+ // next we assume that source is either file system URI or HTTP(S) URL
182
+ try {
183
+ const parseResult = await parseURI(source, mergedOptions);
184
+
185
+ // set retrievalURI metadata for file/URL sources (not for inline content)
186
+ if (!source.startsWith('memory://')) {
187
+ parseResult.meta.set('retrievalURI', source);
188
+ }
189
+
190
+ // validate that the parsed document is an Arazzo specification
191
+ if (!isArazzoSpecification1Element(parseResult.api)) {
192
+ throw new UnmatchedParserError(`Could not find a parser that can parse "${sourceProvenance}" as an Arazzo specification`);
193
+ }
194
+ return parseResult;
195
+ } catch (error) {
196
+ throw new ParseError(`Failed to parse Arazzo Document from "${sourceProvenance}"`, {
197
+ cause: error
198
+ });
199
+ }
200
+ }