Skip to content

Commit

Permalink
transformTest for valid props
Browse files Browse the repository at this point in the history
  • Loading branch information
pyramation committed May 18, 2024
1 parent 7b188b6 commit ced0f45
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 33 deletions.
4 changes: 2 additions & 2 deletions __tests__/__snapshots__/utils.chain.remove.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ exports[`JSONSchemaPatch transformer w excludes 1`] = `
"apis": {
"additionalProperties": false,
"properties": {
"evm-http-jsonrpc": {
"evmHttpJsonrpc": {
"items": {
"$ref": "#/$defs/endpoint",
},
Expand All @@ -157,7 +157,7 @@ exports[`JSONSchemaPatch transformer w excludes 1`] = `
},
"type": "array",
},
"grpc-web": {
"grpcWeb": {
"items": {
"$ref": "#/$defs/endpoint",
},
Expand Down
20 changes: 18 additions & 2 deletions __tests__/__snapshots__/utils.chain.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ exports[`JSONSchemaPatch transformer 1`] = `
"apis": {
"additionalProperties": false,
"properties": {
"evm-http-jsonrpc": {
"evmHttpJsonrpc": {
"items": {
"$ref": "#/$defs/endpoint",
},
Expand All @@ -157,7 +157,7 @@ exports[`JSONSchemaPatch transformer 1`] = `
},
"type": "array",
},
"grpc-web": {
"grpcWeb": {
"items": {
"$ref": "#/$defs/endpoint",
},
Expand Down Expand Up @@ -1003,6 +1003,22 @@ exports[`createJSONSchemaPatchOperations 1`] = `
"oldName": "persistent_peers",
},
},
{
"op": "renameProperty",
"path": "/properties/apis",
"value": {
"newName": "grpcWeb",
"oldName": "grpc-web",
},
},
{
"op": "renameProperty",
"path": "/properties/apis",
"value": {
"newName": "evmHttpJsonrpc",
"oldName": "evm-http-jsonrpc",
},
},
{
"op": "renameProperty",
"path": "/$defs/explorer",
Expand Down
13 changes: 11 additions & 2 deletions __tests__/utils.assetlist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ import assetList from '../__fixtures__/assetlist.schema.json';
import { createJSONSchemaPatchOperations, findAllProps } from '../src/utils';
import JSONSchemaPatch from '../src';

// FROM schema-typescript
// // Determine if the key is a valid JavaScript identifier

// Determine if the key is a valid JavaScript-like identifier, allowing internal hyphens
function isValidIdentifierCamelized(key: string) {
return /^[$A-Z_][0-9A-Z_$\-]*$/i.test(key) && !/^[0-9]+$/.test(key) && !/^-/.test(key);
}

// FROM strfy-js
function camelCaseTransform(key: string): string {
return key.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : '');
}
Expand All @@ -13,13 +22,13 @@ it('findAllProps', () => {


it('createJSONSchemaPatchOperations', () => {
expect(createJSONSchemaPatchOperations(findAllProps(assetList), camelCaseTransform)).toMatchSnapshot();
expect(createJSONSchemaPatchOperations(findAllProps(assetList), camelCaseTransform, isValidIdentifierCamelized)).toMatchSnapshot();
})


it('JSONSchemaPatch transformer', () => {
const patcher = new JSONSchemaPatch(assetList);
patcher.transform(camelCaseTransform);
patcher.transform(camelCaseTransform, isValidIdentifierCamelized);
patcher.applyPatch();
expect(patcher.schema).toMatchSnapshot();
})
12 changes: 10 additions & 2 deletions __tests__/utils.chain.remove.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,27 @@
import chain from '../__fixtures__/chain.schema.json';
import JSONSchemaPatch from '../src';

// FROM schema-typescript
// // Determine if the key is a valid JavaScript identifier

// Determine if the key is a valid JavaScript-like identifier, allowing internal hyphens
function isValidIdentifierCamelized(key: string) {
return /^[$A-Z_][0-9A-Z_$\-]*$/i.test(key) && !/^[0-9]+$/.test(key) && !/^-/.test(key);
}

// FROM strfy-js
function camelCaseTransform(key: string): string {
return key.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : '');
}


it('JSONSchemaPatch transformer w excludes', () => {
const patcher = new JSONSchemaPatch(chain);
patcher.prepareOperation({
op: 'remove',
path: '/properties/images/items/properties/image_sync'
});
// patcher.applyPatch();
patcher.transform(camelCaseTransform);
patcher.transform(camelCaseTransform, isValidIdentifierCamelized);
patcher.applyPatch();
expect(patcher.schema).toMatchSnapshot();
})
14 changes: 12 additions & 2 deletions __tests__/utils.chain.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,32 @@ import chain from '../__fixtures__/chain.schema.json';
import { createJSONSchemaPatchOperations, findAllProps } from '../src/utils';
import JSONSchemaPatch from '../src';

// FROM schema-typescript
// // Determine if the key is a valid JavaScript identifier

// Determine if the key is a valid JavaScript-like identifier, allowing internal hyphens
function isValidIdentifierCamelized(key: string) {
return /^[$A-Z_][0-9A-Z_$\-]*$/i.test(key) && !/^[0-9]+$/.test(key) && !/^-/.test(key);
}

// FROM strfy-js
function camelCaseTransform(key: string): string {
return key.replace(/[-_\s]+(.)?/g, (_, c) => c ? c.toUpperCase() : '');
}


it('findAllProps', () => {
expect(findAllProps(chain)).toMatchSnapshot();
})


it('createJSONSchemaPatchOperations', () => {
expect(createJSONSchemaPatchOperations(findAllProps(chain), camelCaseTransform)).toMatchSnapshot();
expect(createJSONSchemaPatchOperations(findAllProps(chain), camelCaseTransform, isValidIdentifierCamelized)).toMatchSnapshot();
})

it('JSONSchemaPatch transformer', () => {
const patcher = new JSONSchemaPatch(chain);
patcher.transform(camelCaseTransform);
patcher.transform(camelCaseTransform, isValidIdentifierCamelized);
patcher.applyPatch();
expect(patcher.schema).toMatchSnapshot();
})
6 changes: 3 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { applyPatch, Operation } from 'fast-json-patch';
import { createJSONSchemaPatchOperations, dirname, findAllProps, TransformFunction } from './utils';
import { BooleanFunction, createJSONSchemaPatchOperations, dirname, findAllProps, TransformFunction } from './utils';

export interface JSONSchemaPatchOperation {
op: 'add' | 'remove' | 'replace' | 'rename' | 'addProperty' | 'removeProperty' | 'renameProperty' | 'addDefinition' | 'removeDefinition';
Expand Down Expand Up @@ -62,10 +62,10 @@ export class JSONSchemaPatch {
this.ops.push(op);
}

transform(transformFunction: TransformFunction): void {
transform(transformFunction: TransformFunction, transformTest: BooleanFunction): void {
this.ops = [
...this.ops,
...createJSONSchemaPatchOperations(findAllProps(this.schema), transformFunction)
...createJSONSchemaPatchOperations(findAllProps(this.schema), transformFunction, transformTest)
];
}

Expand Down
57 changes: 38 additions & 19 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export interface PropertyPath {
}

export type TransformFunction = (str: string) => string;
export type BooleanFunction = (str: string) => boolean;

function sortByDeepestPath(propertyPaths: PropertyPath[]): PropertyPath[] {
return propertyPaths.sort((a, b) => {
Expand Down Expand Up @@ -90,15 +91,19 @@ export function findAllProps(schema: JSONSchema, currentPath: string = ''): Prop
return sortByDeepestPath(findProps(schema, currentPath));
}

export function createJSONSchemaPatchOperations(propertyPaths: PropertyPath[], transform: TransformFunction): JSONSchemaPatchOperation[] {
export function createJSONSchemaPatchOperations(
propertyPaths: PropertyPath[],
transform: TransformFunction,
transformTest: BooleanFunction
): JSONSchemaPatchOperation[] {
const ops = propertyPaths.map(propertyPath => {
switch (propertyPath.type) {
case 'property':
return createRenamePropertyOperation(propertyPath, transform);
return createRenamePropertyOperation(propertyPath, transform, transformTest);
case '$def':
return createReplaceDefOperation(propertyPath, transform);
return createReplaceDefOperation(propertyPath, transform, transformTest);
case '$ref':
return createReplaceRefOperation(propertyPath, transform);
return createReplaceRefOperation(propertyPath, transform, transformTest);
default:
throw new Error(`Unknown property type: ${propertyPath.type}`);
}
Expand All @@ -113,12 +118,16 @@ export function createJSONSchemaPatchOperations(propertyPaths: PropertyPath[], t

}

function createRenamePropertyOperation(propertyPath: PropertyPath, transform: TransformFunction): JSONSchemaPatchOperation {
function createRenamePropertyOperation(
propertyPath: PropertyPath,
transform: TransformFunction,
transformTest: BooleanFunction
): JSONSchemaPatchOperation {
const grandParent = dirname(dirname(propertyPath.path));
const oldName = basename(propertyPath.path);
const newName = transform(oldName);

if (!isSimpleKey(oldName) || oldName === newName) return;
if (!transformTest(oldName) || oldName === newName) return;

return {
op: 'renameProperty',
Expand All @@ -127,44 +136,54 @@ function createRenamePropertyOperation(propertyPath: PropertyPath, transform: Tr
};
}

function createReplaceRefOperation(propertyPath: PropertyPath, transform: TransformFunction): JSONSchemaPatchOperation {
const newRef = transformJsonPath(propertyPath.name, transform);
function createReplaceRefOperation(
propertyPath: PropertyPath,
transform: TransformFunction,
transformTest: BooleanFunction
): JSONSchemaPatchOperation {
const newRef = transformJsonPath(propertyPath.name, transform, transformTest);
if (newRef === propertyPath.name) return;
return {
op: 'replace',
path: transformJsonPath(propertyPath.path + '/$ref', transform),
path: transformJsonPath(propertyPath.path + '/$ref', transform, transformTest),
value: newRef
};
}

function createReplaceDefOperation(propertyPath: PropertyPath, transform: TransformFunction): JSONSchemaPatchOperation {
function createReplaceDefOperation(
propertyPath: PropertyPath,
transform: TransformFunction,
transformTest: BooleanFunction
): JSONSchemaPatchOperation {
const oldName = basename(propertyPath.path);
const newName = transform(oldName);
if (!isSimpleKey(oldName) || oldName === newName) return;
if (!transformTest(oldName) || oldName === newName) return;
return {
op: 'rename',
path: propertyPath.path,
value: transformJsonPath(propertyPath.name, transform)
value: transformJsonPath(propertyPath.name, transform, transformTest)
};
}

function transformJsonPath(path: string, transformFunc: (str: string) => string): string {
function transformJsonPath(
path: string,
transform: TransformFunction,
transformTest: BooleanFunction
): string {
const specialKeywords = ['#', '$defs', '$ref', 'definitions', 'properties'];
return path.split('/').map(segment => {
const normalizedSegment = segment.replace(/^#/, '');
if (specialKeywords.includes(normalizedSegment) || !isSimpleKey(segment)) {
if (specialKeywords.includes(normalizedSegment) || !transformTest(segment)) {
return segment;
}
return transformFunc(segment);
return transform(segment);
}).join('/');
}

// MARKED AS NOT DRY
// from strfy-js
export function isSimpleKey(key: string): boolean {
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key);
}


// from strfy-js
export function dirname(path: string): string {
return path.replace(/\/[^\/]*$/, ''); // Removes last segment after the last '/'
}
Expand Down
2 changes: 1 addition & 1 deletion types/utils.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JSONSchemaPatchOperation } from "src";
import { JSONSchemaPatchOperation } from "./";
interface JSONSchema {
properties?: {
[key: string]: JSONSchema;
Expand Down

0 comments on commit ced0f45

Please sign in to comment.