@speclynx/apidom-reference 2.8.0 → 2.9.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.
@@ -816,6 +816,7 @@ __webpack_require__.r(__webpack_exports__);
816
816
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
817
817
  /* harmony export */ Arazzo1DereferenceVisitor: () => (/* reexport safe */ _visitor_ts__WEBPACK_IMPORTED_MODULE_9__["default"]),
818
818
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
819
+ /* harmony export */ dereferenceSourceDescriptions: () => (/* reexport safe */ _source_descriptions_ts__WEBPACK_IMPORTED_MODULE_10__.dereferenceSourceDescriptions),
819
820
  /* harmony export */ maybeRefractToJSONSchemaElement: () => (/* reexport safe */ _util_ts__WEBPACK_IMPORTED_MODULE_11__.maybeRefractToJSONSchemaElement),
820
821
  /* harmony export */ resolveSchema$idField: () => (/* reexport safe */ _util_ts__WEBPACK_IMPORTED_MODULE_12__.resolveSchema$idField),
821
822
  /* harmony export */ resolveSchema$refField: () => (/* reexport safe */ _util_ts__WEBPACK_IMPORTED_MODULE_12__.resolveSchema$refField)
@@ -830,7 +831,7 @@ __webpack_require__.r(__webpack_exports__);
830
831
  /* harmony import */ var _Reference_ts__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(98979);
831
832
  /* harmony import */ var _ReferenceSet_ts__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(24131);
832
833
  /* harmony import */ var _visitor_ts__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(31843);
833
- /* harmony import */ var _source_description_ts__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(99371);
834
+ /* harmony import */ var _source_descriptions_ts__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(12586);
834
835
  /* harmony import */ var _util_ts__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(91005);
835
836
  /* harmony import */ var _util_ts__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(60888);
836
837
 
@@ -908,7 +909,7 @@ class Arazzo1DereferenceStrategy extends _DereferenceStrategy_ts__WEBPACK_IMPORT
908
909
  */
909
910
  const shouldDereferenceSourceDescriptions = options?.dereference?.strategyOpts?.[this.name]?.sourceDescriptions ?? options?.dereference?.strategyOpts?.sourceDescriptions;
910
911
  if (shouldDereferenceSourceDescriptions) {
911
- const sourceDescriptions = await (0,_source_description_ts__WEBPACK_IMPORTED_MODULE_10__.dereferenceSourceDescriptions)(dereferencedElement, reference, options);
912
+ const sourceDescriptions = await (0,_source_descriptions_ts__WEBPACK_IMPORTED_MODULE_10__.dereferenceSourceDescriptions)(dereferencedElement, reference.uri, options, this.name);
912
913
  dereferencedElement.push(...sourceDescriptions);
913
914
  }
914
915
 
@@ -935,11 +936,12 @@ class Arazzo1DereferenceStrategy extends _DereferenceStrategy_ts__WEBPACK_IMPORT
935
936
  }
936
937
 
937
938
 
939
+
938
940
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Arazzo1DereferenceStrategy);
939
941
 
940
942
  /***/ },
941
943
 
942
- /***/ 99371
944
+ /***/ 12586
943
945
  (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
944
946
 
945
947
  "use strict";
@@ -949,17 +951,17 @@ __webpack_require__.r(__webpack_exports__);
949
951
  /* harmony export */ });
950
952
  /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(25162);
951
953
  /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(12111);
952
- /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(84660);
953
- /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4823);
954
- /* harmony import */ var _speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(28839);
955
- /* harmony import */ var _speclynx_apidom_ns_openapi_2__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(26365);
956
- /* harmony import */ var _speclynx_apidom_ns_openapi_3_0__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(32131);
957
- /* harmony import */ var _speclynx_apidom_ns_openapi_3_1__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(76332);
958
- /* harmony import */ var _speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(44673);
959
- /* harmony import */ var _util_url_ts__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(30658);
960
- /* harmony import */ var _options_util_ts__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(86547);
961
- /* harmony import */ var _index_ts__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(42037);
962
-
954
+ /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(96911);
955
+ /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(84660);
956
+ /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(4823);
957
+ /* harmony import */ var _speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(28839);
958
+ /* harmony import */ var _speclynx_apidom_ns_openapi_2__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(26365);
959
+ /* harmony import */ var _speclynx_apidom_ns_openapi_3_0__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(32131);
960
+ /* harmony import */ var _speclynx_apidom_ns_openapi_3_1__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(76332);
961
+ /* harmony import */ var _speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(44673);
962
+ /* harmony import */ var _util_url_ts__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(30658);
963
+ /* harmony import */ var _options_util_ts__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(86547);
964
+ /* harmony import */ var _index_ts__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(42037);
963
965
 
964
966
 
965
967
 
@@ -969,16 +971,14 @@ __webpack_require__.r(__webpack_exports__);
969
971
 
970
972
 
971
973
 
972
- // shared key for recursion state (works across JSON/YAML documents)
973
- const ARAZZO_DEREFERENCE_RECURSION_KEY = 'arazzo-1';
974
974
  /**
975
975
  * Dereferences a single source description element.
976
976
  * Returns ParseResultElement on success, or with annotation if skipped.
977
977
  */
978
978
  async function dereferenceSourceDescription(sourceDescription, ctx) {
979
- const parseResult = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"]();
980
- if (!(0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_4__.isSourceDescriptionElement)(sourceDescription)) {
981
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"]('Element is not a valid SourceDescriptionElement. Skipping');
979
+ const parseResult = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_4__["default"]();
980
+ if (!(0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_5__.isSourceDescriptionElement)(sourceDescription)) {
981
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"]('Element is not a valid SourceDescriptionElement. Skipping');
982
982
  annotation.classes.push('warning');
983
983
  parseResult.push(annotation);
984
984
  return parseResult;
@@ -988,37 +988,73 @@ async function dereferenceSourceDescription(sourceDescription, ctx) {
988
988
  parseResult.classes.push('source-description');
989
989
  if ((0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.isStringElement)(sourceDescription.name)) parseResult.setMetaProperty('name', (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__.cloneDeep)(sourceDescription.name));
990
990
  if ((0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.isStringElement)(sourceDescription.type)) parseResult.setMetaProperty('type', (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__.cloneDeep)(sourceDescription.type));
991
- const sourceDescriptionURI = (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_8__["default"])(sourceDescription.url);
991
+ const sourceDescriptionURI = (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_9__["default"])(sourceDescription.url);
992
992
  if (typeof sourceDescriptionURI !== 'string') {
993
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"]('Source description URL is missing or not a string. Skipping');
993
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"]('Source description URL is missing or not a string. Skipping');
994
994
  annotation.classes.push('warning');
995
995
  parseResult.push(annotation);
996
996
  return parseResult;
997
997
  }
998
- const retrievalURI = _util_url_ts__WEBPACK_IMPORTED_MODULE_9__.resolve(ctx.baseURI, sourceDescriptionURI);
998
+
999
+ // normalize URI for consistent cycle detection and refSet cache key matching
1000
+ const retrievalURI = _util_url_ts__WEBPACK_IMPORTED_MODULE_10__.sanitize(_util_url_ts__WEBPACK_IMPORTED_MODULE_10__.stripHash(_util_url_ts__WEBPACK_IMPORTED_MODULE_10__.resolve(ctx.baseURI, sourceDescriptionURI)));
999
1001
 
1000
1002
  // skip if already visited (cycle detection)
1001
1003
  if (ctx.visitedUrls.has(retrievalURI)) {
1002
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"](`Source description "${retrievalURI}" has already been visited. Skipping to prevent cycle`);
1004
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"](`Source description "${retrievalURI}" has already been visited. Skipping to prevent cycle`);
1003
1005
  annotation.classes.push('warning');
1004
1006
  parseResult.push(annotation);
1005
1007
  return parseResult;
1006
1008
  }
1007
1009
  ctx.visitedUrls.add(retrievalURI);
1010
+
1011
+ // check if source description was already parsed (e.g., during parse phase with sourceDescriptions: true)
1012
+ const existingParseResult = sourceDescription.meta.get('parseResult');
1008
1013
  try {
1009
- const sourceDescriptionDereferenced = await (0,_index_ts__WEBPACK_IMPORTED_MODULE_11__["default"])(retrievalURI, (0,_options_util_ts__WEBPACK_IMPORTED_MODULE_10__.merge)(ctx.options, {
1010
- parse: {
1011
- mediaType: 'text/plain' // allow parser plugin detection
1012
- },
1013
- dereference: {
1014
- strategyOpts: {
1015
- [ARAZZO_DEREFERENCE_RECURSION_KEY]: {
1016
- sourceDescriptionsDepth: ctx.currentDepth + 1,
1017
- sourceDescriptionsVisitedUrls: ctx.visitedUrls
1014
+ let sourceDescriptionDereferenced;
1015
+ if ((0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__.isParseResultElement)(existingParseResult)) {
1016
+ // use existing parsed result - just dereference it (no re-fetch/re-parse)
1017
+ sourceDescriptionDereferenced = await (0,_index_ts__WEBPACK_IMPORTED_MODULE_12__.dereferenceApiDOM)(existingParseResult, (0,_options_util_ts__WEBPACK_IMPORTED_MODULE_11__.merge)(ctx.options, {
1018
+ parse: {
1019
+ mediaType: 'text/plain' // allow dereference strategy detection via ApiDOM inspection
1020
+ },
1021
+ resolve: {
1022
+ baseURI: retrievalURI
1023
+ },
1024
+ dereference: {
1025
+ strategyOpts: {
1026
+ // nested documents should dereference all their source descriptions
1027
+ // (parent's name filter doesn't apply to nested documents)
1028
+ // set at strategy-specific level to override any inherited filters
1029
+ [ctx.strategyName]: {
1030
+ sourceDescriptions: true,
1031
+ sourceDescriptionsDepth: ctx.currentDepth + 1,
1032
+ sourceDescriptionsVisitedUrls: ctx.visitedUrls
1033
+ }
1018
1034
  }
1019
1035
  }
1020
- }
1021
- }));
1036
+ }));
1037
+ } else {
1038
+ // no existing parse result - fetch, parse, and dereference
1039
+ sourceDescriptionDereferenced = await (0,_index_ts__WEBPACK_IMPORTED_MODULE_12__["default"])(retrievalURI, (0,_options_util_ts__WEBPACK_IMPORTED_MODULE_11__.merge)(ctx.options, {
1040
+ parse: {
1041
+ mediaType: 'text/plain' // allow parser plugin detection
1042
+ },
1043
+ dereference: {
1044
+ strategyOpts: {
1045
+ // nested documents should dereference all their source descriptions
1046
+ // (parent's name filter doesn't apply to nested documents)
1047
+ // set at strategy-specific level to override any inherited filters
1048
+ [ctx.strategyName]: {
1049
+ sourceDescriptions: true,
1050
+ sourceDescriptionsDepth: ctx.currentDepth + 1,
1051
+ sourceDescriptionsVisitedUrls: ctx.visitedUrls
1052
+ }
1053
+ }
1054
+ }
1055
+ }));
1056
+ }
1057
+
1022
1058
  // merge dereferenced result into our parse result
1023
1059
  for (const item of sourceDescriptionDereferenced) {
1024
1060
  parseResult.push(item);
@@ -1026,7 +1062,7 @@ async function dereferenceSourceDescription(sourceDescription, ctx) {
1026
1062
  } catch (error) {
1027
1063
  // create error annotation instead of failing entire dereference
1028
1064
  const message = error instanceof Error ? error.message : String(error);
1029
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"](`Error dereferencing source description "${retrievalURI}": ${message}`);
1065
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"](`Error dereferencing source description "${retrievalURI}": ${message}`);
1030
1066
  annotation.classes.push('error');
1031
1067
  parseResult.push(annotation);
1032
1068
  return parseResult;
@@ -1036,24 +1072,24 @@ async function dereferenceSourceDescription(sourceDescription, ctx) {
1036
1072
  const {
1037
1073
  api: sourceDescriptionAPI
1038
1074
  } = parseResult;
1039
- const isOpenApi = (0,_speclynx_apidom_ns_openapi_2__WEBPACK_IMPORTED_MODULE_5__.isSwaggerElement)(sourceDescriptionAPI) || (0,_speclynx_apidom_ns_openapi_3_0__WEBPACK_IMPORTED_MODULE_6__.isOpenApi3_0Element)(sourceDescriptionAPI) || (0,_speclynx_apidom_ns_openapi_3_1__WEBPACK_IMPORTED_MODULE_7__.isOpenApi3_1Element)(sourceDescriptionAPI);
1040
- const isArazzo = (0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_4__.isArazzoSpecification1Element)(sourceDescriptionAPI);
1075
+ const isOpenApi = (0,_speclynx_apidom_ns_openapi_2__WEBPACK_IMPORTED_MODULE_6__.isSwaggerElement)(sourceDescriptionAPI) || (0,_speclynx_apidom_ns_openapi_3_0__WEBPACK_IMPORTED_MODULE_7__.isOpenApi3_0Element)(sourceDescriptionAPI) || (0,_speclynx_apidom_ns_openapi_3_1__WEBPACK_IMPORTED_MODULE_8__.isOpenApi3_1Element)(sourceDescriptionAPI);
1076
+ const isArazzo = (0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_5__.isArazzoSpecification1Element)(sourceDescriptionAPI);
1041
1077
  if (!isOpenApi && !isArazzo) {
1042
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"](`Source description "${retrievalURI}" is not an OpenAPI or Arazzo document`);
1078
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"](`Source description "${retrievalURI}" is not an OpenAPI or Arazzo document`);
1043
1079
  annotation.classes.push('warning');
1044
1080
  parseResult.push(annotation);
1045
1081
  return parseResult;
1046
1082
  }
1047
1083
 
1048
1084
  // validate declared type matches actual dereferenced type
1049
- const declaredType = (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_8__["default"])(sourceDescription.type);
1085
+ const declaredType = (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_9__["default"])(sourceDescription.type);
1050
1086
  if (typeof declaredType === 'string') {
1051
1087
  if (declaredType === 'openapi' && !isOpenApi) {
1052
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"](`Source description "${retrievalURI}" declared as "openapi" but dereferenced as Arazzo document`);
1088
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"](`Source description "${retrievalURI}" declared as "openapi" but dereferenced as Arazzo document`);
1053
1089
  annotation.classes.push('warning');
1054
1090
  parseResult.push(annotation);
1055
1091
  } else if (declaredType === 'arazzo' && !isArazzo) {
1056
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"](`Source description "${retrievalURI}" declared as "arazzo" but dereferenced as OpenAPI document`);
1092
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"](`Source description "${retrievalURI}" declared as "arazzo" but dereferenced as OpenAPI document`);
1057
1093
  annotation.classes.push('warning');
1058
1094
  parseResult.push(annotation);
1059
1095
  }
@@ -1063,11 +1099,45 @@ async function dereferenceSourceDescription(sourceDescription, ctx) {
1063
1099
 
1064
1100
  /**
1065
1101
  * Dereferences source descriptions from an Arazzo document.
1102
+ *
1103
+ * Each source description result is attached to its corresponding
1104
+ * SourceDescriptionElement's meta as 'parseResult' for easy access,
1105
+ * regardless of success or failure. On failure, the ParseResultElement
1106
+ * contains annotations explaining what went wrong.
1107
+ *
1108
+ * @param parseResult - ParseResult containing a parsed (optionally dereferenced) Arazzo specification
1109
+ * @param parseResultRetrievalURI - URI from which the parseResult was retrieved
1110
+ * @param options - Full ReferenceOptions. Pass `sourceDescriptions` as an array of names
1111
+ * in `dereference.strategyOpts` to filter which source descriptions to process.
1112
+ * @param strategyName - Strategy name for options lookup (defaults to 'arazzo-1')
1113
+ * @returns Array of ParseResultElements. Returns one ParseResultElement per source description
1114
+ * (each with class 'source-description' and name/type metadata).
1115
+ * May return early with a single-element array containing a warning annotation when:
1116
+ * - The API is not an Arazzo specification
1117
+ * - The sourceDescriptions field is missing or not an array
1118
+ * - Maximum dereference depth is exceeded (error annotation)
1119
+ * Returns an empty array when no source description names match the filter.
1120
+ *
1121
+ * @example
1122
+ * ```typescript
1123
+ * // Dereference all source descriptions
1124
+ * await dereferenceSourceDescriptions(parseResult, uri, options);
1125
+ *
1126
+ * // Filter by name
1127
+ * await dereferenceSourceDescriptions(parseResult, uri, mergeOptions(options, {
1128
+ * dereference: { strategyOpts: { sourceDescriptions: ['petStore'] } },
1129
+ * }));
1130
+ *
1131
+ * // Access dereferenced document from source description element
1132
+ * const sourceDesc = parseResult.api.sourceDescriptions.get(0);
1133
+ * const dereferencedDoc = sourceDesc.meta.get('parseResult');
1134
+ * ```
1135
+ *
1066
1136
  * @public
1067
1137
  */
1068
- async function dereferenceSourceDescriptions(parseResult, reference, options) {
1138
+ async function dereferenceSourceDescriptions(parseResult, parseResultRetrievalURI, options, strategyName = 'arazzo-1') {
1139
+ const baseURI = _util_url_ts__WEBPACK_IMPORTED_MODULE_10__.sanitize(_util_url_ts__WEBPACK_IMPORTED_MODULE_10__.stripHash(parseResultRetrievalURI));
1069
1140
  const results = [];
1070
- const strategyName = 'arazzo-1';
1071
1141
 
1072
1142
  // get API from dereferenced parse result
1073
1143
  const {
@@ -1078,57 +1148,55 @@ async function dereferenceSourceDescriptions(parseResult, reference, options) {
1078
1148
  * Validate prerequisites for dereferencing source descriptions.
1079
1149
  * Return warning annotations if validation fails.
1080
1150
  */
1081
- if (!(0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_4__.isArazzoSpecification1Element)(api)) {
1082
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"]('Cannot dereference source descriptions: API is not an Arazzo specification');
1151
+ if (!(0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_5__.isArazzoSpecification1Element)(api)) {
1152
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"]('Cannot dereference source descriptions: API is not an Arazzo specification');
1083
1153
  annotation.classes.push('warning');
1084
- return [new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"]([annotation])];
1154
+ return [new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_4__["default"]([annotation])];
1085
1155
  }
1086
1156
  if (!(0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.isArrayElement)(api.sourceDescriptions)) {
1087
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"]('Cannot dereference source descriptions: sourceDescriptions field is missing or not an array');
1157
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"]('Cannot dereference source descriptions: sourceDescriptions field is missing or not an array');
1088
1158
  annotation.classes.push('warning');
1089
- return [new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"]([annotation])];
1159
+ return [new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_4__["default"]([annotation])];
1090
1160
  }
1091
1161
 
1092
1162
  // user config: strategy-specific options take precedence over global strategyOpts
1093
1163
  const maxDepth = options?.dereference?.strategyOpts?.[strategyName]?.sourceDescriptionsMaxDepth ?? options?.dereference?.strategyOpts?.sourceDescriptionsMaxDepth ?? +Infinity;
1094
1164
 
1095
- // recursion state comes from shared key (works across JSON/YAML)
1096
- const sharedOpts = options?.dereference?.strategyOpts?.[ARAZZO_DEREFERENCE_RECURSION_KEY] ?? {};
1165
+ // recursion state comes from strategy-specific options
1166
+ const sharedOpts = options?.dereference?.strategyOpts?.[strategyName] ?? {};
1097
1167
  const currentDepth = sharedOpts.sourceDescriptionsDepth ?? 0;
1098
1168
  const visitedUrls = sharedOpts.sourceDescriptionsVisitedUrls ?? new Set();
1099
1169
 
1100
1170
  // add current file to visited URLs to prevent cycles
1101
- visitedUrls.add(reference.uri);
1171
+ visitedUrls.add(baseURI);
1102
1172
  if (currentDepth >= maxDepth) {
1103
- const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_2__["default"](`Maximum dereference depth of ${maxDepth} has been exceeded by file "${reference.uri}"`);
1173
+ const annotation = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"](`Maximum dereference depth of ${maxDepth} has been exceeded by file "${baseURI}"`);
1104
1174
  annotation.classes.push('error');
1105
- const parseResult = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_3__["default"]([annotation]);
1175
+ const parseResult = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_4__["default"]([annotation]);
1106
1176
  parseResult.classes.push('source-description');
1107
1177
  return [parseResult];
1108
1178
  }
1109
1179
  const ctx = {
1110
- baseURI: reference.uri,
1180
+ baseURI,
1111
1181
  options,
1182
+ strategyName,
1112
1183
  currentDepth,
1113
1184
  visitedUrls
1114
1185
  };
1115
1186
 
1116
- // determine which source descriptions to dereference
1187
+ // determine which source descriptions to dereference (array filters by name)
1117
1188
  const sourceDescriptionsOption = options?.dereference?.strategyOpts?.[strategyName]?.sourceDescriptions ?? options?.dereference?.strategyOpts?.sourceDescriptions;
1118
-
1119
- // handle false or other falsy values - no source descriptions should be dereferenced
1120
- if (!sourceDescriptionsOption) {
1121
- return results;
1122
- }
1123
1189
  const sourceDescriptions = Array.isArray(sourceDescriptionsOption) ? api.sourceDescriptions.filter(sd => {
1124
- if (!(0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_4__.isSourceDescriptionElement)(sd)) return false;
1125
- const name = (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_8__["default"])(sd.name);
1190
+ if (!(0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_5__.isSourceDescriptionElement)(sd)) return false;
1191
+ const name = (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_9__["default"])(sd.name);
1126
1192
  return typeof name === 'string' && sourceDescriptionsOption.includes(name);
1127
1193
  }) : api.sourceDescriptions;
1128
1194
 
1129
1195
  // process sequentially to ensure proper cycle detection with shared visitedUrls
1130
1196
  for (const sourceDescription of sourceDescriptions) {
1131
1197
  const sourceDescriptionDereferenceResult = await dereferenceSourceDescription(sourceDescription, ctx);
1198
+ // always attach result (even on failure - contains annotations)
1199
+ sourceDescription.meta.set('parseResult', sourceDescriptionDereferenceResult);
1132
1200
  results.push(sourceDescriptionDereferenceResult);
1133
1201
  }
1134
1202
  return results;
@@ -5832,7 +5900,9 @@ async function parseSourceDescription(sourceDescription, ctx) {
5832
5900
  parseResult.push(annotation);
5833
5901
  return parseResult;
5834
5902
  }
5835
- const retrievalURI = _util_url_ts__WEBPACK_IMPORTED_MODULE_10__.resolve(ctx.baseURI, sourceDescriptionURI);
5903
+
5904
+ // normalize URI for consistent cycle detection and cache key matching
5905
+ const retrievalURI = _util_url_ts__WEBPACK_IMPORTED_MODULE_10__.sanitize(_util_url_ts__WEBPACK_IMPORTED_MODULE_10__.stripHash(_util_url_ts__WEBPACK_IMPORTED_MODULE_10__.resolve(ctx.baseURI, sourceDescriptionURI)));
5836
5906
 
5837
5907
  // skip if already visited (cycle detection)
5838
5908
  if (ctx.visitedUrls.has(retrievalURI)) {
@@ -5848,6 +5918,9 @@ async function parseSourceDescription(sourceDescription, ctx) {
5848
5918
  mediaType: 'text/plain',
5849
5919
  // allow parser plugin detection
5850
5920
  parserOpts: {
5921
+ // nested documents should parse all their source descriptions
5922
+ // (parent's name filter doesn't apply to nested documents)
5923
+ sourceDescriptions: true,
5851
5924
  [ARAZZO_RECURSION_KEY]: {
5852
5925
  sourceDescriptionsDepth: ctx.currentDepth + 1,
5853
5926
  sourceDescriptionsVisitedUrls: ctx.visitedUrls
@@ -5900,27 +5973,40 @@ async function parseSourceDescription(sourceDescription, ctx) {
5900
5973
  /**
5901
5974
  * Parses source descriptions from an Arazzo document's ParseResult.
5902
5975
  *
5976
+ * Each source description result is attached to its corresponding
5977
+ * SourceDescriptionElement's meta as 'parseResult' for easy access,
5978
+ * regardless of success or failure. On failure, the ParseResultElement
5979
+ * contains annotations explaining what went wrong.
5980
+ *
5903
5981
  * @param parseResult - ParseResult containing an Arazzo specification
5904
5982
  * @param parseResultRetrievalURI - URI from which the parseResult was retrieved
5905
- * @param options - Full ReferenceOptions (caller responsibility to construct)
5983
+ * @param options - Full ReferenceOptions. Pass `sourceDescriptions` as an array of names
5984
+ * in `parse.parserOpts` to filter which source descriptions to process.
5906
5985
  * @param parserName - Parser name for options lookup (defaults to 'arazzo-json-1')
5907
- * @returns Array of ParseResultElements. On success, returns one ParseResultElement per
5908
- * source description (each with class 'source-description' and name/type metadata).
5986
+ * @returns Array of ParseResultElements. Returns one ParseResultElement per source description
5987
+ * (each with class 'source-description' and name/type metadata).
5909
5988
  * May return early with a single-element array containing a warning annotation when:
5910
5989
  * - The API is not an Arazzo specification
5911
5990
  * - The sourceDescriptions field is missing or not an array
5912
5991
  * - Maximum parse depth is exceeded (error annotation)
5913
- * Returns an empty array when sourceDescriptions option is disabled or no names match.
5992
+ * Returns an empty array when no source description names match the filter.
5914
5993
  *
5915
5994
  * @example
5916
5995
  * ```typescript
5917
5996
  * import { options, mergeOptions } from '@speclynx/apidom-reference';
5918
5997
  * import { parseSourceDescriptions } from '@speclynx/apidom-reference/parse/parsers/arazzo-json-1';
5919
5998
  *
5920
- * const fullOptions = mergeOptions(options, {
5921
- * parse: { parserOpts: { sourceDescriptions: true } }
5922
- * });
5923
- * const results = await parseSourceDescriptions(parseResult, uri, fullOptions);
5999
+ * // Parse all source descriptions
6000
+ * const results = await parseSourceDescriptions(parseResult, uri, options);
6001
+ *
6002
+ * // Filter by name
6003
+ * const filtered = await parseSourceDescriptions(parseResult, uri, mergeOptions(options, {
6004
+ * parse: { parserOpts: { sourceDescriptions: ['petStore'] } }
6005
+ * }));
6006
+ *
6007
+ * // Access parsed document from source description element
6008
+ * const sourceDesc = parseResult.api.sourceDescriptions.get(0);
6009
+ * const parsedDoc = sourceDesc.meta.get('parseResult');
5924
6010
  * ```
5925
6011
  *
5926
6012
  * @public
@@ -5973,13 +6059,8 @@ async function parseSourceDescriptions(parseResult, parseResultRetrievalURI, opt
5973
6059
  visitedUrls
5974
6060
  };
5975
6061
 
5976
- // determine which source descriptions to parse
6062
+ // determine which source descriptions to parse (array filters by name)
5977
6063
  const sourceDescriptionsOption = options?.parse?.parserOpts?.[parserName]?.sourceDescriptions ?? options?.parse?.parserOpts?.sourceDescriptions;
5978
-
5979
- // handle false or other falsy values - no source descriptions should be parsed
5980
- if (!sourceDescriptionsOption) {
5981
- return results;
5982
- }
5983
6064
  const sourceDescriptions = Array.isArray(sourceDescriptionsOption) ? api.sourceDescriptions.filter(sd => {
5984
6065
  if (!(0,_speclynx_apidom_ns_arazzo_1__WEBPACK_IMPORTED_MODULE_4__.isSourceDescriptionElement)(sd)) return false;
5985
6066
  const name = (0,_speclynx_apidom_core__WEBPACK_IMPORTED_MODULE_8__["default"])(sd.name);
@@ -5989,6 +6070,8 @@ async function parseSourceDescriptions(parseResult, parseResultRetrievalURI, opt
5989
6070
  // process sequentially to ensure proper cycle detection with shared visitedUrls
5990
6071
  for (const sourceDescription of sourceDescriptions) {
5991
6072
  const sourceDescriptionParseResult = await parseSourceDescription(sourceDescription, ctx);
6073
+ // always attach result (even on failure - contains annotations)
6074
+ sourceDescription.meta.set('parseResult', sourceDescriptionParseResult);
5992
6075
  results.push(sourceDescriptionParseResult);
5993
6076
  }
5994
6077
  return results;