Skip to content

Commit

Permalink
rename
Browse files Browse the repository at this point in the history
  • Loading branch information
pyramation committed May 17, 2024
1 parent 6c5b221 commit 8b8ea50
Show file tree
Hide file tree
Showing 3 changed files with 308 additions and 2 deletions.
214 changes: 214 additions & 0 deletions __tests__/__snapshots__/patch.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,217 @@
exports[`JSONSchemaPatch Operations should correctly apply schema modifications and match snapshot 1`] = `
{
"$defs": {
"asset": {
"additionalProperties": false,
"if": {
"properties": {
"type_asset": {
"enum": [
"erc20",
"cw20",
"snip20",
],
},
},
"required": [
"type_asset",
],
},
"properties": {
"address": {
"description": "[OPTIONAL] The address of the asset. Only required for type_asset : cw20, snip20",
"type": "string",
},
"base": {
"description": "The base unit of the asset. Must be in denom_units.",
"type": "string",
},
"coingecko_id": {
"description": "[OPTIONAL] The coingecko id to fetch asset data from coingecko v3 api. See https://api.coingecko.com/api/v3/coins/list",
"type": "string",
},
"denom_units": {
"items": {
"$ref": "#/$defs/denom_unit",
},
"minContains": 1,
"type": "array",
},
"deprecated": {
"description": "[OPTIONAL] Whether the asset has been deprecated for use. For readability, it is best to omit this property unless TRUE.",
"type": "boolean",
},
"description": {
"description": "[OPTIONAL] A short description of the asset",
"type": "string",
},
"display": {
"description": "The human friendly unit of the asset. Must be in denom_units.",
"type": "string",
},
"extended_description": {
"description": "[OPTIONAL] A long description of the asset",
"type": "string",
},
"ibc": {
"additionalProperties": false,
"description": "[OPTIONAL] IBC Channel between src and dst between chain",
"properties": {
"dst_channel": {
"type": "string",
},
"source_channel": {
"type": "string",
},
"source_denom": {
"type": "string",
},
},
"required": [
"source_channel",
"dst_channel",
"source_denom",
],
"type": "object",
},
"images": {
"items": {
"additionalProperties": false,
"properties": {
"image_sync": {
"$ref": "#/$defs/pointer",
},
"png": {
"format": "uri-reference",
"pattern": "^https://raw\\.githubusercontent\\.com/cosmos/chain-registry/master/(|testnets/|_non-cosmos/)[a-z0-9]+/images/.+\\.png$",
"type": "string",
},
"svg": {
"format": "uri-reference",
"pattern": "^https://raw\\.githubusercontent\\.com/cosmos/chain-registry/master/(|testnets/|_non-cosmos/)[a-z0-9]+/images/.+\\.svg$",
"type": "string",
},
"theme": {
"additionalProperties": false,
"minProperties": 1,
"properties": {
"circle": {
"type": "boolean",
},
"dark_mode": {
"type": "boolean",
},
"primary_color_hex": {
"pattern": "^#[0-9a-fA-F]{6}$",
"type": "string",
},
},
"type": "object",
},
},
"type": "object",
},
"minItems": 1,
"type": "array",
},
"keywords": {
"items": {
"type": "string",
},
"maxContains": 20,
"minContains": 1,
"type": "array",
},
"logo_URIs": {
"additionalProperties": false,
"properties": {
"png": {
"format": "uri-reference",
"pattern": "^https://raw\\.githubusercontent\\.com/cosmos/chain-registry/master/(|testnets/|_non-cosmos/)[a-z0-9]+/images/.+\\.png$",
"type": "string",
},
"svg": {
"format": "uri-reference",
"pattern": "^https://raw\\.githubusercontent\\.com/cosmos/chain-registry/master/(|testnets/|_non-cosmos/)[a-z0-9]+/images/.+\\.svg$",
"type": "string",
},
},
"type": "object",
},
"name": {
"description": "The project name of the asset. For example Bitcoin.",
"maxLength": 42,
"type": "string",
},
"newDescription": {
"description": "A new description property",
"type": "string",
},
"socials": {
"minProperties": 1,
"properties": {
"twitter": {
"format": "uri",
"type": "string",
},
"website": {
"format": "uri",
"type": "string",
},
},
"type": "object",
},
"traces": {
"description": "The origin of the asset, starting with the index, and capturing all transitions in form and location.",
"items": {
"anyOf": [
{
"$ref": "#/$defs/ibc_transition",
},
{
"$ref": "#/$defs/ibc_cw20_transition",
},
{
"$ref": "#/$defs/non_ibc_transition",
},
],
},
"minContains": 1,
"type": "array",
},
"type_asset": {
"default": "sdk.coin",
"description": "[OPTIONAL] The potential options for type of asset. By default, assumes sdk.coin",
"enum": [
"sdk.coin",
"cw20",
"erc20",
"ics20",
"snip20",
"snip25",
"sdk.factory",
"bitcoin-like",
"evm-base",
"svm-base",
"substrate",
"bitsong",
],
"type": "string",
},
},
"required": [
"denom_units",
"base",
"display",
"name",
],
"then": {
"required": [
"address",
],
},
"type": "object",
},
"denom_unit": {
"additionalProperties": false,
"properties": {
Expand Down Expand Up @@ -250,6 +461,9 @@ exports[`JSONSchemaPatch Operations should correctly apply schema modifications
"type": "string",
},
"assets": {
"items": {
"$ref": "#/$defs/asset",
},
"minContains": 1,
"type": "array",
},
Expand Down
64 changes: 64 additions & 0 deletions __tests__/path.rename-property.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import JSONSchemaPatch from '../src';

describe('JSONSchemaPatch - renameProperty', () => {
it('should rename a property and update required fields', () => {
const schema = {
properties: {
oldName: { type: "string" },
otherProp: { type: "number" }
},
required: ["oldName", "otherProp"]
};
const patcher = new JSONSchemaPatch(schema);

// Preparing operation to rename 'oldName' to 'newName'
patcher.prepareOperation({
op: 'renameProperty',
path: '/properties',
value: { oldName: 'oldName', newName: 'newName' }
});

// Applying all prepared operations
patcher.applyPatch();

// Expected schema after the operation
const expectedSchema = {
properties: {
newName: { type: "string" }, // 'oldName' should now be 'newName'
otherProp: { type: "number" }
},
required: ["newName", "otherProp"] // 'required' should be updated to reflect the new property name
};

// Asserting that the schema has been updated as expected
expect(schema).toEqual(expectedSchema);
});

it('should handle renaming a non-existent property gracefully', () => {
const schema = {
properties: {
someProp: { type: "string" }
},
required: ["someProp"]
};
const patcher = new JSONSchemaPatch(schema);

// Attempting to rename a non-existent property
patcher.prepareOperation({
op: 'renameProperty',
path: '/properties',
value: { oldName: 'nonExistent', newName: 'newName' }
});

// Applying all prepared operations
patcher.applyPatch();

// Expect the schema to remain unchanged as the property does not exist
expect(schema).toEqual({
properties: {
someProp: { type: "string" }
},
required: ["someProp"]
});
});
});
32 changes: 30 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { applyPatch, Operation } from 'fast-json-patch';

export interface JSONSchemaPatchOperation {
op: 'add' | 'remove' | 'replace' | 'addProperty' | 'removeProperty' | 'addDefinition' | 'removeDefinition';
op: 'add' | 'remove' | 'replace' | 'addProperty' | 'removeProperty' | 'renameProperty' | 'addDefinition' | 'removeDefinition';
path: string;
value?: any;
}
Expand Down Expand Up @@ -37,11 +37,13 @@ export class JSONSchemaPatch {
case 'removeProperty':
this.removeProperty(op.path, op.value);
break;
case 'renameProperty':
this.renameProperty(op.path, op.value.oldName, op.value.newName);
case 'addDefinition':
this.addDefinition(op.path, op.value);
break;
case 'removeDefinition':
this.removeDefinition(op.path);
this.removeDefinition(op.value);
break;
default:
// Standard operations will be processed later
Expand Down Expand Up @@ -135,6 +137,32 @@ export class JSONSchemaPatch {
applyPatch(this.schema, [{ op: 'remove', path: `${requiredPath}/${requiredIndex}` }]);
}
}

renameProperty(path: string, oldName: string, newName: string): void {
const propertyPath = `${path}/properties/${oldName}`;
const newPath = `${path}/properties/${newName}`;
const propertyValue = getValueAtPath(this.schema, propertyPath);
if (propertyValue) {
applyPatch(this.schema, [{ op: 'remove', path: propertyPath }]);
applyPatch(this.schema, [{ op: 'add', path: newPath, value: propertyValue }]);
this.updateRequiredField(path, oldName, newName);
}
}

private updateRequiredField(path: string, oldName: string, newName: string): void {
const requiredPath = `${path}/required`;
const requiredArray = getValueAtPath(this.schema, requiredPath);
if (requiredArray && requiredArray.includes(oldName)) {
const index = requiredArray.indexOf(oldName);
if (index !== -1) {
applyPatch(this.schema, [
{ op: 'remove', path: `${requiredPath}/${index}` },
{ op: 'add', path: `${requiredPath}/-`, value: newName }
]);
}
}
}

}

export default JSONSchemaPatch;

0 comments on commit 8b8ea50

Please sign in to comment.