Skip to content

Commit e44555b

Browse files
committed
feat: aggregate operation diffs
1 parent 5d717af commit e44555b

File tree

8 files changed

+98
-6
lines changed

8 files changed

+98
-6
lines changed

src/api.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ import {
1515
SPEC_TYPE_OPEN_API_31,
1616
SpecType,
1717
} from '@netcracker/qubership-apihub-api-unifier'
18-
import { DEFAULT_NORMALIZED_RESULT, DEFAULT_OPTION_DEFAULTS_META_KEY, DEFAULT_OPTION_ORIGINS_META_KEY, DIFF_META_KEY } from './core'
18+
import {
19+
DIFFS_AGGREGATED_META_KEY,
20+
DEFAULT_NORMALIZED_RESULT,
21+
DEFAULT_OPTION_DEFAULTS_META_KEY,
22+
DEFAULT_OPTION_ORIGINS_META_KEY,
23+
DIFF_META_KEY,
24+
} from './core'
1925

2026
export const COMPARE_ENGINES_MAP: Record<SpecType, CompareEngine> = {
2127
[SPEC_TYPE_JSON_SCHEMA_04]: compareJsonSchema(SPEC_TYPE_JSON_SCHEMA_04),
@@ -41,6 +47,7 @@ export function apiDiff(before: unknown, after: unknown, options: CompareOptions
4147
metaKey: DIFF_META_KEY,
4248
defaultsFlag: DEFAULT_OPTION_DEFAULTS_META_KEY,
4349
originsFlag: DEFAULT_OPTION_ORIGINS_META_KEY,
50+
diffsAggregatedFlag: DIFFS_AGGREGATED_META_KEY,
4451
compareScope: COMPARE_SCOPE_ROOT,
4552
mergedJsoCache: createEvaluationCacheService(),
4653
diffUniquenessCache: createEvaluationCacheService(),

src/core/compare.ts

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { anyArrayKeys, getNodeRules, JsonPath, syncCrawl, SyncCrawlHook } from '@netcracker/qubership-apihub-json-crawl'
1+
import {
2+
anyArrayKeys,
3+
getNodeRules,
4+
JsonPath,
5+
syncClone,
6+
syncCrawl,
7+
SyncCrawlHook,
8+
} from '@netcracker/qubership-apihub-json-crawl'
29

310
import {
411
ChainItem,
@@ -16,6 +23,7 @@ import { deepEqual } from 'fast-equals'
1623
import {
1724
AdapterContext,
1825
AdapterResolver,
26+
AGGREGATE_DIFFS_HERE_RULE,
1927
CompareContext,
2028
CompareResult,
2129
CompareRule,
@@ -473,7 +481,7 @@ export const compare = (before: unknown, after: unknown, options: InternalCompar
473481
return {
474482
diffs: rawDiffs,
475483
ownerDiffEntry: undefined,
476-
merged,
484+
merged: aggregateDiffs(merged, options),
477485
}
478486
}
479487
const diffFlags = Symbol('diffs')
@@ -491,8 +499,66 @@ export const compare = (before: unknown, after: unknown, options: InternalCompar
491499
return {
492500
diffs: denormalizedDiffs,
493501
ownerDiffEntry: undefined,
494-
merged,
502+
merged: merged,
503+
}
504+
}
505+
506+
export function aggregateDiffs(merged: unknown, options: InternalCompareOptions): unknown {
507+
let activeDataCycleGuard: Set<unknown> = new Set()
508+
509+
const collectCurrentNodeDiffs = (value: Record<string | symbol, unknown>, operationDiffs: Set<Diff>) => {
510+
if (options.metaKey in value) {
511+
const diffs = value[options.metaKey] as Record<PropertyKey, unknown> | undefined
512+
for (const key in diffs) {
513+
// @ts-ignore
514+
if (operationDiffs) {
515+
// @ts-ignore
516+
operationDiffs.add(diffs[key])
517+
}
518+
}
519+
}
495520
}
521+
522+
syncClone(
523+
merged,
524+
[
525+
({ key, value, state, rules }) => {
526+
if (!isObject(value)) {
527+
return { value }
528+
}
529+
if (typeof key === 'symbol') {
530+
// return { value }
531+
return { done: true }
532+
}
533+
if (activeDataCycleGuard.has(value)) {
534+
return { done: true }
535+
}
536+
activeDataCycleGuard.add(value)
537+
538+
// @ts-ignore
539+
collectCurrentNodeDiffs(value, state.operationDiffs)
540+
541+
if (rules && AGGREGATE_DIFFS_HERE_RULE in rules) {
542+
activeDataCycleGuard = new Set()
543+
const operationDiffs = new Set<Diff>()
544+
collectCurrentNodeDiffs(value, operationDiffs)
545+
return {
546+
value,
547+
state: { ...state, operationDiffs },
548+
exitHook: () => {
549+
value[options.diffsAggregatedFlag] = operationDiffs
550+
},
551+
}
552+
}
553+
return { value }
554+
},
555+
],
556+
{
557+
rules: options.rules
558+
},
559+
)
560+
561+
return merged
496562
}
497563

498564
export const nestedCompare = (before: unknown, after: unknown, options: InternalCompareOptions): CompareResult => {

src/core/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ClassifyRule } from '../types'
22

33
export const DIFF_META_KEY = Symbol('$diff')
4+
export const DIFFS_AGGREGATED_META_KEY = Symbol('$diffs-aggregated')
45
export const DEFAULT_NORMALIZED_RESULT = false
56
export const DEFAULT_OPTION_DEFAULTS_META_KEY = Symbol('$defaults')
67
export const DEFAULT_OPTION_ORIGINS_META_KEY = Symbol('$origins')

src/graphapi/graphapi.rules.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
deepEqualsUniqueItemsArrayMappingResolver
1919
} from '../core'
2020
import { resolveSchemaDescriptionTemplates } from '../jsonSchema'
21-
import type { ClassifyRule, CompareRules, DescriptionTemplates, MappingResolver } from '../types'
21+
import { AGGREGATE_DIFFS_HERE_RULE, ClassifyRule, CompareRules, DescriptionTemplates, MappingResolver } from '../types'
2222
import { graphApiSchemaAdapter as graphApiTypeAdapter, removeNotCorrectlySupportedInterfacesAdapter } from './graphapi.adapter'
2323
import { COMPARE_SCOPE_COMPONENTS, COMPARE_SCOPE_DIRECTIVE_USAGES, COMPARE_SCOPE_ARGS, COMPARE_SCOPE_OUTPUT } from './graphapi.const'
2424
import { complexTypeCompareResolver } from './graphapi.resolver'
@@ -335,18 +335,21 @@ export const graphApiRules = (): CompareRules => {
335335
'/queries': {
336336
'/*': {
337337
...methodRules,
338+
[AGGREGATE_DIFFS_HERE_RULE]: true,
338339
$: addNonBreaking
339340
},
340341
},
341342
'/mutations': {
342343
'/*': {
343344
...methodRules,
345+
[AGGREGATE_DIFFS_HERE_RULE]: true,
344346
$: addNonBreaking
345347
},
346348
},
347349
'/subscriptions': {
348350
'/*': {
349351
...methodRules,
352+
[AGGREGATE_DIFFS_HERE_RULE]: true,
350353
$: addNonBreaking
351354
}
352355
},

src/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
export { COMPARE_MODE_DEFAULT, COMPARE_MODE_OPERATION } from './types'
22

33
export {
4-
ClassifierType, DiffAction, DIFF_META_KEY, breaking, nonBreaking, unclassified, annotation, deprecated, risky,
4+
ClassifierType,
5+
DiffAction,
6+
DIFF_META_KEY,
7+
DIFFS_AGGREGATED_META_KEY,
8+
breaking,
9+
nonBreaking,
10+
unclassified,
11+
annotation,
12+
deprecated,
13+
risky,
514
} from './core'
615

716
export { apiDiff } from './api'

src/openapi/openapi3.rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
deepEqualsUniqueItemsArrayMappingResolver,
3131
} from '../core'
3232
import {
33+
AGGREGATE_DIFFS_HERE_RULE,
3334
COMPARE_MODE_OPERATION,
3435
CompareRules,
3536
DescriptionTemplates,
@@ -345,6 +346,7 @@ export const openApi3Rules = (options: OpenApi3RulesOptions): CompareRules => {
345346

346347
const operationRule: CompareRules = {
347348
$: [nonBreaking, breaking, unclassified],
349+
[AGGREGATE_DIFFS_HERE_RULE]: true,
348350
'/callbacks': {
349351
'/*': {
350352
//no support?

src/types/compare.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ export interface CompareOptions extends Omit<NormalizeOptions, 'source'> {
8888
mode?: CompareMode
8989
normalizedResult?: boolean
9090
metaKey?: symbol // metakey for merge changes
91+
diffsAggregatedFlag?: symbol
9192
beforeSource?: unknown
9293
afterSource?: unknown
9394
onCreateDiffError?: (message: string, diff: Diff, ctx: CompareContext) => void
@@ -101,6 +102,7 @@ export interface StrictCompareOptions extends Omit<CompareOptions, 'defaultsFlag
101102
metaKey: symbol
102103
defaultsFlag: symbol,
103104
originsFlag: symbol,
105+
diffsAggregatedFlag: symbol,
104106
compareScope: CompareScope
105107
mergedJsoCache: EvaluationCacheService
106108
diffUniquenessCache: EvaluationCacheService

src/types/rules.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export const DIFF_DESCRIPTION_PARAM_CALCULATOR_RULE = 'descriptionParamCalculato
8282
export const IGNORE_DIFFERENCE_IN_KEYS_RULE = 'ignoreKeyDifference'
8383
//not happy to do this, but introduce covariant support on core level too hard. If you can change it, feel free
8484
export const START_NEW_COMPARE_SCOPE_RULE = 'newCompareScope'
85+
export const AGGREGATE_DIFFS_HERE_RULE = 'aggregateDiffsHere'
8586

8687
export type CompareRule = {
8788
[CLASSIFIER_RULE]?: ClassifyRule // classifier for current node
@@ -92,6 +93,7 @@ export type CompareRule = {
9293
[DIFF_DESCRIPTION_PARAM_CALCULATOR_RULE]?: DiffTemplateParamsCalculator // rule for description calculation
9394
[IGNORE_DIFFERENCE_IN_KEYS_RULE]?: boolean // rule for ignore keys as values, it is relevant for arrays as sets
9495
[START_NEW_COMPARE_SCOPE_RULE]?: CompareScope // rule for star a new scope
96+
[AGGREGATE_DIFFS_HERE_RULE]?: boolean
9597
}
9698

9799
export type CompareRules = CrawlRules<CompareRule>

0 commit comments

Comments
 (0)