@@ -202,22 +202,35 @@ export const buildAsyncApiOperation = (
202202}
203203
204204/**
205- * Creates an operation spec from AsyncAPI document
206- * Crops the document to contain only the requested operation(s)
205+ * Creates an operation spec (a cropped AsyncAPI document) that contains only the requested operation(s).
206+ *
207+ * By default, the returned object includes only `asyncapi`, `info`, and `operations`.
208+ * If `refsDocument` is provided and contains inline refs for all requested operations, the function
209+ * will also inline referenced `channels`, `servers`, and `components` from the original `document`.
210+ *
211+ * @param document AsyncAPI 3.0 document to crop.
212+ * @param operationKey Operation key or an array of operation keys to include.
213+ * @param refsDocument Optional "refs-only" document used to detect inline refs that must be copied.
214+ * @throws Error when the document has no `operations`, when no operation keys are provided, or when any
215+ * requested operation key is missing in the document.
207216 */
208217export const createOperationSpec = (
209218 document : AsyncAPIV3 . AsyncAPIObject ,
210219 operationKey : string | string [ ] ,
211- refsOnlyDocument ?: AsyncAPIV3 . AsyncAPIObject ,
220+ refsDocument ?: AsyncAPIV3 . AsyncAPIObject ,
212221) : TYPE . AsyncOperationData => {
213222 const operations = document ?. operations
214223 if ( ! operations ) {
215- throw new Error ( 'No operations' )
224+ throw new Error (
225+ 'AsyncAPI document has no operations. Expected a non-empty "operations" object at document.operations.' ,
226+ )
216227 }
217228
218229 const operationKeys = Array . isArray ( operationKey ) ? operationKey : [ operationKey ]
219230 if ( operationKeys . length === 0 ) {
220- throw new Error ( 'No operation keys provided' )
231+ throw new Error (
232+ 'No operation keys provided. Pass a non-empty operation key string or a non-empty array of operation keys.' ,
233+ )
221234 }
222235
223236 const missingOperationKeys : string [ ] = [ ]
@@ -233,9 +246,13 @@ export const createOperationSpec = (
233246
234247 if ( missingOperationKeys . length > 0 ) {
235248 if ( ! Array . isArray ( operationKey ) && missingOperationKeys . length === 1 ) {
236- throw new Error ( `Operation ${ missingOperationKeys [ 0 ] } not found in document` )
249+ throw new Error (
250+ `Operation "${ missingOperationKeys [ 0 ] } " not found in document.operations` ,
251+ )
237252 }
238- throw new Error ( `Operations ${ missingOperationKeys . join ( ', ' ) } not found in document` )
253+ throw new Error (
254+ `Operations not found in document.operations: ${ missingOperationKeys . join ( ', ' ) } ` ,
255+ )
239256 }
240257
241258 const resultSpec : TYPE . AsyncOperationData = {
@@ -244,64 +261,62 @@ export const createOperationSpec = (
244261 operations : selectedOperations ,
245262 }
246263
247- const refsOnlyOperations = refsOnlyDocument ?. operations
248- if ( refsOnlyOperations ) {
249- let hasAllOperationsInRefsOnly = true
250- for ( const key of operationKeys ) {
251- if ( ! refsOnlyOperations [ key ] ) {
252- hasAllOperationsInRefsOnly = false
253- break
254- }
264+ const refsOnlyOperations = refsDocument ?. operations
265+ if ( ! refsOnlyOperations ) {
266+ return resultSpec
267+ }
268+
269+ // If there are not enough operations, we will get an incorrect result.
270+ for ( const key of operationKeys ) {
271+ if ( ! refsOnlyOperations [ key ] ) {
272+ return resultSpec
255273 }
256- if ( hasAllOperationsInRefsOnly ) {
257- const handledObjects = new Set < unknown > ( )
258- const inlineRefs = new Set < string > ( )
274+ }
275+ const handledObjects = new Set < unknown > ( )
276+ const inlineRefs = new Set < string > ( )
259277
260- syncCrawl (
261- refsOnlyDocument ,
262- ( { key, value } ) => {
263- if ( typeof key === 'symbol' && key !== INLINE_REFS_FLAG ) {
264- return { done : true }
265- }
266- if ( handledObjects . has ( value ) ) {
267- return { done : true }
268- }
269- handledObjects . add ( value )
270- if ( key !== INLINE_REFS_FLAG ) {
271- return { value }
272- }
273- if ( ! Array . isArray ( value ) ) {
274- return { done : true }
275- }
276- value . forEach ( ref => inlineRefs . add ( ref ) )
277- } ,
278- )
278+ syncCrawl (
279+ refsDocument ,
280+ ( { key, value } ) => {
281+ if ( typeof key === 'symbol' && key !== INLINE_REFS_FLAG ) {
282+ return { done : true }
283+ }
284+ if ( handledObjects . has ( value ) ) {
285+ return { done : true }
286+ }
287+ handledObjects . add ( value )
288+ if ( key !== INLINE_REFS_FLAG ) {
289+ return { value }
290+ }
291+ if ( ! Array . isArray ( value ) ) {
292+ return { done : true }
293+ }
294+ value . forEach ( ref => inlineRefs . add ( ref ) )
295+ } ,
296+ )
279297
280- const componentNameMatcher = grepValue ( 'componentName' )
281- const matchPatterns = [
282- [ ASYNCAPI_PROPERTY_COMPONENTS , PREDICATE_ANY_VALUE , componentNameMatcher , PREDICATE_UNCLOSED_END ] ,
283- [ ASYNCAPI_PROPERTY_CHANNELS , componentNameMatcher , PREDICATE_UNCLOSED_END ] ,
284- [ ASYNCAPI_PROPERTY_SERVERS , componentNameMatcher , PREDICATE_UNCLOSED_END ] ,
285- ]
298+ const componentNameMatcher = grepValue ( 'componentName' )
299+ const matchPatterns = [
300+ [ ASYNCAPI_PROPERTY_COMPONENTS , PREDICATE_ANY_VALUE , componentNameMatcher , PREDICATE_UNCLOSED_END ] ,
301+ [ ASYNCAPI_PROPERTY_CHANNELS , componentNameMatcher , PREDICATE_UNCLOSED_END ] ,
302+ [ ASYNCAPI_PROPERTY_SERVERS , componentNameMatcher , PREDICATE_UNCLOSED_END ] ,
303+ ]
286304
287- inlineRefs . forEach ( ref => {
288- const parsed = parseRef ( ref )
289- const path = parsed ?. jsonPath
290- if ( ! path ) {
291- return
292- }
293- const matchResult = matchPaths ( [ path ] , matchPatterns )
294- if ( ! matchResult ) {
295- return
296- }
297- const component = getKeyValue ( document , ...matchResult . path ) as Record < string , unknown >
298- if ( ! component ) {
299- return
300- }
301- setValueByPath ( resultSpec , matchResult . path , component )
302- } )
305+ inlineRefs . forEach ( ref => {
306+ const parsed = parseRef ( ref )
307+ const path = parsed ?. jsonPath
308+ if ( ! path ) {
309+ return
303310 }
304- }
311+ const matchResult = matchPaths ( [ path ] , matchPatterns )
312+ if ( ! matchResult ) {
313+ return
314+ }
315+ const component = getKeyValue ( document , ...matchResult . path ) as Record < string , unknown >
316+ if ( ! component ) {
317+ return
318+ }
319+ setValueByPath ( resultSpec , matchResult . path , component )
320+ } )
305321 return resultSpec
306322}
307-
0 commit comments