
Research
2025 Report: Destructive Malware in Open Source Packages
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.
api-smart-diff
Advanced tools
Generate the diff between two API specifications (OpenAPI, AsyncAPI, JsonSchema)
This package provides utils to compute the diff between two Json based API documents - online demo
npm install api-smart-diff --save
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)
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>
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.
The apiDiff function calculates the difference between two objects.
before: any - the origin objectafter: any - the object being compared structurally with the origin object\options: CompareOptions [optional] - comparison optionstype CompareOptions = {
rules?: Rules
trimStrings?: boolean
caseSensitive?: boolean
strictArrays?: boolean
externalRefs?: { [key: string]: any }
}
rules - custom match and classification rulestrimString - ignore spaces in matching, default falsecaseSensitive - ignore case in matching, default falsestrictArrays - use strict match algorithm for array items, default falseexternalRefs - object with external refsFunction 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"
}
const diffs = apiDiff(before, after)
if (diffs.length) {
// do something with the changes
}
The apiDiff function calculates the difference between two objects.
before: any - the origin objectafter: any - the object being compared structurally with the origin object\options: CompareOptions [optional] - comparison optionsFunction 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"
}
const diff = apiDiffTree(before, after)
// do something with the changes object
The apiDiff function calculates the difference between two objects.
before: any - the origin objectafter: any - the object being compared structurally with the origin object\options: MergeOptions [optional] - comparison optionstype MergeOptions<T> = CompareOptions & {
resolveUnchangedRefs?: boolean
arrayMeta?: boolean
formatMergedMeta?: (diff: T) => any
metaKey?: string | symbol
}
Additional to compare options:
arrayMeta - inject meta to arrays for items changes, default falseresolveUnchangedRefs - resolve refs even if no changes, default falsemetaKey - key for diff metadata, default $diffformatMergedMeta - custom formatting function for metaFunction 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 }
}
const apiKey = Symbol("diff")
const merged = apiMerge(before, after, { apiKey })
// do something with merged object
import { apiDiff, changeDoc, changeDocOpenApiRules } from "api-smart-diff"
const diff = apiDiff(before, after, {
formatMergedMeta: (diff) => ({ ...diff, description: changeDoc(diff, before, after, changeDocOpenApiRules) })
})
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
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!
MIT
FAQs
Generate the diff between two API specifications (OpenAPI, AsyncAPI, GraphApi, JsonSchema)
We found that api-smart-diff demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

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.

Research
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.

Security News
Socket CTO Ahmad Nassri shares practical AI coding techniques, tools, and team workflows, plus what still feels noisy and why shipping remains human-led.

Research
/Security News
A five-month operation turned 27 npm packages into durable hosting for browser-run lures that mimic document-sharing portals and Microsoft sign-in, targeting 25 organizations across manufacturing, industrial automation, plastics, and healthcare for credential theft.