|  | 
| 14 | 14 |  * limitations under the License. | 
| 15 | 15 |  */ | 
| 16 | 16 | 
 | 
| 17 |  | -import { VersionGraphQLOperation } from './graphql.types' | 
| 18 |  | -import { removeComponents, takeIf } from '../../utils' | 
| 19 |  | -import { apiDiff, COMPARE_MODE_OPERATION, Diff } from '@netcracker/qubership-apihub-api-diff' | 
| 20 |  | -import { NORMALIZE_OPTIONS } from '../../consts' | 
| 21 |  | -import { GraphApiSchema } from '@netcracker/qubership-apihub-graphapi' | 
| 22 |  | - | 
| 23 |  | -export const graphqlOperationsCompare = async (current: VersionGraphQLOperation | undefined, previous: VersionGraphQLOperation | undefined): Promise<Diff[]> => { | 
| 24 |  | -  let previousOperation = removeComponents(previous?.data) | 
| 25 |  | -  let currentOperation = removeComponents(current?.data) | 
| 26 |  | -  if (!previousOperation && currentOperation) { | 
| 27 |  | -    previousOperation = getCopyWithEmptyOperations(currentOperation as GraphApiSchema) | 
| 28 |  | -  } | 
|  | 17 | +import { isEmpty, slugify, takeIf } from '../../utils' | 
|  | 18 | +import { aggregateDiffsWithRollup, apiDiff, Diff, DIFF_META_KEY, DIFFS_AGGREGATED_META_KEY } from '@netcracker/qubership-apihub-api-diff' | 
|  | 19 | +import { NORMALIZE_OPTIONS, ORIGINS_SYMBOL } from '../../consts' | 
|  | 20 | +import { GraphApiOperation, GraphApiSchema } from '@netcracker/qubership-apihub-graphapi' | 
|  | 21 | +import { buildSchema } from 'graphql/utilities' | 
|  | 22 | +import { buildGraphQLDocument } from './graphql.document' | 
|  | 23 | +import { | 
|  | 24 | +  CompareOperationsPairContext, | 
|  | 25 | +  FILE_KIND, | 
|  | 26 | +  OperationChanges, | 
|  | 27 | +  ResolvedVersionDocument, | 
|  | 28 | +  WithAggregatedDiffs, | 
|  | 29 | +  WithDiffMetaRecord, | 
|  | 30 | +} from '../../types' | 
|  | 31 | +import { GRAPHQL_TYPE, GRAPHQL_TYPE_KEYS } from './graphql.consts' | 
|  | 32 | +import { createOperationChange, getOperationTags, OperationsMap } from '../../components' | 
|  | 33 | + | 
|  | 34 | +export const compareDocuments = async ( | 
|  | 35 | +  operationsMap: OperationsMap, | 
|  | 36 | +  prevDoc: ResolvedVersionDocument | undefined, | 
|  | 37 | +  currDoc: ResolvedVersionDocument | undefined, | 
|  | 38 | +  ctx: CompareOperationsPairContext): Promise<{ | 
|  | 39 | +    operationChanges: OperationChanges[] | 
|  | 40 | +    tags: Set<string> | 
|  | 41 | +  }> => { | 
|  | 42 | +  const { apiType, rawDocumentResolver, previousVersion, currentVersion, previousPackageId, currentPackageId } = ctx | 
|  | 43 | +  const prevFile = prevDoc && await rawDocumentResolver(previousVersion, previousPackageId, prevDoc.slug) | 
|  | 44 | +  const currFile = currDoc && await rawDocumentResolver(currentVersion, currentPackageId, currDoc.slug) | 
|  | 45 | +  const prevDocSchema = prevFile && buildSchema(await prevFile.text(), { noLocation: true }) | 
|  | 46 | +  const currDocSchema = currFile && buildSchema(await currFile.text(), { noLocation: true }) | 
|  | 47 | + | 
|  | 48 | +  let prevDocData = prevDocSchema && (await buildGraphQLDocument({ | 
|  | 49 | +    ...prevDoc, | 
|  | 50 | +    source: prevFile, | 
|  | 51 | +    kind: FILE_KIND.TEXT, | 
|  | 52 | +    data: prevDocSchema, | 
|  | 53 | +  }, prevDoc)).data | 
|  | 54 | +  let currDocData = currDocSchema && (await buildGraphQLDocument({ | 
|  | 55 | +    ...currDoc, | 
|  | 56 | +    source: currFile, | 
|  | 57 | +    kind: FILE_KIND.TEXT, | 
|  | 58 | +    data: currDocSchema, | 
|  | 59 | +  }, currDoc)).data | 
| 29 | 60 | 
 | 
| 30 |  | -  if (previousOperation && !currentOperation) { | 
| 31 |  | -    currentOperation = getCopyWithEmptyOperations(previousOperation as GraphApiSchema) | 
|  | 61 | +  if (!prevDocData && currDocData) { | 
|  | 62 | +    prevDocData = getCopyWithEmptyOperations(currDocData) | 
|  | 63 | +  } | 
|  | 64 | +  if (prevDocData && !currDocData) { | 
|  | 65 | +    currDocData = getCopyWithEmptyOperations(prevDocData) | 
| 32 | 66 |   } | 
| 33 | 67 | 
 | 
| 34 |  | -  //todo think about normalize options | 
| 35 |  | -  const { diffs } = apiDiff( | 
| 36 |  | -    previousOperation, | 
| 37 |  | -    currentOperation, | 
|  | 68 | +  const { merged, diffs } = apiDiff( | 
|  | 69 | +    prevDocData, | 
|  | 70 | +    currDocData, | 
| 38 | 71 |     { | 
| 39 | 72 |       ...NORMALIZE_OPTIONS, | 
| 40 |  | -      mode: COMPARE_MODE_OPERATION, | 
|  | 73 | +      metaKey: DIFF_META_KEY, | 
|  | 74 | +      originsFlag: ORIGINS_SYMBOL, | 
| 41 | 75 |       normalizedResult: true, | 
| 42 |  | -      beforeSource: previous?.data, | 
| 43 |  | -      afterSource: current?.data, | 
| 44 | 76 |     }, | 
| 45 |  | -  ) | 
| 46 |  | -  return diffs | 
|  | 77 | +  ) as { merged: GraphApiSchema; diffs: Diff[] } | 
|  | 78 | + | 
|  | 79 | +  if (isEmpty(diffs)) { | 
|  | 80 | +    return { operationChanges: [], tags: new Set() } | 
|  | 81 | +  } | 
|  | 82 | + | 
|  | 83 | +  aggregateDiffsWithRollup(merged, DIFF_META_KEY, DIFFS_AGGREGATED_META_KEY) | 
|  | 84 | + | 
|  | 85 | +  const { currentGroup, previousGroup } = ctx | 
|  | 86 | + | 
|  | 87 | +  const tags = new Set<string>() | 
|  | 88 | +  const operationChanges: OperationChanges[] = [] | 
|  | 89 | + | 
|  | 90 | +  for (const type of GRAPHQL_TYPE_KEYS) { | 
|  | 91 | +    const operationsByType = merged[type] | 
|  | 92 | +    if (!operationsByType) { continue } | 
|  | 93 | + | 
|  | 94 | +    for (const operationKey of Object.keys(operationsByType)) { | 
|  | 95 | +      const operationId = slugify(`${GRAPHQL_TYPE[type]}-${operationKey}`) | 
|  | 96 | +      const methodData = operationsByType[operationKey] | 
|  | 97 | + | 
|  | 98 | +      const { current, previous } = operationsMap[operationId] ?? {} | 
|  | 99 | +      if (!current && !previous) { | 
|  | 100 | +        throw new Error(`Can't find the ${operationId} operation from documents pair ${prevDoc?.fileId} and ${currDoc?.fileId}`) | 
|  | 101 | +      } | 
|  | 102 | +      const operationChanged = Boolean(current && previous) | 
|  | 103 | +      const operationAddedOrRemoved = !operationChanged | 
|  | 104 | + | 
|  | 105 | +      let operationDiffs: Diff[] = [] | 
|  | 106 | +      if (operationChanged) { | 
|  | 107 | +        operationDiffs = [...(methodData as WithAggregatedDiffs<GraphApiOperation>)[DIFFS_AGGREGATED_META_KEY] ?? []] | 
|  | 108 | +      } | 
|  | 109 | +      if (operationAddedOrRemoved) { | 
|  | 110 | +        const operationAddedOrRemovedDiff = (merged[type] as WithDiffMetaRecord<Record<string, GraphApiOperation>>)[DIFF_META_KEY]?.[operationKey] | 
|  | 111 | +        operationAddedOrRemovedDiff && operationDiffs.push(operationAddedOrRemovedDiff) | 
|  | 112 | +      } | 
|  | 113 | + | 
|  | 114 | +      if (isEmpty(operationDiffs)) { | 
|  | 115 | +        continue | 
|  | 116 | +      } | 
|  | 117 | + | 
|  | 118 | +      operationChanges.push(createOperationChange(apiType, operationDiffs, previous, current, currentGroup, previousGroup)) | 
|  | 119 | +      getOperationTags(current ?? previous).forEach(tag => tags.add(tag)) | 
|  | 120 | +    } | 
|  | 121 | +  } | 
|  | 122 | + | 
|  | 123 | +  return { operationChanges, tags } | 
| 47 | 124 | } | 
| 48 | 125 | 
 | 
| 49 | 126 | function getCopyWithEmptyOperations(template: GraphApiSchema): GraphApiSchema { | 
|  | 
0 commit comments