Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 39 additions & 70 deletions v1-to-v2-data-migration/helpers/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,11 @@ function legacyHistoryItemToV2ActionType(
},
}
case 'DECLARATION_UPDATED': //TODO - check if this is correct
const update = transformCorrection(historyItem, eventType, declaration)
return {
type: 'DECLARE' as ActionType,
declaration: {},
declaration: update.output,
annotation: update.input,
}
default:
break
Expand All @@ -260,7 +262,7 @@ function legacyHistoryItemToV2ActionType(
status: 'Accepted',
type: 'REQUEST_CORRECTION' as ActionType,
declaration: correction.output,
annotation: { ...declaration, ...annotation, ...correction.input },
annotation: { ...annotation, ...correction.input },
requestId: historyItem.id,
}
case 'APPROVED_CORRECTION':
Expand Down Expand Up @@ -471,7 +473,7 @@ export function transform(
],
}

return postProcess(documents)
return postProcess(documents, declaration)
}

/**
Expand Down Expand Up @@ -505,84 +507,51 @@ function deepMerge(target: any, source: any): any {
return result
}

function postProcess(documents: TransformedDocument): TransformedDocument {
const correctionResolverKeys = Object.keys(correctionResolver)

// Step 1: Build a map of current declaration state at each action
// We start from the final declaration and work backwards
let currentDeclaration: Record<string, any> = {}

// Find the final declaration by merging all DECLARE/REGISTER/VALIDATE declarations
for (const action of documents.actions) {
if (
(action.type === 'DECLARE' ||
action.type === 'REGISTER' ||
action.type === 'VALIDATE') &&
action.declaration &&
Object.keys(action.declaration).length > 0
) {
currentDeclaration = deepMerge(currentDeclaration, action.declaration)
}
}

// Step 2: Process corrections in reverse order to reverse-engineer the original state
const corrections: Array<{ index: number; action: Action }> = []
function postProcess(
document: TransformedDocument,
currDeclaration: Record<string, any>
): TransformedDocument {
const resolverKeys = Object.keys({
...correctionResolver,
...declareResolver,
})
const hasKeys = (declaration: {} | null | undefined) =>
Object.keys(declaration || {}).length > 0
let previousDeclaration = currDeclaration

for (let i = 0; i < documents.actions.length; i++) {
if (documents.actions[i].type === 'REQUEST_CORRECTION') {
corrections.push({ index: i, action: documents.actions[i] })
}
}
const approvedCorrections = []
Copy link

Copilot AI Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The approvedCorrections array should have an explicit type annotation. Since it stores requestId values which can be string or undefined according to the Action interface, it should be typed as Array<string | undefined> or the push operation on line 528 should guard against undefined values.

Suggested change
const approvedCorrections = []
const approvedCorrections: Array<string | undefined> = []

Copilot uses AI. Check for mistakes.

// Process corrections from newest to oldest to reverse engineer
for (let i = corrections.length - 1; i >= 0; i--) {
const { action } = corrections[i]
const rev = document.actions.slice().reverse()

if (!action.annotation || !action.declaration) {
continue
for (const action of rev) {
if (action.type === 'APPROVE_CORRECTION') {
approvedCorrections.push(action.requestId)
}

// Filter out correctionResolver metadata fields from annotation
const filteredAnnotation = Object.fromEntries(
Object.entries(action.annotation).filter(
([key]) => !correctionResolverKeys.includes(key)
const declaration = action.declaration || {}
const annotation = Object.fromEntries(
Object.entries(action.annotation || {}).filter(
([key]) => !resolverKeys.includes(key)
)
)

// First, reverse the correction: for each field in the correction's declaration,
// replace the current state with the input value (from filteredAnnotation)
for (const key of Object.keys(action.declaration)) {
if (filteredAnnotation.hasOwnProperty(key)) {
currentDeclaration[key] = filteredAnnotation[key]
if (hasKeys(declaration)) {
if (action.type === 'REQUEST_CORRECTION') {
if (approvedCorrections.includes(action.requestId)) {
previousDeclaration = deepMerge(previousDeclaration, annotation)
action.annotation = previousDeclaration
}
continue
}
action.declaration = previousDeclaration
if (hasKeys(annotation)) {
previousDeclaration = deepMerge(previousDeclaration, annotation)
action.annotation = previousDeclaration
}
}

// Now set the annotation to the reversed state (which is the state BEFORE this correction)
const newAnnotation = {
...currentDeclaration,
...Object.fromEntries(
Object.entries(action.annotation).filter(([key]) =>
correctionResolverKeys.includes(key)
)
),
}

action.annotation = newAnnotation
}

// Step 3: Update the base DECLARE/REGISTER/VALIDATE actions with the reverse-engineered state
// Find the first action with a non-empty declaration
for (const action of documents.actions) {
if (
(action.type === 'DECLARE' ||
action.type === 'REGISTER' ||
action.type === 'VALIDATE') &&
action.declaration &&
Object.keys(action.declaration).length > 0
) {
action.declaration = { ...currentDeclaration }
}
}
document.actions = rev.reverse()

return documents
return document
}
Loading