@@ -16,6 +16,8 @@ import { deepEqual } from 'fast-equals'
1616import {
1717 AdapterContext ,
1818 AdapterResolver ,
19+ API_COMPATIBILITY_KIND_BACKWARD_COMPATIBLE ,
20+ ApiCompatibilityKind ,
1921 CompareContext ,
2022 CompareResult ,
2123 CompareRule ,
@@ -75,6 +77,7 @@ export const createContext = (data: ContextInput, options: InternalCompareOption
7577 rules,
7678 compareScope,
7779 parentContext,
80+ apiCompatibilityScope,
7881 } = data
7982 return {
8083 parentContext : parentContext ,
@@ -84,6 +87,7 @@ export const createContext = (data: ContextInput, options: InternalCompareOption
8487 mergeKey,
8588 rules,
8689 options,
90+ apiCompatibilityScope : apiCompatibilityScope ,
8791 }
8892}
8993
@@ -92,6 +96,7 @@ export const createChildContext = (
9296 mergedKey : PropertyKey ,
9397 beforeChildKey : PropertyKey | undefined ,
9498 afterChildKey : PropertyKey | undefined ,
99+ apiCompatibilityScope : ApiCompatibilityKind = ctx . apiCompatibilityScope ,
95100) : CompareContext => {
96101 const { before, after, rules, options, scope } = ctx
97102 let beforeContext : NodeContext
@@ -133,6 +138,7 @@ export const createChildContext = (
133138 ) ?? { } ,
134139 options,
135140 scope : scope ,
141+ apiCompatibilityScope : apiCompatibilityScope ,
136142 }
137143}
138144
@@ -156,7 +162,19 @@ const cleanUpRecursive = (ctx: NodeContext): NodeContext => {
156162}
157163
158164export const getOrCreateChildDiffAdd = ( diffUniquenessCache : EvaluationCacheService , childCtx : CompareContext ) => {
159- const diff = diffUniquenessCache . cacheEvaluationResultByFootprint < [ unknown , string , CompareScope , typeof DiffAction . add ] , DiffAdd > ( [ childCtx . after . value , buildPathsIdentifier ( childCtx . after . declarativePaths ) , childCtx . scope , DiffAction . add ] , ( ) => {
165+ const diff = diffUniquenessCache . cacheEvaluationResultByFootprint < [
166+ unknown ,
167+ string ,
168+ CompareScope ,
169+ typeof DiffAction . add ,
170+ ApiCompatibilityKind
171+ ] , DiffAdd > ( [
172+ childCtx . after . value ,
173+ buildPathsIdentifier ( childCtx . after . declarativePaths ) ,
174+ childCtx . scope ,
175+ DiffAction . add ,
176+ childCtx . apiCompatibilityScope ,
177+ ] , ( ) => {
160178 return diffFactory . added ( childCtx )
161179 } , { } as DiffAdd , ( result , guard ) => {
162180 Object . assign ( guard , result )
@@ -167,7 +185,19 @@ export const getOrCreateChildDiffAdd = (diffUniquenessCache: EvaluationCacheServ
167185}
168186
169187export const getOrCreateChildDiffRemove = ( diffUniquenessCache : EvaluationCacheService , childCtx : CompareContext ) => {
170- const diff = diffUniquenessCache . cacheEvaluationResultByFootprint < [ unknown , string , CompareScope , typeof DiffAction . remove ] , DiffRemove > ( [ childCtx . before . value , buildPathsIdentifier ( childCtx . before . declarativePaths ) , childCtx . scope , DiffAction . remove ] , ( ) => {
188+ const diff = diffUniquenessCache . cacheEvaluationResultByFootprint < [
189+ unknown ,
190+ string ,
191+ CompareScope ,
192+ typeof DiffAction . remove ,
193+ ApiCompatibilityKind
194+ ] , DiffRemove > ( [
195+ childCtx . before . value ,
196+ buildPathsIdentifier ( childCtx . before . declarativePaths ) ,
197+ childCtx . scope ,
198+ DiffAction . remove ,
199+ childCtx . apiCompatibilityScope ,
200+ ] , ( ) => {
171201 return diffFactory . removed ( childCtx )
172202 } , { } as DiffRemove , ( result , guard ) => {
173203 Object . assign ( guard , result )
@@ -201,9 +231,8 @@ const adaptValues = (beforeJso: JsonNode, beforeKey: PropertyKey, afterJso: Json
201231 } )
202232 return [ beforeValueAdapted , afterValueAdapted ]
203233}
204-
205234const useMergeFactory = ( onDiff : DiffCallback , options : InternalCompareOptions ) : SyncCrawlHook < MergeState , CompareRule > => {
206- const { metaKey } = options
235+ const { metaKey, apiCompatibilityScopeFunction } = options
207236 const diffs : Set < Diff > = new Set ( )
208237 const addDiff : ( diff : Diff ) => void = ( diff ) => {
209238 const oldSize = diffs . size
@@ -218,6 +247,7 @@ const useMergeFactory = (onDiff: DiffCallback, options: InternalCompareOptions):
218247 compare,
219248 mapping,
220249 ignoreKeyDifference,
250+ syntheticDiffs : mappingSyntheticDiffsPostProcessor ,
221251 newCompareScope,
222252 } = rules
223253 const {
@@ -229,6 +259,7 @@ const useMergeFactory = (onDiff: DiffCallback, options: InternalCompareOptions):
229259 diffUniquenessCache,
230260 createdMergedJso,
231261 compareScope,
262+ apiCompatibilityScope : parentApiCompatibilityScope ,
232263 } = state
233264
234265 if ( typeof unsafeKey === 'symbol' ) {
@@ -252,6 +283,8 @@ const useMergeFactory = (onDiff: DiffCallback, options: InternalCompareOptions):
252283 afterValueAdapted ,
253284 ] = adaptValues ( beforeJso , beforeKey , afterJso , afterKey , adapter , options )
254285
286+ const computedApiCompatibilityScope = apiCompatibilityScopeFunction ?.( crawlContext . path , beforeValueAdapted , afterValueAdapted ) ?? parentApiCompatibilityScope
287+
255288 const ctx = createContext ( {
256289 ...state ,
257290 beforeValue : beforeValueAdapted ,
@@ -261,12 +294,27 @@ const useMergeFactory = (onDiff: DiffCallback, options: InternalCompareOptions):
261294 mergeKey,
262295 rules,
263296 compareScope : newCompareScope ?? compareScope ,
297+ apiCompatibilityScope : computedApiCompatibilityScope ,
264298 } , options )
265299
266300 const beforeDeclarativePathsId = buildPathsIdentifier ( cleanUpRecursive ( ctx . before ) . declarativePaths )
267301 const afterDeclarativePathsId = buildPathsIdentifier ( cleanUpRecursive ( ctx . after ) . declarativePaths )
268302
269- const reuseResult : ReusableMergeResult = mergedJsoCache . cacheEvaluationResultByFootprint < [ typeof ctx . before . value , typeof ctx . after . value , typeof beforeDeclarativePathsId , typeof afterDeclarativePathsId , CompareScope ] , ReusableMergeResult > ( [ ctx . before . value , ctx . after . value , beforeDeclarativePathsId , afterDeclarativePathsId , ctx . scope ] , ( [ beforeValue , afterValue ] ) => {
303+ const reuseResult : ReusableMergeResult = mergedJsoCache . cacheEvaluationResultByFootprint < [
304+ typeof ctx . before . value ,
305+ typeof ctx . after . value ,
306+ typeof beforeDeclarativePathsId ,
307+ typeof afterDeclarativePathsId ,
308+ CompareScope ,
309+ ApiCompatibilityKind
310+ ] , ReusableMergeResult > ( [
311+ ctx . before . value ,
312+ ctx . after . value ,
313+ beforeDeclarativePathsId ,
314+ afterDeclarativePathsId ,
315+ ctx . scope ,
316+ computedApiCompatibilityScope ,
317+ ] , ( [ beforeValue , afterValue ] ) => {
270318 if ( ! ignoreKeyDifference && beforeKey !== afterKey ) {
271319 const diffEntry = createDiffEntry ( ctx , diffFactory . renamed ( ctx ) )
272320 addDiff ( diffEntry . diff )
@@ -291,11 +339,17 @@ const useMergeFactory = (onDiff: DiffCallback, options: InternalCompareOptions):
291339 if ( isObject ( beforeValue ) && isObject ( afterValue ) ) {
292340 const mergedJsoValue : JsonNode = isArray ( beforeValue ) ? [ ] as JsonNode < number > : { } as JsonNode < string | symbol >
293341 const mapKeys = mapping ?? ( isArray ( beforeValue ) ? arrayMappingResolver : objectMappingResolver )
342+ const mappingData = mapKeys ( beforeValue as any , afterValue as any , ctx )
343+
344+ // Adding synthetic diffs if necessary
345+ mappingSyntheticDiffsPostProcessor ?.( mappingData , beforeValue , afterValue )
346+
294347 const {
295348 added : addedKeys ,
296349 removed : removedKeys ,
297350 mapped : mappedKeys ,
298- } = mapKeys ( beforeValue as any , afterValue as any , ctx )
351+ } = mappingData
352+
299353 const jsoDiffEntries : DiffEntry < Diff > [ ] = [ ]
300354 const keyToRemove = removedKeys
301355 . filter ( key => ! isDefaultValue ( beforeValue , key , options . defaultsFlag ) )
@@ -310,13 +364,15 @@ const useMergeFactory = (onDiff: DiffCallback, options: InternalCompareOptions):
310364 once = true
311365
312366 keyToRemove . forEach ( ( keyToBefore ) => {
313- const childCtx = createChildContext ( ctx , keyToBefore , keyToBefore , undefined )
367+ const removalBwc = apiCompatibilityScopeFunction ?.( [ ...crawlContext . path , keyToBefore ] , beforeValue [ keyToBefore ] ) || computedApiCompatibilityScope
368+ const childCtx = createChildContext ( ctx , keyToBefore , keyToBefore , undefined , removalBwc )
314369 jsoDiffEntries . push ( getOrCreateChildDiffRemove ( diffUniquenessCache , childCtx ) )
315370 } )
316371
317372 keysToAdd . forEach ( ( keyInAfter ) => {
373+ const additionBwc = apiCompatibilityScopeFunction ?.( [ ...crawlContext . path , keyInAfter ] , undefined , afterJso [ keyInAfter ] ) || computedApiCompatibilityScope
318374 const keyInMerge = isArray ( mergedJsoValue ) ? mergedJsoValue . length : keyInAfter
319- const childCtx = createChildContext ( ctx , keyInMerge , undefined , keyInAfter )
375+ const childCtx = createChildContext ( ctx , keyInMerge , undefined , keyInAfter , additionBwc )
320376 jsoDiffEntries . push ( getOrCreateChildDiffAdd ( diffUniquenessCache , childCtx ) )
321377 mergedJsoValue [ keyInMerge ] = afterValue [ keyInAfter ]
322378 } )
@@ -363,6 +419,7 @@ const useMergeFactory = (onDiff: DiffCallback, options: InternalCompareOptions):
363419 afterJso : afterValueAdapted as JsonNode /*safe cause it only happens for object*/ ,
364420 mergedJso : mergedValue ,
365421 compareScope : newCompareScope ?? compareScope ,
422+ apiCompatibilityScope : computedApiCompatibilityScope ,
366423 }
367424 return { value : reuseResult . nextValue , state : childState , exitHook : reuseResult . exitHook }
368425 } else {
@@ -532,6 +589,8 @@ const compareInternal = (before: unknown, after: unknown, onDiff: DiffCallback,
532589 const beforeRootJso = root . before
533590 const afterRootJso = root . after
534591
592+ const apiCompatibilityScope = options ?. apiCompatibilityScopeFunction ?.( ) || API_COMPATIBILITY_KIND_BACKWARD_COMPATIBLE
593+
535594 if ( ! isObject ( beforeRootJso ) || ! isObject ( afterRootJso ) ) {
536595 // TODO
537596 throw new Error ( 'Not ready to compare primitive' )
@@ -548,6 +607,7 @@ const compareInternal = (before: unknown, after: unknown, onDiff: DiffCallback,
548607 diffUniquenessCache : options . diffUniquenessCache ,
549608 createdMergedJso : options . createdMergedJso ,
550609 compareScope : options . compareScope ,
610+ apiCompatibilityScope : apiCompatibilityScope ,
551611 }
552612 syncCrawl < MergeState , CompareRule > ( before , [ hook ] , { state : rootState , rules : options . rules } )
553613 return root . merged [ JSO_ROOT ]
0 commit comments