Skip to content

feat: add the main diff function #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 18, 2021
Merged
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
1 change: 0 additions & 1 deletion sonar-project.properties → .sonarcloud.properties
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
# Disable specific duplicate code since it would introduce more complexity to reduce it.
sonar.cpd.exclusions=src/standard.ts
sonar.exclusions=src/standard.ts
9 changes: 5 additions & 4 deletions src/asyncapidiff.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Output, DiffOutputItem } from './types';
import { breaking, nonBreaking, unclassified } from './constants';

/**
* Implements functions to deal with the diff.
@@ -10,28 +11,28 @@ export default class AsyncAPIDiff {

constructor(output: string) {
// output is a stringified JSON
this.output= JSON.parse(output);
this.output = JSON.parse(output);
}

/**
* @returns All the breaking changes
*/
breaking(): DiffOutputItem[] {
return this.output.changes.filter((diff) => diff.type === 'breaking');
return this.output.changes.filter((diff) => diff.type === breaking);
}

/**
* @returns All the non-breaking changes
*/
nonBreaking(): DiffOutputItem[] {
return this.output.changes.filter((diff) => diff.type === 'non-breaking');
return this.output.changes.filter((diff) => diff.type === nonBreaking);
}

/**
* @returns All the unclassified changes
*/
unclassified(): DiffOutputItem[] {
return this.output.changes.filter((diff) => diff.type === 'unclassified');
return this.output.changes.filter((diff) => diff.type === unclassified);
}

/**
7 changes: 4 additions & 3 deletions src/classifier.ts
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
// Disabling this since the property we are accessing will always have `/` as the prefix
// Thus preventing the prototype chain attacks

import { unclassified } from './constants';
import { generateClassifierPath } from './helpers/ClassifierHelpers';
import { Classifier, OverrideStandard } from './types';

@@ -18,9 +19,9 @@ export default function classifier(
const classifierPath = generateClassifierPath(standard, path);
if (!classifierPath) {
return {
add: 'unclassified',
remove: 'unclassified',
edit: 'unclassified',
add: unclassified,
remove: unclassified,
edit: unclassified,
};
}
return standard[classifierPath];
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const breaking = 'breaking';
export const nonBreaking = 'non-breaking';
export const unclassified = 'unclassified';
2 changes: 1 addition & 1 deletion src/diff.ts → src/generateDiff.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import { DiffOutput } from './types';
* @param {*} secondDocument The second document in JSON format
* @returns {DiffOutput[]} An array containing all the diffs
*/
export default function diff(
export default function generateDiff(
firstDocument: any,
secondDocument: any
): DiffOutput[] {
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export {};
export * from './main';
export * from './types';
42 changes: 42 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Config, OverrideStandard } from './types';
import generateDiff from './generateDiff';
import { standard } from './standard';
import categorizeChanges from './categorizeChanges';
import AsyncAPIDiff from './asyncapidiff';
import { mergeStandard } from './mergeStandard';

/**
* Generates diff between two AsyncAPI documents
* @param firstDocument The parsed AsyncAPI document
* @param secondDocument The parsed AsyncAPI document
* @param {Object} config Configuration options
* @param {Object} [config.override] Object to override the standard
* @returns {AsyncAPIDiff} The diff data
*
* @example
* const output = diff(firstDocument, secondDocument, {
* override: {
* '/servers': {
* add: 'non-breaking', // when a property has been added in the AsyncAPI document
* remove: 'breaking', // when a property has been removed from the AsyncAPI document
* edit: 'unclassified' // when a property has been edited in the AsyncAPI document
* }
* }
* })
*/
export function diff(
firstDocument: any,
secondDocument: any,
config: Config = {}
): AsyncAPIDiff {
if (config.override) {
if (typeof config.override !== 'object') {
throw new TypeError('Override data must be an object');
}
mergeStandard(standard, config.override);
}

const diffOutput = generateDiff(firstDocument, secondDocument);
const output = categorizeChanges(standard as OverrideStandard, diffOutput);
return new AsyncAPIDiff(JSON.stringify(output));
}
99 changes: 96 additions & 3 deletions src/standard.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
const breaking = 'breaking';
const nonBreaking = 'non-breaking';
const unclassified = 'unclassified';
import { breaking, nonBreaking, unclassified } from './constants';

/**
* The standard object
@@ -126,6 +124,11 @@ export const standard = {
remove: breaking,
edit: breaking,
},
'/servers/*/variables/*/enum/*': {
add: nonBreaking,
remove: breaking,
edit: breaking,
},
'/servers/*/variables/*/default': {
add: breaking,
remove: breaking,
@@ -141,11 +144,21 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/servers/*/variables/*/examples/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/servers/*/security': {
add: breaking,
remove: breaking,
edit: breaking,
},
'/servers/*/security/*': {
add: breaking,
remove: breaking,
edit: breaking,
},
'/servers/*/bindings': {
add: unclassified,
remove: unclassified,
@@ -196,6 +209,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/tags/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/externalDocs': {
add: nonBreaking,
remove: nonBreaking,
@@ -211,6 +229,11 @@ export const standard = {
remove: breaking,
edit: breaking,
},
'/channels/*/subscribe/traits/*': {
add: nonBreaking,
remove: breaking,
edit: breaking,
},
'/channels/*/subscribe/traits/operationId': {
add: nonBreaking,
remove: breaking,
@@ -231,6 +254,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/traits/tags/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/traits/externalDocs': {
add: nonBreaking,
remove: nonBreaking,
@@ -296,6 +324,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/message/tags/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/message/externalDocs': {
add: nonBreaking,
remove: nonBreaking,
@@ -311,11 +344,21 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/message/examples/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/message/traits': {
add: nonBreaking,
remove: breaking,
edit: breaking,
},
'/channels/*/subscribe/message/traits/*': {
add: nonBreaking,
remove: breaking,
edit: breaking,
},
'/channels/*/subscribe/message/traits/headers': {
add: unclassified,
remove: unclassified,
@@ -366,6 +409,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/message/traits/tags/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/message/traits/externalDocs': {
add: nonBreaking,
remove: nonBreaking,
@@ -381,6 +429,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/message/traits/examples/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/subscribe/message/description': {
add: nonBreaking,
remove: nonBreaking,
@@ -416,6 +469,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/tags/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/externalDocs': {
add: nonBreaking,
remove: nonBreaking,
@@ -431,6 +489,11 @@ export const standard = {
remove: breaking,
edit: breaking,
},
'/channels/*/publish/traits/*': {
add: nonBreaking,
remove: breaking,
edit: breaking,
},
'/channels/*/publish/traits/operationId': {
add: nonBreaking,
remove: breaking,
@@ -451,6 +514,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/traits/tags/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/traits/externalDocs': {
add: nonBreaking,
remove: nonBreaking,
@@ -516,6 +584,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/message/tags/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/message/externalDocs': {
add: nonBreaking,
remove: nonBreaking,
@@ -531,11 +604,21 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/message/examples/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/message/traits': {
add: nonBreaking,
remove: breaking,
edit: breaking,
},
'/channels/*/publish/message/traits/*': {
add: nonBreaking,
remove: breaking,
edit: breaking,
},
'/channels/*/publish/message/traits/headers': {
add: unclassified,
remove: unclassified,
@@ -586,6 +669,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/message/traits/tags/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/message/traits/externalDocs': {
add: nonBreaking,
remove: nonBreaking,
@@ -601,6 +689,11 @@ export const standard = {
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/message/traits/examples/*': {
add: nonBreaking,
remove: nonBreaking,
edit: nonBreaking,
},
'/channels/*/publish/message/description': {
add: nonBreaking,
remove: nonBreaking,
7 changes: 5 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { ReplaceOperation, AddOperation } from 'fast-json-patch';

import { standard } from './standard';
import { breaking, nonBreaking, unclassified } from './constants';

export type ActionType = 'add' | 'remove' | 'edit';

export type ChangeType = 'breaking' | 'non-breaking' | 'unclassified';
export type ChangeType =
| typeof breaking
| typeof nonBreaking
| typeof unclassified;

export interface Classifier {
add: ChangeType;
@@ -38,6 +42,5 @@ export interface OverrideObject {
export type OverrideStandard = StandardType & OverrideObject;

export interface Config {
parse?: boolean;
override?: OverrideObject;
}
Loading