diff --git a/src/helpers/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/index.js b/src/helpers/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/index.js index ec0cbfef0..db7852b73 100644 --- a/src/helpers/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/index.js +++ b/src/helpers/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/index.js @@ -70,6 +70,7 @@ const OpenApi3_1SwaggerClientDereferenceStrategy = OpenApi3_1DereferenceStrategy if (typeof this.modelPropertyMacro === 'function') { const modelPropertyMacroVisitor = ModelPropertyMacroVisitor({ modelPropertyMacro: this.modelPropertyMacro, + options, }); visitors.push(modelPropertyMacroVisitor); } diff --git a/src/helpers/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/visitors/properties.js b/src/helpers/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/visitors/properties.js index 8d9720989..df80669dd 100644 --- a/src/helpers/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/visitors/properties.js +++ b/src/helpers/apidom/reference/dereference/strategies/openapi-3-1-swagger-client/visitors/properties.js @@ -1,16 +1,34 @@ import { isObjectElement, toValue } from '@swagger-api/apidom-core'; -const ModelPropertyMacroVisitor = ({ modelPropertyMacro }) => ({ - SchemaElement: { - leave(schemaElement) { - if (typeof schemaElement.properties === 'undefined') return; - if (!isObjectElement(schemaElement.properties)) return; +import compose from '../utils/compose.js'; +import toPath from '../utils/to-path.js'; - schemaElement.properties.forEach((property) => { - if (!isObjectElement(property)) return; +const ModelPropertyMacroVisitor = compose({ + init({ modelPropertyMacro, options }) { + this.modelPropertyMacro = modelPropertyMacro; + this.options = options; + }, + props: { + modelPropertyMacro: null, + options: null, + SchemaElement: { + leave(schemaElement, key, parent, path, ancestors) { + if (typeof schemaElement.properties === 'undefined') return; + if (!isObjectElement(schemaElement.properties)) return; + + schemaElement.properties.forEach((property) => { + if (!isObjectElement(property)) return; - property.set('default', modelPropertyMacro(toValue(property))); - }); + try { + const macroValue = this.modelPropertyMacro(toValue(property)); + property.set('default', macroValue); + } catch (error) { + const macroError = new Error(error, { cause: error }); + macroError.fullPath = [...toPath([...ancestors, parent, schemaElement]), 'properties']; + this.options.dereference.dereferenceOpts?.errors?.push?.(macroError); + } + }); + }, }, }, }); diff --git a/test/resolver/strategies/openapi-3-1/__fixtures__/model-property-macro-error.json b/test/resolver/strategies/openapi-3-1/__fixtures__/model-property-macro-error.json new file mode 100644 index 000000000..e0c9c4261 --- /dev/null +++ b/test/resolver/strategies/openapi-3-1/__fixtures__/model-property-macro-error.json @@ -0,0 +1,27 @@ +{ + "openapi": "3.1.0", + "info": { + "version": "1.0.0", + "title": "Swagger Petstore", + "license": { + "name": "MIT" + } + }, + "components": { + "schemas": { + "Pet": { + "type": "object", + "required": [ + "id", + "name" + ], + "properties": { + "id": { + "type": "integer", + "format": "int64" + } + } + } + } + } +} diff --git a/test/resolver/strategies/openapi-3-1/__snapshots__/index.js.snap b/test/resolver/strategies/openapi-3-1/__snapshots__/index.js.snap index 57b39c938..1fcd08a9c 100644 --- a/test/resolver/strategies/openapi-3-1/__snapshots__/index.js.snap +++ b/test/resolver/strategies/openapi-3-1/__snapshots__/index.js.snap @@ -1292,6 +1292,37 @@ exports[`resolve OpenAPI 3.1.0 strategy given OpenAPI 3.1.0 definition via spec } `; +exports[`resolve OpenAPI 3.1.0 strategy given OpenAPI 3.1.0 definition via spec option and modelPropertyMacro is provided as a function given the function throws error should collect error 1`] = ` +{ + "$$normalized": true, + "components": { + "schemas": { + "Pet": { + "properties": { + "id": { + "format": "int64", + "type": "integer", + }, + }, + "required": [ + "id", + "name", + ], + "type": "object", + }, + }, + }, + "info": { + "license": { + "name": "MIT", + }, + "title": "Swagger Petstore", + "version": "1.0.0", + }, + "openapi": "3.1.0", +} +`; + exports[`resolve OpenAPI 3.1.0 strategy given OpenAPI 3.1.0 definition via spec option and modelPropertyMacro is provided as a function should call modelPropertyMacro with Schema Object property 1`] = ` { "errors": [], diff --git a/test/resolver/strategies/openapi-3-1/index.js b/test/resolver/strategies/openapi-3-1/index.js index 01a8b6e50..7ba1a09a6 100644 --- a/test/resolver/strategies/openapi-3-1/index.js +++ b/test/resolver/strategies/openapi-3-1/index.js @@ -227,6 +227,27 @@ describe('resolve', () => { expect(resolvedSpec).toMatchSnapshot(); }); + + describe('given the function throws error', () => { + test('should collect error', async () => { + const spec = globalThis.loadJsonFile( + path.join(fixturePath, 'model-property-macro-error.json') + ); + const { spec: resolvedSpec, errors } = await SwaggerClient.resolve({ + spec, + modelPropertyMacro: () => { + throw new Error('this macro throws'); + }, + }); + + expect(resolvedSpec).toMatchSnapshot(); + expect(errors).toHaveLength(1); + expect(errors[0]).toMatchObject({ + message: expect.stringMatching(/^Error: this macro throws/), + fullPath: ['components', 'schemas', 'Pet', 'properties'], + }); + }); + }); }); }); });