Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

api-smart-diff

Package Overview
Dependencies
Maintainers
1
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

api-smart-diff

Generate the diff between two API specifications (OpenAPI, AsyncAPI, JsonSchema)

  • 0.6.11
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
932
increased by84.92%
Maintainers
1
Weekly downloads
 
Created
Source

api-smart-diff

npm npm npm type definitions GitHub

This package provides utils to compute the diff between two Json based API documents - online demo

Purpose

  • Generate API changelog
  • Identify breaking changes
  • Ensure API versioning consistency

Supported API specifications

Features

  • Generate diff for supported specifications
  • Generate merged spec with changes in metadata
  • Classify all changes as breaking, non-breaking, annotation
  • Human-readable change description (OpenApi only)
  • Supports custom classification rules
  • Supports custom match rules for array items and object keys
  • Resolves all $ref pointers, including external and circular
  • Typescript syntax support out of the box
  • No dependencies, can be used in nodejs or browser

Installation

npm install api-smart-diff --save

Usage

Nodejs

import { apiDiff } from 'api-smart-diff'

const diffs = apiDiff(oldSpec, newSpec)
// {
//   action: "add" | "remove" | "replace" | "rename",
//   after: 'value in newSpec',
//   before: 'value in oldSpec',
//   path: ['path, 'in', 'array', 'format'],
//   type: "annotation" | "breaking" | "non-breaking" | "unclassified" | "deprecated"
// }

const merged = apiMerge(oldSpec, newSpec)

Browsers

A browser version of api-smart-diff is also available via CDN:

<script src="https://cdn.jsdelivr.net/npm/api-smart-diff@latest/browser/api-smart-diff.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/api-smart-diff@latest/browser/api-smart-diff.js"></script>

Reference api-smart-diff.min.js in your HTML and use the global variable ApiSmartDiff.

<script>
  var diffs = ApiSmartDiff.apiDiff(oldSpec, newSpec)
  var merged = ApiSmartDiff.apiMerge(oldSpec, newSpec)
</script>

Documentation

Package provides the following public functions:

apiDiff (before, after, options?: CompareOptions): Array<Diff>

Calculates the difference list between two objects and classify difference in accordinance with before document type: OpenApi3, AsyncApi2, JsonSchema.

apiDiffTree (before, after, options?: CompareOptions): object

Calculates the difference tree between two objects and classify difference in accordinance with before document type: OpenApi3, AsyncApi2, JsonSchema.

apiMerge (before, after, options?: MergeOptions): object

Merge two objects and inject difference as meta data.

apiDiff(before, after, options)

The apiDiff function calculates the difference between two objects.

  • before: any - the origin object
  • after: any - the object being compared structurally with the origin object\
  • options: CompareOptions [optional] - comparison options
type CompareOptions = {
  rules?: Rules
  trimStrings?: boolean
  caseSensitive?: boolean
  strictArrays?: boolean
  externalRefs?: { [key: string]: any }
}
Arguments
  • rules - custom match and classification rules
  • trimString - ignore spaces in matching, default false
  • caseSensitive - ignore case in matching, default false
  • strictArrays - use strict match algorithm for array items, default false
  • externalRefs - object with external refs
Result

Function returns array of differences:

type Diff = {
  action: "add" | "remove" | "replace" | "rename"
  path: Array<string | number>
  before?: any
  after?: any
  type: "breaking" | "non-breaking" | "annotation" | "unclassified" | "deprecated"
}
Example
const diffs = apiDiff(before, after)
if (diffs.length) {
  // do something with the changes
}

apiDiffTree(before, after, options)

The apiDiff function calculates the difference between two objects.

  • before: any - the origin object
  • after: any - the object being compared structurally with the origin object\
  • options: CompareOptions [optional] - comparison options
Result

Function returns object with $diff key for all differences:

type Diff = {
  action: "add" | "remove" | "replace" | "rename"
  before?: any
  after?: any
  type: "breaking" | "non-breaking" | "annotation" | "unclassified" | "deprecated"
}
Example
const diff = apiDiffTree(before, after)
// do something with the changes object

apiMerge(before, after, options)

The apiDiff function calculates the difference between two objects.

  • before: any - the origin object
  • after: any - the object being compared structurally with the origin object\
  • options: MergeOptions [optional] - comparison options
type MergeOptions<T> = CompareOptions & {
  resolveUnchangedRefs?: boolean
  arrayMeta?: boolean
  formatMergedMeta?: (diff: T) => any
  metaKey?: string | symbol
}
Arguments

Additional to compare options:

  • arrayMeta - inject meta to arrays for items changes, default false
  • resolveUnchangedRefs - resolve refs even if no changes, default false
  • metaKey - key for diff metadata, default $diff
  • formatMergedMeta - custom formatting function for meta
Result

Function returns merged object with metadata. Metadata includes merged keys and differences:

type MergedMeta = {
  [key: string]: MergedKeyMeta | MergedArrayMeta
}

type MergedKeyMeta = {
  type: DiffType
  action: ActionType
  replaced?: any
}

type MergedArrayMeta = {
  array: { [key: number]: MergedArrayMeta }
}
Example
const apiKey = Symbol("diff")
const merged = apiMerge(before, after, { apiKey })

// do something with merged object

Human-readable change description example

import { apiDiff, changeDoc, changeDocOpenApiRules } from "api-smart-diff"

const diff = apiDiff(before, after, { 
  formatMergedMeta: (diff) => ({ ...diff, description: changeDoc(diff, before, after, changeDocOpenApiRules) })
})

Custom rules

Custom match and classification rules can be defined as object:

type Rules = {
  // root property (or array item) rule
  "/"?: Rule

  // rule for all unspecified properties (or nested array items)
  "/*"?: Rule | Rules | (before) => Rules

  // rule for specified properties
  [key: `/${string}`]?: Rule | Rules | (before) => Rules

  // custom match function for object (or array)
  "#"?: (before, after) => boolean
}

// Change classifier
type Rule = [ 
  DiffType | (ctx: IChangeContext) => DiffType, // add
  DiffType | (ctx: IChangeContext) => DiffType, // remove
  DiffType | (ctx: IChangeContext) => DiffType  // replace (rename)
]

// Current path Change context
interface IChageContext {
  before: any // before value
  after: any // after value
  root: IChageContext // get root Change context
  up: (n?: number) => IChageContext // get parent Change Context
}

Please check predefined rules in /src/rules folder to get examples

Contributing

When contributing, keep in mind that it is an objective of api-smart-diff to have no package dependencies. This may change in the future, but for now, no-dependencies.

Please run the unit tests before submitting your PR: npm test. Hopefully your PR includes additional unit tests to illustrate your change/modification!

License

MIT

Keywords

FAQs

Package last updated on 27 Jul 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc