Skip to content

Commit

Permalink
Attempt to use existing JSON Patch library to apply patches
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardspec committed Feb 3, 2025
1 parent 95de54d commit af4fca8
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 82 deletions.
93 changes: 12 additions & 81 deletions lib/entity/LoadedAsset.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const { config, util } = require( '..' ),
lodash = require( 'lodash' );
jsonPatch = require( 'fast-json-patch' );

/**
* Represents one asset (parsed JSON file from either vanilla or the mod). Used in AssetDatabase.
Expand Down Expand Up @@ -106,95 +106,26 @@ class LoadedAsset {
* @param {Object} data
*/
applyPatchInstructions( patch, data ) {
// This is set to true if we find "test" operation that tells us to ignore the rest of this patch.
var patchSkipped = false;

patch.forEach( ( instruction ) => {
if ( patchSkipped ) {
// This instruction must be ignored, because preceding "test" instruction says so.
return;
}

for ( let instruction of patch ) {
if ( Array.isArray( instruction ) ) {
// This is an array of instructions, not a single instruction.
// Handle this recursively.
this.applyPatchInstructions( instruction, data );
return;
continue;
}

var op = instruction.op,
value = instruction.value;

if ( op === 'copy' || op === 'move' ) {
// These operations are not supported.
// They are also not used in the mod.
return;
}

if ( instruction.path === '/-' && op === 'add' ) {
// Special case: the entire data is an array, and we are adding new element to the bottom of it.
data.push( value );
return;
}

var objectPath = instruction.path.slice( 1 ).split( '/' );
if ( op === 'add' ) {
// Handle add operations to: 1) "/some-array/-" (add to the end of array)
// 2) "/some-array/123" (add the new element BEFORE what is currently element #123).
var possiblyIndex = objectPath.pop();

if ( possiblyIndex !== '-' && Number.isNaN( Number( possiblyIndex ) ) ) {
// Not an index. We don't consider this an "add to array" operation,
// instead this is "add new key-value" operation.
objectPath.push( possiblyIndex );
} else {
var currentArray = ( lodash.get( data, objectPath ) || [] );

if ( possiblyIndex === '-' ) {
// Pseudo-value "-" means "add after the last element of array".
// Here "value" is the new element that we are adding.
value = currentArray.concat( [ value ] );
} else {
// Add "value" to currentArray BEFORE currentArray[possiblyIndex]
var before = currentArray.slice( 0, possiblyIndex ),
after = currentArray.slice( possiblyIndex );

value = before.concat( [ value ] ).concat( after );
}

op = 'replace';
try {
jsonPatch.applyOperation( data, instruction );
} catch ( e ) {
if ( e.name === 'TEST_OPERATION_FAILED' ) {
// This "test" instruction told us to skip all instructions after it.
return;
}
}

if ( op === 'replace' || op === 'add' ) {
lodash.set( data, objectPath, value );
} else if ( op === 'remove' ) {
// Carefully delete the element from Array/Object.
// Note: while lodash.unset() would be enough for objects, using it to delete keys from arrays
// would create holes in the array, resulting in incorrect application of further patches.
var index = objectPath.pop();
var list = lodash.get( data, objectPath );

if ( Array.isArray( list ) ) {
// Removing numeric index from array.
list.splice( index, 1 );
lodash.set( list, objectPath );
} else {
// Unsetting property of object.
objectPath.push( index );
lodash.unset( data, objectPath );
}
} else if ( op === 'test' ) {
var fieldExists = lodash.has( data, objectPath );
if ( fieldExists && instruction.inverse ) {
// This patch shouldn't be applied if the field exists.
patchSkipped = true;
} else if ( !fieldExists && !instruction.inverse ) {
// This patch shouldn't be applied, because the field doesn't exist.
patchSkipped = true;
}
// FIXME: there are errors in existing assets/patches.
util.log( '[error] Patch error: ' + this.filename + ': ' + e.name + ': ' + JSON.stringify( instruction ) );
}
} );
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"cli-progress": "^3.12.0",
"deepmerge": "^4.3.1",
"diff": "^7.0.0",
"fast-json-patch": "^3.1.1",
"fs": "^0.0.2",
"lodash": "^4.17.21",
"minimist": "^1.2.8",
"mwbot": "^2.1.3",
"picomatch": "^4.0.2",
Expand Down

0 comments on commit af4fca8

Please sign in to comment.