@contractual/differs.json-schema 0.1.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +180 -0
- package/dist/classifiers.d.ts +87 -0
- package/dist/classifiers.d.ts.map +1 -0
- package/dist/classifiers.js +357 -0
- package/dist/classifiers.js.map +1 -0
- package/dist/compare.d.ts +37 -0
- package/dist/compare.d.ts.map +1 -0
- package/dist/compare.js +232 -0
- package/dist/compare.js.map +1 -0
- package/dist/differ.d.ts +57 -0
- package/dist/differ.d.ts.map +1 -0
- package/dist/differ.js +304 -0
- package/dist/differ.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/ref-resolver.d.ts +73 -0
- package/dist/ref-resolver.d.ts.map +1 -0
- package/dist/ref-resolver.js +345 -0
- package/dist/ref-resolver.js.map +1 -0
- package/dist/types.d.ts +276 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +210 -0
- package/dist/types.js.map +1 -0
- package/dist/walker.d.ts +17 -0
- package/dist/walker.d.ts.map +1 -0
- package/dist/walker.js +1195 -0
- package/dist/walker.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (C) 2025 Omer Morad
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# @contractual/differs.json-schema
|
|
2
|
+
|
|
3
|
+
Production-quality breaking change detection for JSON Schema.
|
|
4
|
+
|
|
5
|
+
Detects and classifies structural changes between JSON Schema versions, recommending semantic version bumps (major/minor/patch).
|
|
6
|
+
|
|
7
|
+
## Why?
|
|
8
|
+
|
|
9
|
+
JSON Schema has 150M+ weekly npm downloads but **no production-quality breaking change detection tool**. This package fills that gap.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @contractual/differs.json-schema
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Compare Schema Files
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { diffJsonSchema } from '@contractual/differs.json-schema';
|
|
23
|
+
|
|
24
|
+
const result = await diffJsonSchema('v1/user.schema.json', 'v2/user.schema.json');
|
|
25
|
+
|
|
26
|
+
console.log(`Suggested bump: ${result.suggestedBump}`);
|
|
27
|
+
console.log(`Breaking: ${result.summary.breaking}`);
|
|
28
|
+
console.log(`Non-breaking: ${result.summary.nonBreaking}`);
|
|
29
|
+
|
|
30
|
+
// List breaking changes
|
|
31
|
+
for (const change of result.changes) {
|
|
32
|
+
if (change.severity === 'breaking') {
|
|
33
|
+
console.log(`❌ ${change.message}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Compare Schema Objects
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { diffJsonSchemaObjects } from '@contractual/differs.json-schema';
|
|
42
|
+
|
|
43
|
+
const oldSchema = { type: 'object', properties: { name: { type: 'string' } } };
|
|
44
|
+
const newSchema = { type: 'object', properties: { name: { type: 'number' } } };
|
|
45
|
+
|
|
46
|
+
const result = diffJsonSchemaObjects(oldSchema, newSchema);
|
|
47
|
+
// result.suggestedBump === 'major'
|
|
48
|
+
// result.changes[0].message === 'Type changed from "string" to "number"...'
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Quick Breaking Check
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { hasBreakingChanges } from '@contractual/differs.json-schema';
|
|
55
|
+
|
|
56
|
+
if (hasBreakingChanges(oldSchema, newSchema)) {
|
|
57
|
+
throw new Error('Breaking changes detected!');
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Change Classifications
|
|
62
|
+
|
|
63
|
+
### Breaking Changes (→ major bump)
|
|
64
|
+
|
|
65
|
+
| Category | Example |
|
|
66
|
+
|----------|---------|
|
|
67
|
+
| `property-removed` | Field deleted from schema |
|
|
68
|
+
| `required-added` | Existing field became required |
|
|
69
|
+
| `type-changed` | Type changed incompatibly |
|
|
70
|
+
| `type-narrowed` | Union type reduced |
|
|
71
|
+
| `enum-value-removed` | Enum option removed |
|
|
72
|
+
| `constraint-tightened` | minLength/maxLength made stricter |
|
|
73
|
+
| `additional-properties-denied` | Open schema closed |
|
|
74
|
+
| `min-items-increased` | Array minimum increased |
|
|
75
|
+
| `max-items-decreased` | Array maximum decreased |
|
|
76
|
+
|
|
77
|
+
### Non-Breaking Changes (→ minor bump)
|
|
78
|
+
|
|
79
|
+
| Category | Example |
|
|
80
|
+
|----------|---------|
|
|
81
|
+
| `property-added` | New optional field |
|
|
82
|
+
| `required-removed` | Field became optional |
|
|
83
|
+
| `type-widened` | Type accepts more values |
|
|
84
|
+
| `enum-value-added` | New enum option |
|
|
85
|
+
| `constraint-loosened` | Constraints relaxed |
|
|
86
|
+
| `additional-properties-allowed` | Closed schema opened |
|
|
87
|
+
|
|
88
|
+
### Patch Changes (→ patch bump)
|
|
89
|
+
|
|
90
|
+
| Category | Example |
|
|
91
|
+
|----------|---------|
|
|
92
|
+
| `description-changed` | Documentation updated |
|
|
93
|
+
| `title-changed` | Title updated |
|
|
94
|
+
| `default-changed` | Default value updated |
|
|
95
|
+
| `examples-changed` | Examples updated |
|
|
96
|
+
|
|
97
|
+
## Advanced Usage
|
|
98
|
+
|
|
99
|
+
### Resolve $refs
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { resolveRefs } from '@contractual/differs.json-schema';
|
|
103
|
+
|
|
104
|
+
const schema = {
|
|
105
|
+
type: 'object',
|
|
106
|
+
properties: {
|
|
107
|
+
user: { $ref: '#/$defs/User' }
|
|
108
|
+
},
|
|
109
|
+
$defs: {
|
|
110
|
+
User: { type: 'object', properties: { name: { type: 'string' } } }
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const { schema: resolved, warnings } = resolveRefs(schema);
|
|
115
|
+
// resolved.properties.user === { type: 'object', properties: { name: { type: 'string' } } }
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Custom Classification
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { walk, classify, CLASSIFICATION_SETS } from '@contractual/differs.json-schema';
|
|
122
|
+
|
|
123
|
+
// Get raw changes
|
|
124
|
+
const rawChanges = walk(resolvedOld, resolvedNew, '');
|
|
125
|
+
|
|
126
|
+
// Classify with custom rules
|
|
127
|
+
for (const change of rawChanges) {
|
|
128
|
+
if (CLASSIFICATION_SETS.BREAKING.has(change.type)) {
|
|
129
|
+
console.log('Breaking:', change.path);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Supported JSON Schema Versions
|
|
135
|
+
|
|
136
|
+
- Draft-07 (primary target)
|
|
137
|
+
- Draft 2019-09
|
|
138
|
+
- Draft 2020-12
|
|
139
|
+
|
|
140
|
+
## API Reference
|
|
141
|
+
|
|
142
|
+
### Main Functions
|
|
143
|
+
|
|
144
|
+
- `diffJsonSchema(oldPath, newPath)` - Compare two schema files
|
|
145
|
+
- `diffJsonSchemaObjects(oldSchema, newSchema)` - Compare two schema objects
|
|
146
|
+
- `hasBreakingChanges(oldSchema, newSchema)` - Quick boolean check
|
|
147
|
+
|
|
148
|
+
### Utilities
|
|
149
|
+
|
|
150
|
+
- `resolveRefs(schema)` - Resolve all $ref pointers
|
|
151
|
+
- `walk(oldSchema, newSchema, basePath)` - Low-level schema walker
|
|
152
|
+
- `classify(change)` - Classify a raw change
|
|
153
|
+
- `classifyPropertyAdded(change, newSchema)` - Context-aware property classification
|
|
154
|
+
|
|
155
|
+
### Types
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
interface DiffResult {
|
|
159
|
+
changes: Change[];
|
|
160
|
+
summary: DiffSummary;
|
|
161
|
+
suggestedBump: 'major' | 'minor' | 'patch' | 'none';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
interface Change {
|
|
165
|
+
path: string;
|
|
166
|
+
severity: 'breaking' | 'non-breaking' | 'patch' | 'unknown';
|
|
167
|
+
category: string;
|
|
168
|
+
message: string;
|
|
169
|
+
oldValue?: unknown;
|
|
170
|
+
newValue?: unknown;
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Part of Contractual
|
|
175
|
+
|
|
176
|
+
This package is extracted from [Contractual](https://github.com/contractual-dev/contractual), the schema contract lifecycle orchestrator.
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
MIT
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema Change Classifiers
|
|
3
|
+
*
|
|
4
|
+
* Classifies raw structural changes into severity levels for semantic versioning.
|
|
5
|
+
* Follows API compatibility principles where breaking changes require major bumps,
|
|
6
|
+
* additive changes require minor bumps, and metadata changes are patches.
|
|
7
|
+
*/
|
|
8
|
+
import type { RawChange, ChangeType, ChangeSeverity } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Export classification sets for external analysis
|
|
11
|
+
*/
|
|
12
|
+
export declare const CLASSIFICATION_SETS: {
|
|
13
|
+
readonly breaking: ReadonlySet<ChangeType>;
|
|
14
|
+
readonly nonBreaking: ReadonlySet<ChangeType>;
|
|
15
|
+
readonly patch: ReadonlySet<ChangeType>;
|
|
16
|
+
readonly unknown: ReadonlySet<ChangeType>;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Classify a raw change into a severity level
|
|
20
|
+
*
|
|
21
|
+
* Uses the Strands API classification rules where:
|
|
22
|
+
* - Breaking changes require major version bump
|
|
23
|
+
* - Non-breaking changes require minor version bump
|
|
24
|
+
* - Patch changes are metadata/annotation only
|
|
25
|
+
* - Unknown changes require manual review
|
|
26
|
+
*
|
|
27
|
+
* @param change - The raw change to classify
|
|
28
|
+
* @returns The severity classification
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const change: RawChange = {
|
|
33
|
+
* path: '/properties/name',
|
|
34
|
+
* type: 'property-removed',
|
|
35
|
+
* oldValue: { type: 'string' },
|
|
36
|
+
* };
|
|
37
|
+
* const severity = classify(change);
|
|
38
|
+
* // severity === 'breaking'
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare function classify(change: RawChange): ChangeSeverity;
|
|
42
|
+
/**
|
|
43
|
+
* Classify a property-added change with schema context
|
|
44
|
+
*
|
|
45
|
+
* Property additions are breaking if the property is required,
|
|
46
|
+
* otherwise they are non-breaking (additive).
|
|
47
|
+
*
|
|
48
|
+
* @param change - The property-added change
|
|
49
|
+
* @param newSchema - The new schema for context (to check required array)
|
|
50
|
+
* @returns The severity classification
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const change: RawChange = {
|
|
55
|
+
* path: '/properties/email',
|
|
56
|
+
* type: 'property-added',
|
|
57
|
+
* newValue: { type: 'string', format: 'email' },
|
|
58
|
+
* };
|
|
59
|
+
*
|
|
60
|
+
* const schema = {
|
|
61
|
+
* type: 'object',
|
|
62
|
+
* properties: { email: { type: 'string', format: 'email' } },
|
|
63
|
+
* required: ['email'], // email is required!
|
|
64
|
+
* };
|
|
65
|
+
*
|
|
66
|
+
* const severity = classifyPropertyAdded(change, schema);
|
|
67
|
+
* // severity === 'breaking' (because email is in required[])
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function classifyPropertyAdded(change: RawChange, newSchema: unknown): ChangeSeverity;
|
|
71
|
+
/**
|
|
72
|
+
* Batch classify multiple changes
|
|
73
|
+
*
|
|
74
|
+
* @param changes - Array of raw changes
|
|
75
|
+
* @param newSchema - Optional schema for context-aware classification
|
|
76
|
+
* @returns Map of change to severity
|
|
77
|
+
*/
|
|
78
|
+
export declare function classifyAll(changes: readonly RawChange[], newSchema?: unknown): Map<RawChange, ChangeSeverity>;
|
|
79
|
+
/**
|
|
80
|
+
* Get a human-readable message for a classified change
|
|
81
|
+
*
|
|
82
|
+
* @param change - The raw change
|
|
83
|
+
* @param severity - The classified severity
|
|
84
|
+
* @returns Human-readable description
|
|
85
|
+
*/
|
|
86
|
+
export declare function getChangeMessage(change: RawChange, severity: ChangeSeverity): string;
|
|
87
|
+
//# sourceMappingURL=classifiers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifiers.d.ts","sourceRoot":"","sources":["../src/classifiers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA6HxE;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;CAKtB,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,cAAc,CAsB1D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,GAAG,cAAc,CA6B3F;AAgGD;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS,SAAS,EAAE,EAC7B,SAAS,CAAC,EAAE,OAAO,GAClB,GAAG,CAAC,SAAS,EAAE,cAAc,CAAC,CAYhC;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,GAAG,MAAM,CAapF"}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema Change Classifiers
|
|
3
|
+
*
|
|
4
|
+
* Classifies raw structural changes into severity levels for semantic versioning.
|
|
5
|
+
* Follows API compatibility principles where breaking changes require major bumps,
|
|
6
|
+
* additive changes require minor bumps, and metadata changes are patches.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Change types that are always breaking (require major version bump)
|
|
10
|
+
*
|
|
11
|
+
* These changes can break existing consumers:
|
|
12
|
+
* - Removing properties removes data they may depend on
|
|
13
|
+
* - Adding required fields forces consumers to provide new data
|
|
14
|
+
* - Type changes can break parsing/validation
|
|
15
|
+
* - Enum removals can invalidate existing data
|
|
16
|
+
* - Tightened constraints can reject previously valid data
|
|
17
|
+
* - Composition option additions can change validation semantics
|
|
18
|
+
*
|
|
19
|
+
* Aligned with Strands API classification rules.
|
|
20
|
+
*/
|
|
21
|
+
const BREAKING_CHANGES = new Set([
|
|
22
|
+
'property-removed',
|
|
23
|
+
'required-added',
|
|
24
|
+
'type-changed',
|
|
25
|
+
'type-narrowed',
|
|
26
|
+
'enum-value-removed',
|
|
27
|
+
'enum-added',
|
|
28
|
+
'constraint-tightened',
|
|
29
|
+
'additional-properties-denied',
|
|
30
|
+
'items-changed',
|
|
31
|
+
'min-items-increased',
|
|
32
|
+
'max-items-decreased',
|
|
33
|
+
'ref-target-changed',
|
|
34
|
+
'dependent-required-added',
|
|
35
|
+
// Composition breaking changes (per Strands API)
|
|
36
|
+
'anyof-option-added',
|
|
37
|
+
'oneof-option-added',
|
|
38
|
+
'allof-member-added',
|
|
39
|
+
'not-schema-changed',
|
|
40
|
+
]);
|
|
41
|
+
/**
|
|
42
|
+
* Change types that are non-breaking (require minor version bump)
|
|
43
|
+
*
|
|
44
|
+
* These changes are backward compatible additions/relaxations:
|
|
45
|
+
* - Adding optional properties extends the schema without breaking
|
|
46
|
+
* - Removing required constraints makes the schema more permissive
|
|
47
|
+
* - Type widening accepts more values
|
|
48
|
+
* - Loosened constraints accept more values
|
|
49
|
+
* - Composition option removals make schema less restrictive
|
|
50
|
+
*
|
|
51
|
+
* Aligned with Strands API classification rules.
|
|
52
|
+
*/
|
|
53
|
+
const NON_BREAKING_CHANGES = new Set([
|
|
54
|
+
'property-added',
|
|
55
|
+
'required-removed',
|
|
56
|
+
'type-widened',
|
|
57
|
+
'enum-value-added',
|
|
58
|
+
'enum-removed',
|
|
59
|
+
'constraint-loosened',
|
|
60
|
+
'additional-properties-allowed',
|
|
61
|
+
'additional-properties-changed',
|
|
62
|
+
'dependent-required-removed',
|
|
63
|
+
// Composition non-breaking changes (per Strands API)
|
|
64
|
+
'anyof-option-removed',
|
|
65
|
+
'oneof-option-removed',
|
|
66
|
+
'allof-member-removed',
|
|
67
|
+
]);
|
|
68
|
+
/**
|
|
69
|
+
* Change types that are patches (documentation/metadata only)
|
|
70
|
+
*
|
|
71
|
+
* These changes don't affect validation behavior:
|
|
72
|
+
* - Description changes are documentation only
|
|
73
|
+
* - Title changes are display metadata
|
|
74
|
+
* - Default/example changes don't affect validation
|
|
75
|
+
* - Format is an annotation (per Strands API) - doesn't affect validation
|
|
76
|
+
* - Annotation keywords (deprecated, readOnly, writeOnly)
|
|
77
|
+
* - Content keywords (contentEncoding, contentMediaType, contentSchema)
|
|
78
|
+
*
|
|
79
|
+
* Aligned with Strands API classification rules.
|
|
80
|
+
*/
|
|
81
|
+
const PATCH_CHANGES = new Set([
|
|
82
|
+
// Metadata changes
|
|
83
|
+
'description-changed',
|
|
84
|
+
'title-changed',
|
|
85
|
+
'default-changed',
|
|
86
|
+
'examples-changed',
|
|
87
|
+
// Format is annotation (patch per Strands API)
|
|
88
|
+
'format-added',
|
|
89
|
+
'format-removed',
|
|
90
|
+
'format-changed',
|
|
91
|
+
// Annotation keywords (Draft 2019-09+)
|
|
92
|
+
'deprecated-changed',
|
|
93
|
+
'read-only-changed',
|
|
94
|
+
'write-only-changed',
|
|
95
|
+
// Content keywords
|
|
96
|
+
'content-encoding-changed',
|
|
97
|
+
'content-media-type-changed',
|
|
98
|
+
'content-schema-changed',
|
|
99
|
+
]);
|
|
100
|
+
/**
|
|
101
|
+
* Change types that require manual review
|
|
102
|
+
*
|
|
103
|
+
* These changes are too complex to classify automatically:
|
|
104
|
+
* - Generic composition changes require semantic analysis
|
|
105
|
+
* - Complex keywords (propertyNames, dependentSchemas, unevaluated*)
|
|
106
|
+
* - Conditional schema changes (if/then/else)
|
|
107
|
+
* - Unknown changes need human evaluation
|
|
108
|
+
*
|
|
109
|
+
* Aligned with Strands API classification rules.
|
|
110
|
+
*/
|
|
111
|
+
const UNKNOWN_CHANGES = new Set([
|
|
112
|
+
// Complex object keywords
|
|
113
|
+
'property-names-changed',
|
|
114
|
+
'dependent-schemas-changed',
|
|
115
|
+
'unevaluated-properties-changed',
|
|
116
|
+
// Complex array keywords
|
|
117
|
+
'unevaluated-items-changed',
|
|
118
|
+
'min-contains-changed',
|
|
119
|
+
'max-contains-changed',
|
|
120
|
+
// Conditional schema
|
|
121
|
+
'if-then-else-changed',
|
|
122
|
+
// Legacy/generic composition
|
|
123
|
+
'composition-changed',
|
|
124
|
+
// Catch-all
|
|
125
|
+
'unknown-change',
|
|
126
|
+
]);
|
|
127
|
+
/**
|
|
128
|
+
* Export classification sets for external analysis
|
|
129
|
+
*/
|
|
130
|
+
export const CLASSIFICATION_SETS = {
|
|
131
|
+
breaking: BREAKING_CHANGES,
|
|
132
|
+
nonBreaking: NON_BREAKING_CHANGES,
|
|
133
|
+
patch: PATCH_CHANGES,
|
|
134
|
+
unknown: UNKNOWN_CHANGES,
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Classify a raw change into a severity level
|
|
138
|
+
*
|
|
139
|
+
* Uses the Strands API classification rules where:
|
|
140
|
+
* - Breaking changes require major version bump
|
|
141
|
+
* - Non-breaking changes require minor version bump
|
|
142
|
+
* - Patch changes are metadata/annotation only
|
|
143
|
+
* - Unknown changes require manual review
|
|
144
|
+
*
|
|
145
|
+
* @param change - The raw change to classify
|
|
146
|
+
* @returns The severity classification
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* const change: RawChange = {
|
|
151
|
+
* path: '/properties/name',
|
|
152
|
+
* type: 'property-removed',
|
|
153
|
+
* oldValue: { type: 'string' },
|
|
154
|
+
* };
|
|
155
|
+
* const severity = classify(change);
|
|
156
|
+
* // severity === 'breaking'
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function classify(change) {
|
|
160
|
+
const { type } = change;
|
|
161
|
+
// Check each category in order of specificity
|
|
162
|
+
if (BREAKING_CHANGES.has(type)) {
|
|
163
|
+
return 'breaking';
|
|
164
|
+
}
|
|
165
|
+
if (NON_BREAKING_CHANGES.has(type)) {
|
|
166
|
+
return 'non-breaking';
|
|
167
|
+
}
|
|
168
|
+
if (PATCH_CHANGES.has(type)) {
|
|
169
|
+
return 'patch';
|
|
170
|
+
}
|
|
171
|
+
if (UNKNOWN_CHANGES.has(type)) {
|
|
172
|
+
return 'unknown';
|
|
173
|
+
}
|
|
174
|
+
// Defensive: any unhandled type is unknown
|
|
175
|
+
return 'unknown';
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Classify a property-added change with schema context
|
|
179
|
+
*
|
|
180
|
+
* Property additions are breaking if the property is required,
|
|
181
|
+
* otherwise they are non-breaking (additive).
|
|
182
|
+
*
|
|
183
|
+
* @param change - The property-added change
|
|
184
|
+
* @param newSchema - The new schema for context (to check required array)
|
|
185
|
+
* @returns The severity classification
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* const change: RawChange = {
|
|
190
|
+
* path: '/properties/email',
|
|
191
|
+
* type: 'property-added',
|
|
192
|
+
* newValue: { type: 'string', format: 'email' },
|
|
193
|
+
* };
|
|
194
|
+
*
|
|
195
|
+
* const schema = {
|
|
196
|
+
* type: 'object',
|
|
197
|
+
* properties: { email: { type: 'string', format: 'email' } },
|
|
198
|
+
* required: ['email'], // email is required!
|
|
199
|
+
* };
|
|
200
|
+
*
|
|
201
|
+
* const severity = classifyPropertyAdded(change, schema);
|
|
202
|
+
* // severity === 'breaking' (because email is in required[])
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
export function classifyPropertyAdded(change, newSchema) {
|
|
206
|
+
// Validate change type
|
|
207
|
+
if (change.type !== 'property-added') {
|
|
208
|
+
return classify(change);
|
|
209
|
+
}
|
|
210
|
+
// Extract property name from path
|
|
211
|
+
const propertyName = extractPropertyName(change.path);
|
|
212
|
+
if (!propertyName) {
|
|
213
|
+
// Cannot determine property name, fall back to non-breaking
|
|
214
|
+
return 'non-breaking';
|
|
215
|
+
}
|
|
216
|
+
// Find the parent schema containing this property
|
|
217
|
+
const parentSchema = findParentSchema(change.path, newSchema);
|
|
218
|
+
if (!parentSchema) {
|
|
219
|
+
// Cannot find parent schema, fall back to non-breaking
|
|
220
|
+
return 'non-breaking';
|
|
221
|
+
}
|
|
222
|
+
// Check if property is in the required array
|
|
223
|
+
const required = getRequiredArray(parentSchema);
|
|
224
|
+
if (required.includes(propertyName)) {
|
|
225
|
+
// Adding a required property is breaking
|
|
226
|
+
return 'breaking';
|
|
227
|
+
}
|
|
228
|
+
// Adding an optional property is non-breaking
|
|
229
|
+
return 'non-breaking';
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Extract the property name from a JSON Pointer path
|
|
233
|
+
*
|
|
234
|
+
* @param path - JSON Pointer path (e.g., '/properties/name' or '/properties/user/properties/email')
|
|
235
|
+
* @returns The property name or null if not found
|
|
236
|
+
*/
|
|
237
|
+
function extractPropertyName(path) {
|
|
238
|
+
// Match the last /properties/NAME segment
|
|
239
|
+
const match = path.match(/\/properties\/([^/]+)$/);
|
|
240
|
+
if (match?.[1] !== undefined) {
|
|
241
|
+
return decodeJsonPointerSegment(match[1]);
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Decode a JSON Pointer segment (handles ~0 and ~1 escapes)
|
|
247
|
+
*
|
|
248
|
+
* @param segment - The encoded segment
|
|
249
|
+
* @returns The decoded segment
|
|
250
|
+
*/
|
|
251
|
+
function decodeJsonPointerSegment(segment) {
|
|
252
|
+
return segment.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Find the parent schema containing a property
|
|
256
|
+
*
|
|
257
|
+
* @param path - JSON Pointer path to the property
|
|
258
|
+
* @param schema - The root schema
|
|
259
|
+
* @returns The parent schema or null if not found
|
|
260
|
+
*/
|
|
261
|
+
function findParentSchema(path, schema) {
|
|
262
|
+
if (!isObject(schema)) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
// Remove the last segment to get parent path
|
|
266
|
+
// e.g., '/properties/name' -> '' (root)
|
|
267
|
+
// e.g., '/properties/user/properties/email' -> '/properties/user'
|
|
268
|
+
const segments = path.split('/').filter(Boolean);
|
|
269
|
+
// We need to navigate to the schema containing /properties/NAME
|
|
270
|
+
// So we remove 'properties' and 'NAME' from the end
|
|
271
|
+
if (segments.length < 2) {
|
|
272
|
+
// Path is too short, parent is root
|
|
273
|
+
return schema;
|
|
274
|
+
}
|
|
275
|
+
// Remove 'NAME' and 'properties' from the end
|
|
276
|
+
const parentSegments = segments.slice(0, -2);
|
|
277
|
+
// Navigate to parent
|
|
278
|
+
let current = schema;
|
|
279
|
+
for (const segment of parentSegments) {
|
|
280
|
+
if (!isObject(current)) {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
const decoded = decodeJsonPointerSegment(segment);
|
|
284
|
+
current = current[decoded];
|
|
285
|
+
}
|
|
286
|
+
return current;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Get the required array from a schema object
|
|
290
|
+
*
|
|
291
|
+
* @param schema - The schema object
|
|
292
|
+
* @returns Array of required property names
|
|
293
|
+
*/
|
|
294
|
+
function getRequiredArray(schema) {
|
|
295
|
+
if (!isObject(schema)) {
|
|
296
|
+
return [];
|
|
297
|
+
}
|
|
298
|
+
const obj = schema;
|
|
299
|
+
const required = obj['required'];
|
|
300
|
+
if (!Array.isArray(required)) {
|
|
301
|
+
return [];
|
|
302
|
+
}
|
|
303
|
+
return required.filter((item) => typeof item === 'string');
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Type guard for objects
|
|
307
|
+
*/
|
|
308
|
+
function isObject(value) {
|
|
309
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Batch classify multiple changes
|
|
313
|
+
*
|
|
314
|
+
* @param changes - Array of raw changes
|
|
315
|
+
* @param newSchema - Optional schema for context-aware classification
|
|
316
|
+
* @returns Map of change to severity
|
|
317
|
+
*/
|
|
318
|
+
export function classifyAll(changes, newSchema) {
|
|
319
|
+
const results = new Map();
|
|
320
|
+
for (const change of changes) {
|
|
321
|
+
if (change.type === 'property-added' && newSchema !== undefined) {
|
|
322
|
+
results.set(change, classifyPropertyAdded(change, newSchema));
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
results.set(change, classify(change));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return results;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get a human-readable message for a classified change
|
|
332
|
+
*
|
|
333
|
+
* @param change - The raw change
|
|
334
|
+
* @param severity - The classified severity
|
|
335
|
+
* @returns Human-readable description
|
|
336
|
+
*/
|
|
337
|
+
export function getChangeMessage(change, severity) {
|
|
338
|
+
const severityLabel = severity === 'breaking'
|
|
339
|
+
? 'BREAKING'
|
|
340
|
+
: severity === 'non-breaking'
|
|
341
|
+
? 'Non-breaking'
|
|
342
|
+
: severity === 'patch'
|
|
343
|
+
? 'Patch'
|
|
344
|
+
: 'Unknown';
|
|
345
|
+
const typeLabel = formatChangeType(change.type);
|
|
346
|
+
return `[${severityLabel}] ${typeLabel} at ${change.path}`;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Format a change type into a human-readable label
|
|
350
|
+
*/
|
|
351
|
+
function formatChangeType(type) {
|
|
352
|
+
return type
|
|
353
|
+
.split('-')
|
|
354
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
355
|
+
.join(' ');
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=classifiers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifiers.js","sourceRoot":"","sources":["../src/classifiers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strands-compatible JSON Schema comparison API
|
|
3
|
+
*
|
|
4
|
+
* Provides schema comparison with output format matching the Strands API
|
|
5
|
+
* (https://strands.octue.com/api/compare-schemas)
|
|
6
|
+
*/
|
|
7
|
+
import { type CompareResult, type CompareOptions, type StrandsCompatibility } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Compare two JSON Schema objects and return Strands-compatible result
|
|
10
|
+
*
|
|
11
|
+
* @param sourceSchema - The source (old/baseline) schema object
|
|
12
|
+
* @param targetSchema - The target (new/current) schema object
|
|
13
|
+
* @param options - Optional comparison options
|
|
14
|
+
* @returns CompareResult in Strands API format
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const source = { type: 'object', properties: { name: { type: 'string' } } };
|
|
19
|
+
* const target = { type: 'object', properties: { name: { type: 'number' } } };
|
|
20
|
+
*
|
|
21
|
+
* const result = compareSchemas(source, target, { currentVersion: '1.0.0' });
|
|
22
|
+
* console.log(result.version); // 'major'
|
|
23
|
+
* console.log(result.newVersion); // { major: 2, minor: 0, patch: 0, version: '2.0.0' }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function compareSchemas(sourceSchema: unknown, targetSchema: unknown, options?: CompareOptions): CompareResult;
|
|
27
|
+
/**
|
|
28
|
+
* Compare two JSON Schema objects and return a simple compatibility result
|
|
29
|
+
*
|
|
30
|
+
* Convenience function for quick compatibility checks.
|
|
31
|
+
*
|
|
32
|
+
* @param sourceSchema - The source (old/baseline) schema object
|
|
33
|
+
* @param targetSchema - The target (new/current) schema object
|
|
34
|
+
* @returns 'compatible' | 'incompatible' | 'unknown'
|
|
35
|
+
*/
|
|
36
|
+
export declare function checkCompatibility(sourceSchema: unknown, targetSchema: unknown): StrandsCompatibility;
|
|
37
|
+
//# sourceMappingURL=compare.d.ts.map
|