@teambit/semantics.entities.semantic-schema 0.0.100 → 0.0.101
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/dist/index.d.ts +2 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -1
- package/dist/schema-diff-members.d.ts +3 -0
- package/dist/schema-diff-members.js +171 -0
- package/dist/schema-diff-members.js.map +1 -0
- package/dist/schema-diff.d.ts +13 -0
- package/dist/schema-diff.js +138 -0
- package/dist/schema-diff.js.map +1 -0
- package/dist/schema-node.d.ts +7 -0
- package/dist/schema-node.js +49 -0
- package/dist/schema-node.js.map +1 -1
- package/dist/schemas/class.d.ts +2 -0
- package/dist/schemas/class.js +11 -0
- package/dist/schemas/class.js.map +1 -1
- package/dist/schemas/enum.d.ts +2 -0
- package/dist/schemas/enum.js +55 -0
- package/dist/schemas/enum.js.map +1 -1
- package/dist/schemas/function-like.d.ts +9 -0
- package/dist/schemas/function-like.js +300 -0
- package/dist/schemas/function-like.js.map +1 -1
- package/dist/schemas/interface.d.ts +2 -0
- package/dist/schemas/interface.js +11 -0
- package/dist/schemas/interface.js.map +1 -1
- package/dist/schemas/type.d.ts +2 -0
- package/dist/schemas/type.js +25 -0
- package/dist/schemas/type.js.map +1 -1
- package/dist/schemas/variable-like.d.ts +2 -0
- package/dist/schemas/variable-like.js +60 -0
- package/dist/schemas/variable-like.js.map +1 -1
- package/index.ts +2 -0
- package/package.json +2 -2
- package/schema-diff-members.ts +164 -0
- package/schema-diff.ts +168 -0
- package/schema-node.ts +34 -0
- package/schemas/class.ts +7 -0
- package/schemas/enum.ts +46 -0
- package/schemas/function-like.ts +277 -0
- package/schemas/interface.ts +7 -0
- package/schemas/type.ts +18 -0
- package/schemas/variable-like.ts +54 -0
package/schema-node.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { pickBy } from 'lodash';
|
|
2
2
|
import pluralize from 'pluralize';
|
|
3
3
|
import type { DocSchema } from './schemas';
|
|
4
|
+
import type { SchemaChangeFact } from './schema-diff';
|
|
5
|
+
import { deepEqualNoLocation, diffDoc } from './schema-diff';
|
|
4
6
|
|
|
5
7
|
export interface ISchemaNode {
|
|
6
8
|
__schema: string;
|
|
@@ -84,6 +86,38 @@ export abstract class SchemaNode implements ISchemaNode {
|
|
|
84
86
|
|
|
85
87
|
return undefined;
|
|
86
88
|
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Compute neutral change facts between this node and another node of the same type.
|
|
92
|
+
* Subclasses should override with type-specific comparison logic.
|
|
93
|
+
* Returns facts without impact judgment — impact is assessed separately.
|
|
94
|
+
*/
|
|
95
|
+
diff(other: SchemaNode): SchemaChangeFact[] {
|
|
96
|
+
const facts: SchemaChangeFact[] = [];
|
|
97
|
+
const baseObj = this.toObject();
|
|
98
|
+
const compareObj = other.toObject();
|
|
99
|
+
|
|
100
|
+
// Doc changes
|
|
101
|
+
facts.push(...diffDoc(baseObj.doc, compareObj.doc));
|
|
102
|
+
|
|
103
|
+
// If only doc changed, we're done
|
|
104
|
+
const baseNoDoc = { ...baseObj, doc: undefined, location: undefined };
|
|
105
|
+
const compareNoDoc = { ...compareObj, doc: undefined, location: undefined };
|
|
106
|
+
if (deepEqualNoLocation(baseNoDoc, compareNoDoc)) return facts;
|
|
107
|
+
|
|
108
|
+
// Signature changed
|
|
109
|
+
if (baseObj.signature !== compareObj.signature) {
|
|
110
|
+
facts.push({
|
|
111
|
+
changeKind: 'signature-changed',
|
|
112
|
+
description: 'signature changed',
|
|
113
|
+
context: { fromSignature: baseObj.signature, toSignature: compareObj.signature },
|
|
114
|
+
from: baseObj.signature,
|
|
115
|
+
to: compareObj.signature,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return facts;
|
|
120
|
+
}
|
|
87
121
|
}
|
|
88
122
|
|
|
89
123
|
export type SchemaLocation = {
|
package/schemas/class.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import type { SchemaLocation } from '../schema-node';
|
|
3
3
|
import { SchemaNode } from '../schema-node';
|
|
4
|
+
import type { SchemaChangeFact } from '../schema-diff';
|
|
5
|
+
import { diffMembers } from '../schema-diff-members';
|
|
4
6
|
import { DocSchema } from './docs';
|
|
5
7
|
import { ExpressionWithTypeArgumentsSchema } from './expression-with-arguments';
|
|
6
8
|
import { SchemaRegistry } from '../schema-registry';
|
|
@@ -120,6 +122,11 @@ export class ClassSchema extends SchemaNode {
|
|
|
120
122
|
);
|
|
121
123
|
}
|
|
122
124
|
|
|
125
|
+
diff(other: SchemaNode): SchemaChangeFact[] {
|
|
126
|
+
if (!(other instanceof ClassSchema)) return super.diff(other);
|
|
127
|
+
return diffMembers(this.toObject(), other.toObject(), this, other);
|
|
128
|
+
}
|
|
129
|
+
|
|
123
130
|
static fromSchema(node: ClassSchema, memberTransformer: (_node: SchemaNode) => SchemaNode = (_node) => _node) {
|
|
124
131
|
return new ClassSchema(
|
|
125
132
|
node.name,
|
package/schemas/enum.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import type { SchemaLocation } from '../schema-node';
|
|
3
3
|
import { SchemaNode } from '../schema-node';
|
|
4
|
+
import type { SchemaChangeFact } from '../schema-diff';
|
|
5
|
+
import { deepEqualNoLocation, diffDoc } from '../schema-diff';
|
|
4
6
|
import { DocSchema } from './docs';
|
|
5
7
|
import { SchemaRegistry } from '..';
|
|
6
8
|
|
|
@@ -63,6 +65,50 @@ export class EnumSchema extends SchemaNode {
|
|
|
63
65
|
};
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
diff(other: SchemaNode): SchemaChangeFact[] {
|
|
69
|
+
if (!(other instanceof EnumSchema)) return super.diff(other);
|
|
70
|
+
const facts: SchemaChangeFact[] = [];
|
|
71
|
+
const baseMembers: Record<string, any>[] = this.toObject().members || [];
|
|
72
|
+
const compareMembers: Record<string, any>[] = other.toObject().members || [];
|
|
73
|
+
const baseMap = new Map(baseMembers.map((m) => [m.name || '', m]));
|
|
74
|
+
const compareMap = new Map(compareMembers.map((m) => [m.name || '', m]));
|
|
75
|
+
|
|
76
|
+
for (const [name, member] of compareMap) {
|
|
77
|
+
if (!baseMap.has(name)) {
|
|
78
|
+
facts.push({
|
|
79
|
+
changeKind: 'enum-member-added',
|
|
80
|
+
description: `enum member '${name}' added`,
|
|
81
|
+
context: { memberName: name },
|
|
82
|
+
to: member.signature || name,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const [name, member] of baseMap) {
|
|
87
|
+
if (!compareMap.has(name)) {
|
|
88
|
+
facts.push({
|
|
89
|
+
changeKind: 'enum-member-removed',
|
|
90
|
+
description: `enum member '${name}' removed`,
|
|
91
|
+
context: { memberName: name },
|
|
92
|
+
from: member.signature || name,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
for (const [name, bm] of baseMap) {
|
|
97
|
+
const cm = compareMap.get(name);
|
|
98
|
+
if (cm && !deepEqualNoLocation(bm, cm)) {
|
|
99
|
+
facts.push({
|
|
100
|
+
changeKind: 'enum-member-value-changed',
|
|
101
|
+
description: `enum member '${name}' value changed`,
|
|
102
|
+
context: { memberName: name },
|
|
103
|
+
from: bm.signature || name,
|
|
104
|
+
to: cm.signature || name,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
facts.push(...diffDoc(this.doc?.toObject(), other.doc?.toObject()));
|
|
109
|
+
return facts;
|
|
110
|
+
}
|
|
111
|
+
|
|
66
112
|
static fromObject(obj: Record<string, any>): EnumSchema {
|
|
67
113
|
const location = obj.location;
|
|
68
114
|
const name = obj.name;
|
package/schemas/function-like.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import type { SchemaLocation } from '../schema-node';
|
|
3
3
|
import { SchemaNode } from '../schema-node';
|
|
4
|
+
import type { SchemaChangeFact } from '../schema-diff';
|
|
5
|
+
import { typesAreSemanticallyEqual, typeStr, deepEqualNoLocation, diffDoc } from '../schema-diff';
|
|
4
6
|
import { ParameterSchema } from './parameter';
|
|
5
7
|
import { DocSchema } from './docs';
|
|
6
8
|
import { TagName } from './docs/tag';
|
|
@@ -148,6 +150,281 @@ export class FunctionLikeSchema extends SchemaNode {
|
|
|
148
150
|
);
|
|
149
151
|
}
|
|
150
152
|
|
|
153
|
+
diff(other: SchemaNode): SchemaChangeFact[] {
|
|
154
|
+
if (!(other instanceof FunctionLikeSchema)) return super.diff(other);
|
|
155
|
+
const facts: SchemaChangeFact[] = [];
|
|
156
|
+
const baseObj = this.toObject();
|
|
157
|
+
const compareObj = other.toObject();
|
|
158
|
+
|
|
159
|
+
FunctionLikeSchema.diffParams(baseObj.params || [], compareObj.params || [], facts);
|
|
160
|
+
|
|
161
|
+
if (!typesAreSemanticallyEqual(baseObj.returnType, compareObj.returnType)) {
|
|
162
|
+
const fromType = typeStr(baseObj.returnType);
|
|
163
|
+
const toType = typeStr(compareObj.returnType);
|
|
164
|
+
facts.push({
|
|
165
|
+
changeKind: 'return-type-changed',
|
|
166
|
+
description: `return type changed: ${fromType} → ${toType}`,
|
|
167
|
+
context: { fromType, toType, position: 'return-type' },
|
|
168
|
+
from: fromType,
|
|
169
|
+
to: toType,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!deepEqualNoLocation(baseObj.typeParams, compareObj.typeParams)) {
|
|
174
|
+
facts.push({
|
|
175
|
+
changeKind: 'type-parameters-changed',
|
|
176
|
+
description: `type parameters changed: <${(baseObj.typeParams || []).join(', ') || 'none'}> → <${(compareObj.typeParams || []).join(', ') || 'none'}>`,
|
|
177
|
+
context: { from: (baseObj.typeParams || []).join(', '), to: (compareObj.typeParams || []).join(', ') },
|
|
178
|
+
from: (baseObj.typeParams || []).join(', '),
|
|
179
|
+
to: (compareObj.typeParams || []).join(', '),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
FunctionLikeSchema.diffModifiers(this.modifiers || [], other.modifiers || [], facts);
|
|
184
|
+
facts.push(...diffDoc(baseObj.doc, compareObj.doc));
|
|
185
|
+
return facts;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private static diffModifiers(baseMods: string[], compareMods: string[], facts: SchemaChangeFact[]): void {
|
|
189
|
+
const base = baseMods.filter((m) => m !== 'export');
|
|
190
|
+
const compare = compareMods.filter((m) => m !== 'export');
|
|
191
|
+
if (deepEqualNoLocation(base, compare)) return;
|
|
192
|
+
|
|
193
|
+
const added = compare.filter((m) => !base.includes(m));
|
|
194
|
+
const removed = base.filter((m) => !compare.includes(m));
|
|
195
|
+
const parts: string[] = [];
|
|
196
|
+
if (added.length) parts.push(`added: ${added.join(', ')}`);
|
|
197
|
+
if (removed.length) parts.push(`removed: ${removed.join(', ')}`);
|
|
198
|
+
const accessNarrowed = removed.includes('public') || added.includes('private') || added.includes('protected');
|
|
199
|
+
|
|
200
|
+
facts.push({
|
|
201
|
+
changeKind: accessNarrowed ? 'access-narrowed' : 'modifiers-changed',
|
|
202
|
+
description: `modifiers changed (${parts.join('; ')})`,
|
|
203
|
+
context: { added, removed, accessNarrowed },
|
|
204
|
+
from: base.join(', ') || 'none',
|
|
205
|
+
to: compare.join(', ') || 'none',
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private static diffParams(
|
|
210
|
+
baseParams: Record<string, any>[],
|
|
211
|
+
compareParams: Record<string, any>[],
|
|
212
|
+
facts: SchemaChangeFact[]
|
|
213
|
+
): void {
|
|
214
|
+
for (const p of compareParams.slice(baseParams.length)) {
|
|
215
|
+
const isOpt = p.isOptional || p.defaultValue !== undefined;
|
|
216
|
+
facts.push({
|
|
217
|
+
changeKind: 'parameter-added',
|
|
218
|
+
description: `parameter '${p.name}: ${typeStr(p.type)}' added${isOpt ? ' (optional)' : ' (required)'}`,
|
|
219
|
+
context: {
|
|
220
|
+
paramName: p.name,
|
|
221
|
+
isOptional: !!p.isOptional,
|
|
222
|
+
hasDefault: p.defaultValue !== undefined,
|
|
223
|
+
paramType: typeStr(p.type),
|
|
224
|
+
},
|
|
225
|
+
to: `${p.name}${p.isOptional ? '?' : ''}: ${typeStr(p.type)}`,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
for (const p of baseParams.slice(compareParams.length)) {
|
|
230
|
+
facts.push({
|
|
231
|
+
changeKind: 'parameter-removed',
|
|
232
|
+
description: `parameter '${p.name}: ${typeStr(p.type)}' removed`,
|
|
233
|
+
context: { paramName: p.name, isOptional: !!p.isOptional, paramType: typeStr(p.type) },
|
|
234
|
+
from: `${p.name}${p.isOptional ? '?' : ''}: ${typeStr(p.type)}`,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const minLen = Math.min(baseParams.length, compareParams.length);
|
|
239
|
+
for (let i = 0; i < minLen; i++) {
|
|
240
|
+
FunctionLikeSchema.diffOverlappingParam(baseParams[i], compareParams[i], i, facts);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private static diffOverlappingParam(
|
|
245
|
+
bp: Record<string, any>,
|
|
246
|
+
cp: Record<string, any>,
|
|
247
|
+
index: number,
|
|
248
|
+
facts: SchemaChangeFact[]
|
|
249
|
+
): void {
|
|
250
|
+
if (bp.objectBindingNodes || cp.objectBindingNodes) {
|
|
251
|
+
FunctionLikeSchema.diffDestructuredParam(bp, cp, facts);
|
|
252
|
+
if (!typesAreSemanticallyEqual(bp.type, cp.type)) {
|
|
253
|
+
const paramName = cp.name || bp.name;
|
|
254
|
+
facts.push({
|
|
255
|
+
changeKind: 'parameter-type-changed',
|
|
256
|
+
description: `parameter at position ${index} type changed: ${typeStr(bp.type)} → ${typeStr(cp.type)}`,
|
|
257
|
+
context: { paramName, fromType: typeStr(bp.type), toType: typeStr(cp.type), position: 'parameter' },
|
|
258
|
+
from: typeStr(bp.type),
|
|
259
|
+
to: typeStr(cp.type),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const nameEqual = bp.name === cp.name;
|
|
266
|
+
const typeEqual = typesAreSemanticallyEqual(bp.type, cp.type);
|
|
267
|
+
if (nameEqual && typeEqual && bp.isOptional === cp.isOptional && bp.defaultValue === cp.defaultValue) return;
|
|
268
|
+
|
|
269
|
+
const paramName = cp.name || bp.name;
|
|
270
|
+
if (!nameEqual) {
|
|
271
|
+
facts.push({
|
|
272
|
+
changeKind: 'parameter-renamed',
|
|
273
|
+
description: `parameter at position ${index} renamed: '${bp.name}' → '${cp.name}'`,
|
|
274
|
+
context: { fromName: bp.name, toName: cp.name, position: index },
|
|
275
|
+
from: bp.name,
|
|
276
|
+
to: cp.name,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
if (!typeEqual) {
|
|
280
|
+
facts.push({
|
|
281
|
+
changeKind: 'parameter-type-changed',
|
|
282
|
+
description: `parameter '${paramName}' type changed: ${typeStr(bp.type)} → ${typeStr(cp.type)}`,
|
|
283
|
+
context: { paramName, fromType: typeStr(bp.type), toType: typeStr(cp.type), position: 'parameter' },
|
|
284
|
+
from: typeStr(bp.type),
|
|
285
|
+
to: typeStr(cp.type),
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
FunctionLikeSchema.diffParamOptionality(bp, cp, paramName, facts);
|
|
289
|
+
FunctionLikeSchema.diffParamDefault(bp, cp, paramName, facts);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private static diffParamOptionality(
|
|
293
|
+
bp: Record<string, any>,
|
|
294
|
+
cp: Record<string, any>,
|
|
295
|
+
paramName: string,
|
|
296
|
+
facts: SchemaChangeFact[]
|
|
297
|
+
): void {
|
|
298
|
+
if (bp.isOptional && !cp.isOptional) {
|
|
299
|
+
facts.push({
|
|
300
|
+
changeKind: 'became-required',
|
|
301
|
+
description: `parameter '${paramName}' became required (was optional)`,
|
|
302
|
+
context: { paramName, position: 'parameter' },
|
|
303
|
+
from: 'optional',
|
|
304
|
+
to: 'required',
|
|
305
|
+
});
|
|
306
|
+
} else if (!bp.isOptional && cp.isOptional) {
|
|
307
|
+
facts.push({
|
|
308
|
+
changeKind: 'became-optional',
|
|
309
|
+
description: `parameter '${paramName}' became optional (was required)`,
|
|
310
|
+
context: { paramName, position: 'parameter' },
|
|
311
|
+
from: 'required',
|
|
312
|
+
to: 'optional',
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private static diffParamDefault(
|
|
318
|
+
bp: Record<string, any>,
|
|
319
|
+
cp: Record<string, any>,
|
|
320
|
+
paramName: string,
|
|
321
|
+
facts: SchemaChangeFact[]
|
|
322
|
+
): void {
|
|
323
|
+
if (bp.defaultValue === cp.defaultValue) return;
|
|
324
|
+
if (bp.defaultValue !== undefined && cp.defaultValue === undefined) {
|
|
325
|
+
facts.push({
|
|
326
|
+
changeKind: 'parameter-default-removed',
|
|
327
|
+
description: `parameter '${paramName}' default value removed (was: ${bp.defaultValue})`,
|
|
328
|
+
context: { paramName, isOptional: !!bp.isOptional, previousDefault: String(bp.defaultValue) },
|
|
329
|
+
from: String(bp.defaultValue),
|
|
330
|
+
});
|
|
331
|
+
} else if (bp.defaultValue === undefined && cp.defaultValue !== undefined) {
|
|
332
|
+
facts.push({
|
|
333
|
+
changeKind: 'parameter-default-added',
|
|
334
|
+
description: `parameter '${paramName}' default value added: ${cp.defaultValue}`,
|
|
335
|
+
context: { paramName, newDefault: String(cp.defaultValue) },
|
|
336
|
+
to: String(cp.defaultValue),
|
|
337
|
+
});
|
|
338
|
+
} else {
|
|
339
|
+
facts.push({
|
|
340
|
+
changeKind: 'parameter-default-changed',
|
|
341
|
+
description: `parameter '${paramName}' default value changed: ${bp.defaultValue} → ${cp.defaultValue}`,
|
|
342
|
+
context: { paramName, previousDefault: String(bp.defaultValue), newDefault: String(cp.defaultValue) },
|
|
343
|
+
from: String(bp.defaultValue),
|
|
344
|
+
to: String(cp.defaultValue),
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private static diffDestructuredParam(
|
|
350
|
+
base: Record<string, any>,
|
|
351
|
+
compare: Record<string, any>,
|
|
352
|
+
facts: SchemaChangeFact[]
|
|
353
|
+
): void {
|
|
354
|
+
const baseBindings: Record<string, any>[] = base.objectBindingNodes || [];
|
|
355
|
+
const compareBindings: Record<string, any>[] = compare.objectBindingNodes || [];
|
|
356
|
+
const baseMap = new Map(baseBindings.map((b) => [b.name || '', b]));
|
|
357
|
+
const compareMap = new Map(compareBindings.map((b) => [b.name || '', b]));
|
|
358
|
+
|
|
359
|
+
for (const [name] of compareMap) {
|
|
360
|
+
if (!baseMap.has(name)) {
|
|
361
|
+
facts.push({
|
|
362
|
+
changeKind: 'destructured-property-added',
|
|
363
|
+
description: `destructured property '${name}' added`,
|
|
364
|
+
context: { propertyName: name },
|
|
365
|
+
to: name,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
for (const [name] of baseMap) {
|
|
370
|
+
if (!compareMap.has(name)) {
|
|
371
|
+
facts.push({
|
|
372
|
+
changeKind: 'destructured-property-removed',
|
|
373
|
+
description: `destructured property '${name}' removed`,
|
|
374
|
+
context: { propertyName: name },
|
|
375
|
+
from: name,
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
for (const [name, bb] of baseMap) {
|
|
380
|
+
const cb = compareMap.get(name);
|
|
381
|
+
if (!cb) continue;
|
|
382
|
+
FunctionLikeSchema.diffBindingDefault(name, bb, cb, !!base.isOptional, facts);
|
|
383
|
+
if (bb.type && cb.type && !typesAreSemanticallyEqual(bb.type, cb.type)) {
|
|
384
|
+
facts.push({
|
|
385
|
+
changeKind: 'destructured-property-type-changed',
|
|
386
|
+
description: `destructured property '${name}' type changed: ${typeStr(bb.type)} → ${typeStr(cb.type)}`,
|
|
387
|
+
context: { propertyName: name, fromType: typeStr(bb.type), toType: typeStr(cb.type), position: 'parameter' },
|
|
388
|
+
from: typeStr(bb.type),
|
|
389
|
+
to: typeStr(cb.type),
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private static diffBindingDefault(
|
|
396
|
+
name: string,
|
|
397
|
+
bb: Record<string, any>,
|
|
398
|
+
cb: Record<string, any>,
|
|
399
|
+
parentIsOptional: boolean,
|
|
400
|
+
facts: SchemaChangeFact[]
|
|
401
|
+
): void {
|
|
402
|
+
if (bb.defaultValue === cb.defaultValue) return;
|
|
403
|
+
if (bb.defaultValue !== undefined && cb.defaultValue === undefined) {
|
|
404
|
+
facts.push({
|
|
405
|
+
changeKind: 'destructured-property-default-removed',
|
|
406
|
+
description: `destructured property '${name}' default value removed (was: ${bb.defaultValue})`,
|
|
407
|
+
context: { propertyName: name, isOptional: parentIsOptional, previousDefault: String(bb.defaultValue) },
|
|
408
|
+
from: String(bb.defaultValue),
|
|
409
|
+
});
|
|
410
|
+
} else if (bb.defaultValue === undefined && cb.defaultValue !== undefined) {
|
|
411
|
+
facts.push({
|
|
412
|
+
changeKind: 'destructured-property-default-added',
|
|
413
|
+
description: `destructured property '${name}' default value added: ${cb.defaultValue}`,
|
|
414
|
+
context: { propertyName: name, newDefault: String(cb.defaultValue) },
|
|
415
|
+
to: String(cb.defaultValue),
|
|
416
|
+
});
|
|
417
|
+
} else {
|
|
418
|
+
facts.push({
|
|
419
|
+
changeKind: 'destructured-property-default-changed',
|
|
420
|
+
description: `destructured property '${name}' default value changed: ${bb.defaultValue} → ${cb.defaultValue}`,
|
|
421
|
+
context: { propertyName: name, previousDefault: String(bb.defaultValue), newDefault: String(cb.defaultValue) },
|
|
422
|
+
from: String(bb.defaultValue),
|
|
423
|
+
to: String(cb.defaultValue),
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
151
428
|
private modifiersToString() {
|
|
152
429
|
const modifiersToPrint = this.modifiers.filter((modifier) => modifier !== 'export');
|
|
153
430
|
return modifiersToPrint.length ? `${modifiersToPrint.join(' ')} ` : '';
|
package/schemas/interface.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import type { SchemaLocation } from '../schema-node';
|
|
3
3
|
import { SchemaNode } from '../schema-node';
|
|
4
|
+
import type { SchemaChangeFact } from '../schema-diff';
|
|
5
|
+
import { diffMembers } from '../schema-diff-members';
|
|
4
6
|
import { DocSchema } from './docs';
|
|
5
7
|
import { ExpressionWithTypeArgumentsSchema } from './expression-with-arguments';
|
|
6
8
|
import { SchemaRegistry } from '../schema-registry';
|
|
@@ -82,6 +84,11 @@ export class InterfaceSchema extends SchemaNode {
|
|
|
82
84
|
};
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
diff(other: SchemaNode): SchemaChangeFact[] {
|
|
88
|
+
if (!(other instanceof InterfaceSchema)) return super.diff(other);
|
|
89
|
+
return diffMembers(this.toObject(), other.toObject(), this, other);
|
|
90
|
+
}
|
|
91
|
+
|
|
85
92
|
static fromObject(obj: Record<string, any>): InterfaceSchema {
|
|
86
93
|
const location = obj.location;
|
|
87
94
|
const name = obj.name;
|
package/schemas/type.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import type { SchemaLocation } from '../schema-node';
|
|
3
3
|
import { SchemaNode } from '../schema-node';
|
|
4
|
+
import type { SchemaChangeFact } from '../schema-diff';
|
|
5
|
+
import { typesAreSemanticallyEqual, diffDoc } from '../schema-diff';
|
|
4
6
|
import { DocSchema } from './docs';
|
|
5
7
|
import { SchemaRegistry } from '../schema-registry';
|
|
6
8
|
|
|
@@ -51,6 +53,22 @@ export class TypeSchema extends SchemaNode {
|
|
|
51
53
|
};
|
|
52
54
|
}
|
|
53
55
|
|
|
56
|
+
diff(other: SchemaNode): SchemaChangeFact[] {
|
|
57
|
+
if (!(other instanceof TypeSchema)) return super.diff(other);
|
|
58
|
+
const facts: SchemaChangeFact[] = [];
|
|
59
|
+
if (!typesAreSemanticallyEqual(this.type.toObject(), other.type.toObject())) {
|
|
60
|
+
facts.push({
|
|
61
|
+
changeKind: 'type-definition-changed',
|
|
62
|
+
description: 'type definition changed',
|
|
63
|
+
context: { fromSignature: this.signature, toSignature: other.signature },
|
|
64
|
+
from: this.signature,
|
|
65
|
+
to: other.signature,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
facts.push(...diffDoc(this.doc?.toObject(), other.doc?.toObject()));
|
|
69
|
+
return facts;
|
|
70
|
+
}
|
|
71
|
+
|
|
54
72
|
static fromObject(obj: Record<string, any>): TypeSchema {
|
|
55
73
|
const location = obj.location;
|
|
56
74
|
const name = obj.name;
|
package/schemas/variable-like.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import type { SchemaLocation } from '../schema-node';
|
|
3
3
|
import { SchemaNode } from '../schema-node';
|
|
4
|
+
import type { SchemaChangeFact } from '../schema-diff';
|
|
5
|
+
import { typesAreSemanticallyEqual, typeStr, diffDoc } from '../schema-diff';
|
|
4
6
|
import { DocSchema } from './docs';
|
|
5
7
|
import { SchemaRegistry } from '../schema-registry';
|
|
6
8
|
|
|
@@ -64,6 +66,58 @@ export class VariableLikeSchema extends SchemaNode {
|
|
|
64
66
|
};
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
diff(other: SchemaNode): SchemaChangeFact[] {
|
|
70
|
+
if (!(other instanceof VariableLikeSchema)) return super.diff(other);
|
|
71
|
+
const facts: SchemaChangeFact[] = [];
|
|
72
|
+
if (!typesAreSemanticallyEqual(this.type.toObject(), other.type.toObject())) {
|
|
73
|
+
facts.push({
|
|
74
|
+
changeKind: 'type-annotation-changed',
|
|
75
|
+
description: `type changed: ${typeStr(this.type.toObject())} → ${typeStr(other.type.toObject())}`,
|
|
76
|
+
context: {
|
|
77
|
+
fromType: typeStr(this.type.toObject()),
|
|
78
|
+
toType: typeStr(other.type.toObject()),
|
|
79
|
+
position: 'variable',
|
|
80
|
+
},
|
|
81
|
+
from: typeStr(this.type.toObject()),
|
|
82
|
+
to: typeStr(other.type.toObject()),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (this.isOptional && !other.isOptional) {
|
|
86
|
+
facts.push({
|
|
87
|
+
changeKind: 'became-required',
|
|
88
|
+
description: 'became required (was optional)',
|
|
89
|
+
context: { position: 'variable' },
|
|
90
|
+
from: 'optional',
|
|
91
|
+
to: 'required',
|
|
92
|
+
});
|
|
93
|
+
} else if (!this.isOptional && other.isOptional) {
|
|
94
|
+
facts.push({
|
|
95
|
+
changeKind: 'became-optional',
|
|
96
|
+
description: 'became optional (was required)',
|
|
97
|
+
context: { position: 'variable' },
|
|
98
|
+
from: 'required',
|
|
99
|
+
to: 'optional',
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (this.defaultValue !== other.defaultValue) {
|
|
103
|
+
const changeKind =
|
|
104
|
+
this.defaultValue === undefined
|
|
105
|
+
? 'parameter-default-added'
|
|
106
|
+
: other.defaultValue === undefined
|
|
107
|
+
? 'parameter-default-removed'
|
|
108
|
+
: 'parameter-default-changed';
|
|
109
|
+
facts.push({
|
|
110
|
+
changeKind,
|
|
111
|
+
description: `default value changed: ${this.defaultValue ?? 'none'} → ${other.defaultValue ?? 'none'}`,
|
|
112
|
+
context: { previousDefault: this.defaultValue, newDefault: other.defaultValue },
|
|
113
|
+
from: this.defaultValue,
|
|
114
|
+
to: other.defaultValue,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
facts.push(...diffDoc(this.doc?.toObject(), other.doc?.toObject()));
|
|
118
|
+
return facts;
|
|
119
|
+
}
|
|
120
|
+
|
|
67
121
|
static fromObject(obj: Record<string, any>): VariableLikeSchema {
|
|
68
122
|
const location = obj.location;
|
|
69
123
|
const name = obj.name;
|