jsii-diff 1.117.0 → 1.119.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.
@@ -49,7 +49,9 @@ const d = new Dog({ name: 'Fido' });
49
49
  console.log(d.name.toLowerCase());
50
50
 
51
51
  // Not valid anymore after the type of `d.name` has changed into `string | undefined`.
52
- // 'd.name' can be undefined, and we have to account for that with an `if`!
52
+ // 'd.name' can be undefined, and calling `undefined.toLowerCase()` would throw an error.
53
+ // The user will have to account for that with an `if`, which means changing their code,
54
+ // which means a breaking change.
53
55
  ```
54
56
 
55
57
  ### Optional properties: how to solve
@@ -83,6 +85,30 @@ This doesn't break any existing users: all their Dogs will have names, so they w
83
85
 
84
86
  For new users that fail to give their Dog a name, presumably they will be aware that their Dog doesn't have a name, so they can avoid trying to read it. If you want to give them a way to avoid the exception, add a `public get hasName(): boolean` field so they can test for the existence of the name before accessing it.
85
87
 
88
+ ### Optional properties: what about structs?
89
+
90
+ In the above example, we said that `DogOptions#name` was an *input* and `Dog#name` was an *output*. Does that mean it's
91
+ always okay to change struct (data interface) fields to optional?
92
+
93
+ Not necessarily! It depends on how the struct is used. If the struct is used as the return value of a method or the
94
+ type of a class proeprty somewhere, it is in *output position* and all of its fields are as well. So if you have the following
95
+ class:
96
+
97
+ ```ts
98
+ class Dog {
99
+ public readonly options: DogOptions; // DogOptions is an OUTPUT
100
+
101
+ constructor(options: DogOptions) { // DogOptions is an INPUT
102
+ this.options = options;
103
+ }
104
+ }
105
+ ```
106
+
107
+ Then `DogOptions` is now both in input as well as output position, and you're not allowed to make anything optional anymore!
108
+
109
+ (That's why using the same struct name to represent both input and output data is best avoided, because it limits
110
+ evolvability).
111
+
86
112
  ## Changing types to superclass/subclass
87
113
 
88
114
  When changing types involved in an operation, you run into a similar issue as with changing the optionality of a property:
package/README.md CHANGED
@@ -126,6 +126,45 @@ abstract members yet.
126
126
  for subclassing, but treating them as such would limit the evolvability of
127
127
  libraries too much.
128
128
 
129
+ ## Accepting breaking changes
130
+
131
+ Sometimes you want to move forward with a change, even if it would technically
132
+ be a breaking change to your API. In order to do that, run `jsii-diff`
133
+ with the flag `--keys`. It will then print an identifier for every violation
134
+ between square brackets, for example:
135
+
136
+ ```
137
+ $ jsii-diff <old> --keys
138
+ IFACE pkg.MyStruct: formerly required property 'prop' is optional: returned from pkg.IConsumer.someMethod [weakened:pkg.MyStruct]
139
+ ```
140
+
141
+ To accept a breaking finding, put the key (in this example `weakened:pkg.MyStruct`)
142
+ into a text file, for example `allowed-breaking-changes.txt`, and pass it to
143
+ `jsii-diff` as an ignore file:
144
+
145
+ ```
146
+ $ jsii-diff <old> --keys --ignore-file allowed-breaking-changes.txt
147
+ (no error)
148
+ ```
149
+
150
+ ### Moving/renaming API elements
151
+
152
+ If you've moved API elements around between versions of your library, you can
153
+ put a special ignore marker starting with `move:` into your `--ignore-file`. To
154
+ separate the old and new class names, you can use `:`, `,` or whitespace.
155
+
156
+ For example:
157
+
158
+ ```
159
+ move:package.OldClassName package.NewClassName
160
+ move:package.OldClassName:package.NewClassName
161
+ move:package.OldClassName, package.NewClassName
162
+ ```
163
+
164
+ Moving API elements is always breaking, but using this feature you can confirm
165
+ that you at least didn't break anything in the API surface of the moved classes
166
+ themselves.
167
+
129
168
  ## Help! jsii-diff is marking my changes as breaking
130
169
 
131
170
  See [BREAKING_CHANGES.md](./BREAKING_CHANGES.md) for more information.
package/bin/jsii-diff.js CHANGED
@@ -91,13 +91,16 @@ async function main() {
91
91
  if (original.name !== updated.name) {
92
92
  process.stderr.write(`Look like different assemblies: '${original.name}' vs '${updated.name}'. Comparing is probably pointless...\n`);
93
93
  }
94
+ const allowedBreakingChanges = await loadFilter(argv['ignore-file']);
95
+ const fqnRemapping = extractFqnRemappings(allowedBreakingChanges);
94
96
  LOG.info('Starting analysis');
95
97
  const mismatches = (0, lib_1.compareAssemblies)(original, updated, {
96
98
  defaultExperimental: argv['default-stability'] === 'experimental',
99
+ fqnRemapping,
97
100
  });
98
101
  LOG.info(`Found ${mismatches.count} issues`);
99
102
  if (mismatches.count > 0) {
100
- const diags = (0, diagnostics_1.classifyDiagnostics)(mismatches, (0, diagnostics_1.treatAsError)(argv['error-on'], argv['experimental-errors']), await loadFilter(argv['ignore-file']));
103
+ const diags = (0, diagnostics_1.classifyDiagnostics)(mismatches, (0, diagnostics_1.treatAsError)(argv['error-on'], argv['experimental-errors']), allowedBreakingChanges);
101
104
  process.stderr.write(`Original assembly: ${original.name}@${original.version}\n`);
102
105
  process.stderr.write(`Updated assembly: ${updated.name}@${updated.version}\n`);
103
106
  process.stderr.write('API elements with incompatible changes:\n');
@@ -108,6 +111,35 @@ async function main() {
108
111
  }
109
112
  return 0;
110
113
  }
114
+ /**
115
+ * Extract all lines that start with `move:` from the given string set
116
+ *
117
+ * Interpret them as `move:OLDFQN <sep> NEWFQN`, mapping moved FQNs.
118
+ *
119
+ * Separator can be any of `:`, comma or whitespace.
120
+ *
121
+ * Modifies the input set in-place.
122
+ */
123
+ function extractFqnRemappings(allowedBreakingChanges) {
124
+ const ret = {};
125
+ for (const line of Array.from(allowedBreakingChanges)) {
126
+ const prefix = 'move:';
127
+ if (!line.startsWith(prefix)) {
128
+ continue;
129
+ }
130
+ const parts = line
131
+ .slice(prefix.length)
132
+ .trim()
133
+ .split(/[:, \t]+/g);
134
+ if (parts.length !== 2) {
135
+ throw new Error(`Invalid moved FQN declaration: ${line}. Expected format is 'move:old:new'`);
136
+ }
137
+ const [oldFqn, newFqn] = parts;
138
+ ret[oldFqn] = newFqn;
139
+ allowedBreakingChanges.delete(line);
140
+ }
141
+ return ret;
142
+ }
111
143
  // Allow both npm:<package> (legacy) and npm://<package> (looks better)
112
144
  const NPM_REGEX = /^npm:(\/\/)?/;
113
145
  /**
@@ -234,7 +266,7 @@ async function loadFilter(filterFilename) {
234
266
  return new Set((await fs.readFile(filterFilename, { encoding: 'utf-8' }))
235
267
  .split('\n')
236
268
  .map((x) => x.trim())
237
- .filter((x) => !x.startsWith('#')));
269
+ .filter((x) => x && !x.startsWith('#')));
238
270
  }
239
271
  catch (e) {
240
272
  if (e.code !== 'ENOENT') {
@@ -1,34 +1,39 @@
1
1
  import * as reflect from 'jsii-reflect';
2
- /**
3
- * Check whether A is a supertype of B
4
- *
5
- * Put differently: whether any value of type B would be assignable to a
6
- * variable of type A.
7
- *
8
- * We always check the relationship in the NEW (latest, updated) typesystem.
9
- */
10
- export declare function isSuperType(a: reflect.TypeReference, b: reflect.TypeReference, updatedSystem: reflect.TypeSystem): Analysis;
11
- /**
12
- * Find types A and B in the updated type system, and check whether they have a supertype relationship in the type system
13
- */
14
- export declare function isNominalSuperType(a: reflect.TypeReference, b: reflect.TypeReference, updatedSystem: reflect.TypeSystem): Analysis;
15
- /**
16
- * Is struct A a structural supertype of struct B?
17
- *
18
- * Trying to answer the question, is this assignment legal for all values
19
- * of `expr in B`.
20
- *
21
- * ```ts
22
- * const var: A = expr as B;
23
- * ```
24
- *
25
- * A is a structural supertype of B if all required members of A are also
26
- * required in B, and of a compatible type.
27
- *
28
- * Nullable members of A must either not exist in B, or be of a compatible
29
- * type.
30
- */
31
- export declare function isStructuralSuperType(a: reflect.InterfaceType, b: reflect.InterfaceType, updatedSystem: reflect.TypeSystem): Analysis;
2
+ export declare class TypeAnalysis {
3
+ private readonly updatedSystem;
4
+ private readonly fqnRemapping;
5
+ constructor(updatedSystem: reflect.TypeSystem, fqnRemapping?: Record<string, string>);
6
+ /**
7
+ * Check whether A is a supertype of B
8
+ *
9
+ * Put differently: whether any value of type B would be assignable to a
10
+ * variable of type A.
11
+ *
12
+ * We always check the relationship in the NEW (latest, updated) typesystem.
13
+ */
14
+ isSuperType(a: reflect.TypeReference, b: reflect.TypeReference): Analysis;
15
+ /**
16
+ * Find types A and B in the updated type system, and check whether they have a supertype relationship in the type system
17
+ */
18
+ isNominalSuperType(a: reflect.TypeReference, b: reflect.TypeReference): Analysis;
19
+ /**
20
+ * Is struct A a structural supertype of struct B?
21
+ *
22
+ * Trying to answer the question, is this assignment legal for all values
23
+ * of `expr in B`.
24
+ *
25
+ * ```ts
26
+ * const var: A = expr as B;
27
+ * ```
28
+ *
29
+ * A is a structural supertype of B if all required members of A are also
30
+ * required in B, and of a compatible type.
31
+ *
32
+ * Nullable members of A must either not exist in B, or be of a compatible
33
+ * type.
34
+ */
35
+ isStructuralSuperType(a: reflect.InterfaceType, b: reflect.InterfaceType): Analysis;
36
+ }
32
37
  export type Analysis = {
33
38
  success: true;
34
39
  } | FailedAnalysis;
@@ -1,180 +1,185 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isSuperType = isSuperType;
4
- exports.isNominalSuperType = isNominalSuperType;
5
- exports.isStructuralSuperType = isStructuralSuperType;
3
+ exports.TypeAnalysis = void 0;
6
4
  exports.prependReason = prependReason;
7
5
  const util_1 = require("./util");
8
- /**
9
- * Check whether A is a supertype of B
10
- *
11
- * Put differently: whether any value of type B would be assignable to a
12
- * variable of type A.
13
- *
14
- * We always check the relationship in the NEW (latest, updated) typesystem.
15
- */
16
- function isSuperType(a, b, updatedSystem) {
17
- if (a.void || b.void) {
18
- throw new Error('isSuperType() does not handle voids');
19
- }
20
- if (a.isAny) {
21
- return { success: true };
22
- }
23
- if (a.primitive !== undefined) {
24
- if (a.primitive === b.primitive) {
6
+ class TypeAnalysis {
7
+ constructor(updatedSystem, fqnRemapping = {}) {
8
+ this.updatedSystem = updatedSystem;
9
+ this.fqnRemapping = fqnRemapping;
10
+ }
11
+ /**
12
+ * Check whether A is a supertype of B
13
+ *
14
+ * Put differently: whether any value of type B would be assignable to a
15
+ * variable of type A.
16
+ *
17
+ * We always check the relationship in the NEW (latest, updated) typesystem.
18
+ */
19
+ isSuperType(a, b) {
20
+ if (a.void || b.void) {
21
+ throw new Error('isSuperType() does not handle voids');
22
+ }
23
+ if (a.isAny) {
25
24
  return { success: true };
26
25
  }
27
- return failure(`${b.toString()} is not assignable to ${a.toString()}`);
28
- }
29
- if (a.arrayOfType !== undefined) {
30
- // Arrays are covariant
31
- if (b.arrayOfType === undefined) {
32
- return failure(`${b.toString()} is not an array type`);
26
+ if (a.primitive !== undefined) {
27
+ if (a.primitive === b.primitive) {
28
+ return { success: true };
29
+ }
30
+ return failure(`${b.toString()} is not assignable to ${a.toString()}`);
33
31
  }
34
- return prependReason(isSuperType(a.arrayOfType, b.arrayOfType, updatedSystem), `${b.toString()} is not assignable to ${a.toString()}`);
35
- }
36
- if (a.mapOfType !== undefined) {
37
- // Maps are covariant (are they?)
38
- if (b.mapOfType === undefined) {
39
- return failure(`${b.toString()} is not a map type`);
32
+ if (a.arrayOfType !== undefined) {
33
+ // Arrays are covariant
34
+ if (b.arrayOfType === undefined) {
35
+ return failure(`${b.toString()} is not an array type`);
36
+ }
37
+ return prependReason(this.isSuperType(a.arrayOfType, b.arrayOfType), `${b.toString()} is not assignable to ${a.toString()}`);
40
38
  }
41
- return prependReason(isSuperType(a.mapOfType, b.mapOfType, updatedSystem), `${b.toString()} is not assignable to ${a.toString()}`);
42
- }
43
- // Every element of B can be assigned to A
44
- if (b.unionOfTypes !== undefined) {
45
- const analyses = b.unionOfTypes.map((bbb) => isSuperType(a, bbb, updatedSystem));
46
- if (analyses.every((x) => x.success)) {
47
- return { success: true };
39
+ if (a.mapOfType !== undefined) {
40
+ // Maps are covariant (are they?)
41
+ if (b.mapOfType === undefined) {
42
+ return failure(`${b.toString()} is not a map type`);
43
+ }
44
+ return prependReason(this.isSuperType(a.mapOfType, b.mapOfType), `${b.toString()} is not assignable to ${a.toString()}`);
48
45
  }
49
- return failure(`some of ${b.toString()} are not assignable to ${a.toString()}`, ...(0, util_1.flatMap)(analyses, (x) => (x.success ? [] : x.reasons)));
50
- }
51
- // There should be an element of A which can accept all of B
52
- if (a.unionOfTypes !== undefined) {
53
- const analyses = a.unionOfTypes.map((aaa) => isSuperType(aaa, b, updatedSystem));
54
- if (analyses.some((x) => x.success)) {
46
+ // Every element of B can be assigned to A
47
+ if (b.unionOfTypes !== undefined) {
48
+ const analyses = b.unionOfTypes.map((bbb) => this.isSuperType(a, bbb));
49
+ if (analyses.every((x) => x.success)) {
50
+ return { success: true };
51
+ }
52
+ return failure(`some of ${b.toString()} are not assignable to ${a.toString()}`, ...(0, util_1.flatMap)(analyses, (x) => (x.success ? [] : x.reasons)));
53
+ }
54
+ // There should be an element of A which can accept all of B
55
+ if (a.unionOfTypes !== undefined) {
56
+ const analyses = a.unionOfTypes.map((aaa) => this.isSuperType(aaa, b));
57
+ if (analyses.some((x) => x.success)) {
58
+ return { success: true };
59
+ }
60
+ return failure(`none of ${b.toString()} are assignable to ${a.toString()}`, ...(0, util_1.flatMap)(analyses, (x) => (x.success ? [] : x.reasons)));
61
+ }
62
+ // intersection A ⊒ B <=> all of the elements of A ⊒ B
63
+ if (a.intersectionOfTypes !== undefined) {
64
+ const analyses = a.intersectionOfTypes.map((aaa) => this.isSuperType(aaa, b));
65
+ if (analyses.every((x) => x.success)) {
66
+ return { success: true };
67
+ }
68
+ return failure(`${b.toString()} is not assignable to all of ${a.toString()}`, ...(0, util_1.flatMap)(analyses, (x) => (x.success ? [] : x.reasons)));
69
+ }
70
+ // A ⊒ intersection B <=> A ⊒ any of the elements of B
71
+ if (b.intersectionOfTypes !== undefined) {
72
+ const analyses = b.intersectionOfTypes.map((bbb) => this.isSuperType(a, bbb));
73
+ if (analyses.some((x) => x.success)) {
74
+ return { success: true };
75
+ }
76
+ return failure(`some of ${b.toString()} are not assignable to ${a.toString()}`, ...(0, util_1.flatMap)(analyses, (x) => (x.success ? [] : x.reasons)));
77
+ }
78
+ // We have two named types, recursion might happen so protect against it.
79
+ try {
80
+ // For named types, we'll always do a nominal typing relationship.
81
+ // That is, if in the updated typesystem someone were to use the type name
82
+ // from the old assembly, do they have a typing relationship that's accepted
83
+ // by a nominal type system. (That check also rules out enums)
84
+ const nominalCheck = this.isNominalSuperType(a, b);
85
+ if (nominalCheck.success === false) {
86
+ return nominalCheck;
87
+ }
88
+ // At this point, the only thing left to do is recurse into the structs.
89
+ // We used to do that here, but we don't anymore; structs check themselves
90
+ // for structural weakening/strengthening.
55
91
  return { success: true };
56
92
  }
57
- return failure(`none of ${b.toString()} are assignable to ${a.toString()}`, ...(0, util_1.flatMap)(analyses, (x) => (x.success ? [] : x.reasons)));
93
+ catch (e) {
94
+ return failure(e.message);
95
+ }
58
96
  }
59
- // intersection A ⊒ B <=> all of the elements of A ⊒ B
60
- if (a.intersectionOfTypes !== undefined) {
61
- const analyses = a.intersectionOfTypes.map((aaa) => isSuperType(aaa, b, updatedSystem));
62
- if (analyses.every((x) => x.success)) {
97
+ /**
98
+ * Find types A and B in the updated type system, and check whether they have a supertype relationship in the type system
99
+ */
100
+ isNominalSuperType(a, b) {
101
+ if (a.fqn === undefined) {
102
+ throw new Error(`I was expecting a named type, got '${a.toString()}'`);
103
+ }
104
+ // Named type vs a non-named type
105
+ if (b.fqn === undefined) {
106
+ return failure(`${b.toString()} is not assignable to ${a.toString()}`);
107
+ }
108
+ // Short-circuit of the types are the same name, saves us some lookup
109
+ if (a.fqn === b.fqn) {
63
110
  return { success: true };
64
111
  }
65
- return failure(`${b.toString()} is not assignable to all of ${a.toString()}`, ...(0, util_1.flatMap)(analyses, (x) => (x.success ? [] : x.reasons)));
66
- }
67
- // A ⊒ intersection B <=> A any of the elements of B
68
- if (b.intersectionOfTypes !== undefined) {
69
- const analyses = b.intersectionOfTypes.map((bbb) => isSuperType(a, bbb, updatedSystem));
70
- if (analyses.some((x) => x.success)) {
112
+ // We now need to do subtype analysis on the
113
+ // Find A in B's typesystem, and see if B is a subtype of A'
114
+ const B = this.updatedSystem.tryFindFqn(this.fqnRemapping[b.fqn] ?? b.fqn);
115
+ const A = this.updatedSystem.tryFindFqn(this.fqnRemapping[a.fqn] ?? a.fqn);
116
+ if (!B) {
117
+ return failure(`could not find type ${b.toString()}`);
118
+ }
119
+ if (!A) {
120
+ return failure(`could not find type ${a.toString()}`);
121
+ }
122
+ // If they're enums, they should have been exactly the same (tested above)
123
+ // enums are never subtypes of any other type.
124
+ if (A.isEnumType()) {
125
+ return failure(`${a.toString()} is an enum different from ${b.toString()}`);
126
+ }
127
+ if (B.isEnumType()) {
128
+ return failure(`${b.toString()} is an enum different from ${a.toString()}`);
129
+ }
130
+ if (B.extends(A)) {
71
131
  return { success: true };
72
132
  }
73
- return failure(`some of ${b.toString()} are not assignable to ${a.toString()}`, ...(0, util_1.flatMap)(analyses, (x) => (x.success ? [] : x.reasons)));
74
- }
75
- // We have two named types, recursion might happen so protect against it.
76
- try {
77
- // For named types, we'll always do a nominal typing relationship.
78
- // That is, if in the updated typesystem someone were to use the type name
79
- // from the old assembly, do they have a typing relationship that's accepted
80
- // by a nominal type system. (That check also rules out enums)
81
- const nominalCheck = isNominalSuperType(a, b, updatedSystem);
82
- if (nominalCheck.success === false) {
83
- return nominalCheck;
84
- }
85
- // At this point, the only thing left to do is recurse into the structs.
86
- // We used to do that here, but we don't anymore; structs check themselves
87
- // for structural weakening/strengthening.
88
- return { success: true };
89
- }
90
- catch (e) {
91
- return failure(e.message);
92
- }
93
- }
94
- /**
95
- * Find types A and B in the updated type system, and check whether they have a supertype relationship in the type system
96
- */
97
- function isNominalSuperType(a, b, updatedSystem) {
98
- if (a.fqn === undefined) {
99
- throw new Error(`I was expecting a named type, got '${a.toString()}'`);
100
- }
101
- // Named type vs a non-named type
102
- if (b.fqn === undefined) {
103
- return failure(`${b.toString()} is not assignable to ${a.toString()}`);
104
- }
105
- // Short-circuit of the types are the same name, saves us some lookup
106
- if (a.fqn === b.fqn) {
107
- return { success: true };
108
- }
109
- // We now need to do subtype analysis on the
110
- // Find A in B's typesystem, and see if B is a subtype of A'
111
- const B = updatedSystem.tryFindFqn(b.fqn);
112
- const A = updatedSystem.tryFindFqn(a.fqn);
113
- if (!B) {
114
- return failure(`could not find type ${b.toString()}`);
115
- }
116
- if (!A) {
117
- return failure(`could not find type ${a.toString()}`);
118
- }
119
- // If they're enums, they should have been exactly the same (tested above)
120
- // enums are never subtypes of any other type.
121
- if (A.isEnumType()) {
122
- return failure(`${a.toString()} is an enum different from ${b.toString()}`);
123
- }
124
- if (B.isEnumType()) {
125
- return failure(`${b.toString()} is an enum different from ${a.toString()}`);
126
- }
127
- if (B.extends(A)) {
128
- return { success: true };
129
- }
130
- return failure(`${b.toString()} does not extend ${a.toString()}`);
131
- }
132
- /**
133
- * Is struct A a structural supertype of struct B?
134
- *
135
- * Trying to answer the question, is this assignment legal for all values
136
- * of `expr in B`.
137
- *
138
- * ```ts
139
- * const var: A = expr as B;
140
- * ```
141
- *
142
- * A is a structural supertype of B if all required members of A are also
143
- * required in B, and of a compatible type.
144
- *
145
- * Nullable members of A must either not exist in B, or be of a compatible
146
- * type.
147
- */
148
- function isStructuralSuperType(a, b, updatedSystem) {
149
- // We know all members can only be properties, so that makes it easier.
150
- const bProps = b.getProperties(true);
151
- // Use timing words in error message to make it more understandable
152
- const formerly = b.system === updatedSystem ? 'formerly' : 'newly';
153
- const is = b.system === updatedSystem ? 'is' : 'used to be';
154
- const removed = b.system === updatedSystem ? 'removed' : 'added';
155
- for (const [name, aProp] of Object.entries(a.getProperties(true))) {
156
- const bProp = bProps[name];
157
- if (aProp.optional) {
158
- // Optional field, only requirement is that IF it exists, the type must match.
159
- if (!bProp) {
160
- continue;
133
+ return failure(`${b.toString()} does not extend ${a.toString()}`);
134
+ }
135
+ /**
136
+ * Is struct A a structural supertype of struct B?
137
+ *
138
+ * Trying to answer the question, is this assignment legal for all values
139
+ * of `expr in B`.
140
+ *
141
+ * ```ts
142
+ * const var: A = expr as B;
143
+ * ```
144
+ *
145
+ * A is a structural supertype of B if all required members of A are also
146
+ * required in B, and of a compatible type.
147
+ *
148
+ * Nullable members of A must either not exist in B, or be of a compatible
149
+ * type.
150
+ */
151
+ isStructuralSuperType(a, b) {
152
+ // We know all members can only be properties, so that makes it easier.
153
+ const bProps = b.getProperties(true);
154
+ // Use timing words in error message to make it more understandable
155
+ const formerly = b.system === this.updatedSystem ? 'formerly' : 'newly';
156
+ const is = b.system === this.updatedSystem ? 'is' : 'used to be';
157
+ const removed = b.system === this.updatedSystem ? 'removed' : 'added';
158
+ for (const [name, aProp] of Object.entries(a.getProperties(true))) {
159
+ const bProp = bProps[name];
160
+ if (aProp.optional) {
161
+ // Optional field, only requirement is that IF it exists, the type must match.
162
+ if (!bProp) {
163
+ continue;
164
+ }
161
165
  }
162
- }
163
- else {
164
- if (!bProp) {
165
- return failure(`${formerly} required property '${name}' ${removed}`);
166
+ else {
167
+ if (!bProp) {
168
+ return failure(`${formerly} required property '${name}' ${removed}`);
169
+ }
170
+ if (bProp.optional) {
171
+ return failure(`${formerly} required property '${name}' ${is} optional`);
172
+ }
166
173
  }
167
- if (bProp.optional) {
168
- return failure(`${formerly} required property '${name}' ${is} optional`);
174
+ const ana = this.isSuperType(aProp.type, bProp.type);
175
+ if (!ana.success) {
176
+ return failure(`property ${name}`, ...ana.reasons);
169
177
  }
170
178
  }
171
- const ana = isSuperType(aProp.type, bProp.type, updatedSystem);
172
- if (!ana.success) {
173
- return failure(`property ${name}`, ...ana.reasons);
174
- }
179
+ return { success: true };
175
180
  }
176
- return { success: true };
177
181
  }
182
+ exports.TypeAnalysis = TypeAnalysis;
178
183
  function failure(...reasons) {
179
184
  return { success: false, reasons };
180
185
  }
@@ -24,6 +24,10 @@ export declare class AssemblyComparison {
24
24
  * Based on a JSII TypeReference, return all reachable ComparableType<> objects.
25
25
  */
26
26
  typesIn(ref: reflect.TypeReference): Array<ComparableType<any>>;
27
+ /**
28
+ * Return the type's FQN, running it through the translation table if present.
29
+ */
30
+ private resolveFqn;
27
31
  /**
28
32
  * All ComparableType<>s
29
33
  */
@@ -44,10 +48,12 @@ export declare abstract class ComparableType<T> {
44
48
  protected readonly assemblyComparison: AssemblyComparison;
45
49
  protected readonly oldType: T;
46
50
  protected readonly newType: T;
51
+ protected readonly displayFqn: string;
47
52
  private static readonly recursionBreaker;
48
53
  private readonly _inputTypeReasons;
49
54
  private readonly _outputTypeReasons;
50
- constructor(assemblyComparison: AssemblyComparison, oldType: T, newType: T);
55
+ constructor(assemblyComparison: AssemblyComparison, oldType: T, newType: T, displayFqn: string);
56
+ get fqnRemapping(): Record<string, string>;
51
57
  /**
52
58
  * Does this type occur in an input role?
53
59
  */
@@ -33,7 +33,8 @@ class AssemblyComparison {
33
33
  load(original, updated) {
34
34
  /* eslint-disable prettier/prettier */
35
35
  for (const [origClass, updatedClass] of this.typePairs(original.allClasses, updated)) {
36
- this.types.set(origClass.fqn, new ComparableClassType(this, origClass, updatedClass));
36
+ const { fqn, displayFqn } = this.resolveFqn(origClass);
37
+ this.types.set(fqn, new ComparableClassType(this, origClass, updatedClass, displayFqn));
37
38
  }
38
39
  for (const [origIface, updatedIface] of this.typePairs(original.allInterfaces, updated)) {
39
40
  if (origIface.datatype !== updatedIface.datatype) {
@@ -44,12 +45,14 @@ class AssemblyComparison {
44
45
  });
45
46
  continue;
46
47
  }
47
- this.types.set(origIface.fqn, origIface.datatype
48
- ? new ComparableStructType(this, origIface, updatedIface)
49
- : new ComparableInterfaceType(this, origIface, updatedIface));
48
+ const { fqn, displayFqn } = this.resolveFqn(origIface);
49
+ this.types.set(fqn, origIface.datatype
50
+ ? new ComparableStructType(this, origIface, updatedIface, displayFqn)
51
+ : new ComparableInterfaceType(this, origIface, updatedIface, displayFqn));
50
52
  }
51
53
  for (const [origEnum, updatedEnum] of this.typePairs(original.allEnums, updated)) {
52
- this.types.set(origEnum.fqn, new ComparableEnumType(this, origEnum, updatedEnum));
54
+ const { fqn, displayFqn } = this.resolveFqn(origEnum);
55
+ this.types.set(fqn, new ComparableEnumType(this, origEnum, updatedEnum, displayFqn));
53
56
  }
54
57
  /* eslint-enable prettier/prettier */
55
58
  }
@@ -67,13 +70,24 @@ class AssemblyComparison {
67
70
  typesIn(ref) {
68
71
  const ret = new Array();
69
72
  for (const fqn of fqnsFrom(ref)) {
70
- const t = this.types.get(fqn);
73
+ const t = this.types.get(this.resolveFqn(fqn).fqn);
71
74
  if (t) {
72
75
  ret.push(t);
73
76
  }
74
77
  }
75
78
  return ret;
76
79
  }
80
+ /**
81
+ * Return the type's FQN, running it through the translation table if present.
82
+ */
83
+ resolveFqn(x) {
84
+ const fqn = typeof x === 'string' ? x : x.fqn;
85
+ const finalFqn = this.options.fqnRemapping?.[fqn] ?? fqn;
86
+ if (fqn !== finalFqn) {
87
+ return { fqn: finalFqn, displayFqn: `${fqn} -> ${finalFqn}` };
88
+ }
89
+ return { fqn, displayFqn: fqn };
90
+ }
77
91
  /**
78
92
  * All ComparableType<>s
79
93
  */
@@ -85,8 +99,9 @@ class AssemblyComparison {
85
99
  */
86
100
  *typePairs(xs, updatedAssembly) {
87
101
  for (const origType of xs) {
88
- LOG.trace(origType.fqn);
89
- const updatedType = updatedAssembly.tryFindType(origType.fqn);
102
+ const { fqn, displayFqn } = this.resolveFqn(origType);
103
+ LOG.trace(displayFqn);
104
+ const updatedType = updatedAssembly.tryFindType(fqn);
90
105
  if (!updatedType) {
91
106
  this.mismatches.report({
92
107
  ruleKey: 'removed',
@@ -116,13 +131,17 @@ exports.AssemblyComparison = AssemblyComparison;
116
131
  * object.
117
132
  */
118
133
  class ComparableType {
119
- constructor(assemblyComparison, oldType, newType) {
134
+ constructor(assemblyComparison, oldType, newType, displayFqn) {
120
135
  this.assemblyComparison = assemblyComparison;
121
136
  this.oldType = oldType;
122
137
  this.newType = newType;
138
+ this.displayFqn = displayFqn;
123
139
  this._inputTypeReasons = new Array();
124
140
  this._outputTypeReasons = new Array();
125
141
  }
142
+ get fqnRemapping() {
143
+ return this.assemblyComparison.options.fqnRemapping ?? {};
144
+ }
126
145
  /**
127
146
  * Does this type occur in an input role?
128
147
  */
@@ -208,9 +227,9 @@ class ComparableReferenceType extends ComparableType {
208
227
  * Compare members of the reference types
209
228
  */
210
229
  compare() {
211
- LOG.debug(`Reference type ${this.oldType.fqn}`);
230
+ LOG.debug(`Reference type ${this.displayFqn}`);
212
231
  (0, stability_1.validateStabilities)(this.oldType, this.newType, this.mismatches);
213
- (0, validations_1.validateBaseTypeAssignability)(this.oldType, this.newType, this.mismatches);
232
+ (0, validations_1.validateBaseTypeAssignability)(this.oldType, this.newType, this.fqnRemapping, this.mismatches);
214
233
  (0, validations_1.validateSubclassableNotRemoved)(this.oldType, this.newType, this.mismatches);
215
234
  if (this.subclassableType) {
216
235
  (0, validations_1.validateNoNewAbstractMembers)(this.oldType, this.newType, this.mismatches);
@@ -249,7 +268,7 @@ class ComparableReferenceType extends ComparableType {
249
268
  (0, validations_1.validateReturnTypeSame)(original, updated, this.mismatches.withMotivation('type is @subclassable'));
250
269
  }
251
270
  else {
252
- (0, validations_1.validateReturnTypeNotWeakened)(original, updated, this.mismatches);
271
+ (0, validations_1.validateReturnTypeNotWeakened)(original, updated, this.fqnRemapping, this.mismatches);
253
272
  }
254
273
  this.validateCallable(original, updated);
255
274
  }
@@ -265,7 +284,7 @@ class ComparableReferenceType extends ComparableType {
265
284
  (0, validations_1.validateParameterTypeSame)(original, oldParam, newParam, this.mismatches.withMotivation('type is @subclassable'));
266
285
  }
267
286
  else {
268
- (0, validations_1.validateParameterTypeWeakened)(original, oldParam, newParam, this.mismatches);
287
+ (0, validations_1.validateParameterTypeWeakened)(original, oldParam, newParam, this.fqnRemapping, this.mismatches);
269
288
  }
270
289
  });
271
290
  (0, validations_1.validateNoNewRequiredParams)(original, updated, this.mismatches);
@@ -298,7 +317,7 @@ class ComparableReferenceType extends ComparableType {
298
317
  (0, validations_1.validatePropertyTypeSame)(original, updated, this.mismatches.withMotivation('mutable property cannot change type'));
299
318
  }
300
319
  else {
301
- (0, validations_1.validatePropertyTypeNotWeakened)(original, updated, this.mismatches);
320
+ (0, validations_1.validatePropertyTypeNotWeakened)(original, updated, this.fqnRemapping, this.mismatches);
302
321
  }
303
322
  }
304
323
  /**
@@ -318,7 +337,7 @@ class ComparableClassType extends ComparableReferenceType {
318
337
  (0, validations_1.validateNotMadeAbstract)(this.oldType, this.newType, this.mismatches);
319
338
  // JSII assembler has already taken care of inheritance here
320
339
  if (this.oldType.initializer && this.newType.initializer) {
321
- (0, validations_1.validateMethodCompatible)(this.oldType.initializer, this.newType.initializer, this.mismatches);
340
+ (0, validations_1.validateMethodCompatible)(this.oldType.initializer, this.newType.initializer, this.fqnRemapping, this.mismatches);
322
341
  }
323
342
  }
324
343
  /**
@@ -348,9 +367,9 @@ exports.ComparableInterfaceType = ComparableInterfaceType;
348
367
  */
349
368
  class ComparableStructType extends ComparableType {
350
369
  compare() {
351
- LOG.debug(`Struct type ${this.oldType.fqn}`);
370
+ LOG.debug(`Struct type ${this.displayFqn}`);
352
371
  (0, stability_1.validateStabilities)(this.oldType, this.newType, this.mismatches);
353
- (0, validations_1.validateBaseTypeAssignability)(this.oldType, this.newType, this.mismatches);
372
+ (0, validations_1.validateBaseTypeAssignability)(this.oldType, this.newType, this.fqnRemapping, this.mismatches);
354
373
  this.validateNoPropertiesRemoved();
355
374
  if (this.inputType) {
356
375
  // If the struct is written, it can't be strengthened (ex: can't change an optional property to required)
@@ -409,7 +428,7 @@ class ComparableStructType extends ComparableType {
409
428
  }
410
429
  isStructuralSuperType(a, b) {
411
430
  try {
412
- return (0, type_analysis_1.isStructuralSuperType)(a, b, this.newType.system);
431
+ return new type_analysis_1.TypeAnalysis(this.newType.system, this.fqnRemapping).isStructuralSuperType(a, b);
413
432
  }
414
433
  catch (e) {
415
434
  // We might get an exception if the type is supposed to come from a different
@@ -427,7 +446,7 @@ class ComparableEnumType extends ComparableType {
427
446
  * Perform comparisons on enum members
428
447
  */
429
448
  compare() {
430
- LOG.debug(`Enum type ${this.oldType.fqn}`);
449
+ LOG.debug(`Enum type ${this.displayFqn}`);
431
450
  (0, stability_1.validateStabilities)(this.oldType, this.newType, this.mismatches);
432
451
  (0, validations_1.validateExistingMembers)(this.oldType, this.newType, this.mismatches, (oldMember, newMember) => {
433
452
  (0, stability_1.validateStabilities)(oldMember, newMember, this.mismatches);
package/lib/types.d.ts CHANGED
@@ -7,6 +7,10 @@ export interface ComparisonOptions {
7
7
  * @default Treat as stable
8
8
  */
9
9
  defaultExperimental?: boolean;
10
+ /**
11
+ * Mapping old FQNs to new ones
12
+ */
13
+ fqnRemapping?: Record<string, string>;
10
14
  }
11
15
  export interface ComparisonContext extends ComparisonOptions {
12
16
  /**
@@ -11,7 +11,7 @@ import { IReport } from './types';
11
11
  *
12
12
  * Where CLASS ≤: BASE.
13
13
  */
14
- export declare function validateBaseTypeAssignability<T extends reflect.ReferenceType>(original: T, updated: T, mismatches: IReport): void;
14
+ export declare function validateBaseTypeAssignability<T extends reflect.ReferenceType>(original: T, updated: T, fqnRemapping: Record<string, string>, mismatches: IReport): void;
15
15
  /**
16
16
  * The updated type has not been newly made abstract
17
17
  *
@@ -58,7 +58,7 @@ export declare function validateNoNewAbstractMembers<T extends reflect.Reference
58
58
  *
59
59
  * Where RETURN_TYPE(method) ≤: T.
60
60
  */
61
- export declare function validateReturnTypeNotWeakened(original: reflect.Method, updated: reflect.Method, mismatches: IReport): void;
61
+ export declare function validateReturnTypeNotWeakened(original: reflect.Method, updated: reflect.Method, fqnRemapping: Record<string, string>, mismatches: IReport): void;
62
62
  /**
63
63
  * Validate that a method return type is the exact same
64
64
  *
@@ -76,7 +76,7 @@ export declare function validateReturnTypeSame(original: reflect.Method, updated
76
76
  *
77
77
  * Where RETURN_TYPE(prop) ≤: T.
78
78
  */
79
- export declare function validatePropertyTypeNotWeakened(original: reflect.Property, updated: reflect.Property, mismatches: IReport): void;
79
+ export declare function validatePropertyTypeNotWeakened(original: reflect.Property, updated: reflect.Property, fqnRemapping: Record<string, string>, mismatches: IReport): void;
80
80
  /**
81
81
  * Validate that a property type is the exact same
82
82
  *
@@ -96,7 +96,7 @@ export declare function validatePropertyTypeSame(original: reflect.Property, upd
96
96
  *
97
97
  * Where T ≤: U.
98
98
  */
99
- export declare function validateParameterTypeWeakened(method: reflect.Method | reflect.Initializer, original: reflect.Parameter, updated: reflect.Parameter, mismatches: IReport): void;
99
+ export declare function validateParameterTypeWeakened(method: reflect.Method | reflect.Initializer, original: reflect.Parameter, updated: reflect.Parameter, fqnRemapping: Record<string, string>, mismatches: IReport): void;
100
100
  /**
101
101
  * Validate that a method parameter type is the exact same
102
102
  *
@@ -127,7 +127,7 @@ export declare function validateExistingParams<T extends reflect.Initializer | r
127
127
  * (Not too few arguments)
128
128
  */
129
129
  export declare function validateNoNewRequiredParams<T extends reflect.Initializer | reflect.Method>(original: T, updated: T, mismatches: IReport): void;
130
- export declare function validateMethodCompatible<T extends reflect.Method | reflect.Initializer>(original: T, updated: T, mismatches: IReport): void;
130
+ export declare function validateMethodCompatible<T extends reflect.Method | reflect.Initializer>(original: T, updated: T, fqnRemapping: Record<string, string>, mismatches: IReport): void;
131
131
  /**
132
132
  * Check if a class/interface has been marked as @subclassable
133
133
  */
@@ -36,8 +36,8 @@ const LOG = log4js.getLogger('jsii-diff');
36
36
  *
37
37
  * Where CLASS ≤: BASE.
38
38
  */
39
- function validateBaseTypeAssignability(original, updated, mismatches) {
40
- const ana = assignableToAllBaseTypes(original, updated);
39
+ function validateBaseTypeAssignability(original, updated, fqnRemapping, mismatches) {
40
+ const ana = assignableToAllBaseTypes(original, updated, fqnRemapping);
41
41
  if (!ana.success) {
42
42
  mismatches.report({
43
43
  ruleKey: 'base-types',
@@ -146,8 +146,8 @@ function validateNoNewAbstractMembers(original, updated, mismatches) {
146
146
  *
147
147
  * Where RETURN_TYPE(method) ≤: T.
148
148
  */
149
- function validateReturnTypeNotWeakened(original, updated, mismatches) {
150
- const retAna = isCompatibleReturnType(original.returns, updated.returns);
149
+ function validateReturnTypeNotWeakened(original, updated, fqnRemapping, mismatches) {
150
+ const retAna = isCompatibleReturnType(original.returns, updated.returns, fqnRemapping);
151
151
  if (!retAna.success) {
152
152
  mismatches.report({
153
153
  ruleKey: 'change-return-type',
@@ -183,8 +183,8 @@ function validateReturnTypeSame(original, updated, mismatches) {
183
183
  *
184
184
  * Where RETURN_TYPE(prop) ≤: T.
185
185
  */
186
- function validatePropertyTypeNotWeakened(original, updated, mismatches) {
187
- const ana = isCompatibleReturnType(original, updated);
186
+ function validatePropertyTypeNotWeakened(original, updated, fqnRemapping, mismatches) {
187
+ const ana = isCompatibleReturnType(original, updated, fqnRemapping);
188
188
  if (!ana.success) {
189
189
  mismatches.report({
190
190
  ruleKey: 'changed-type',
@@ -222,8 +222,8 @@ function validatePropertyTypeSame(original, updated, mismatches) {
222
222
  *
223
223
  * Where T ≤: U.
224
224
  */
225
- function validateParameterTypeWeakened(method, original, updated, mismatches) {
226
- const argAna = isCompatibleArgumentType(original.type, updated.type);
225
+ function validateParameterTypeWeakened(method, original, updated, fqnRemapping, mismatches) {
226
+ const argAna = isCompatibleArgumentType(original.type, updated.type, fqnRemapping);
227
227
  if (!argAna.success) {
228
228
  mismatches.report({
229
229
  ruleKey: 'incompatible-argument',
@@ -306,18 +306,18 @@ function validateNoNewRequiredParams(original, updated, mismatches) {
306
306
  }
307
307
  });
308
308
  }
309
- function validateMethodCompatible(original, updated, mismatches) {
309
+ function validateMethodCompatible(original, updated, fqnRemapping, mismatches) {
310
310
  (0, stability_1.validateStabilities)(original, updated, mismatches);
311
311
  // Type guards on original are duplicated on updated to help tsc... They are required to be the same type by the declaration.
312
312
  if (reflect.isMethod(original) && reflect.isMethod(updated)) {
313
313
  validateStaticSame(original, updated, mismatches);
314
314
  validateAsyncSame(original, updated, mismatches);
315
- validateReturnTypeNotWeakened(original, updated, mismatches);
315
+ validateReturnTypeNotWeakened(original, updated, fqnRemapping, mismatches);
316
316
  }
317
317
  validateNotMadeNonVariadic(original, updated, mismatches);
318
318
  // Check that every original parameter can still be mapped to a parameter in the updated method
319
319
  validateExistingParams(original, updated, mismatches, (oldParam, newParam) => {
320
- validateParameterTypeWeakened(original, oldParam, newParam, mismatches);
320
+ validateParameterTypeWeakened(original, oldParam, newParam, fqnRemapping, mismatches);
321
321
  });
322
322
  validateNoNewRequiredParams(original, updated, mismatches);
323
323
  }
@@ -394,7 +394,7 @@ function* memberPairs(origClass, xs, updatedClass, mismatches) {
394
394
  *
395
395
  * Strengthening output values is allowed!
396
396
  */
397
- function isCompatibleReturnType(original, updated) {
397
+ function isCompatibleReturnType(original, updated, fqnRemapping) {
398
398
  if (original.type.void) {
399
399
  return { success: true };
400
400
  } // If we didn't use to return anything, returning something now is fine
@@ -404,16 +404,16 @@ function isCompatibleReturnType(original, updated) {
404
404
  if (!original.optional && updated.optional) {
405
405
  return { success: false, reasons: ['output type is now optional'] };
406
406
  }
407
- return (0, type_analysis_1.isSuperType)(original.type, updated.type, updated.system);
407
+ return new type_analysis_1.TypeAnalysis(updated.system, fqnRemapping).isSuperType(original.type, updated.type);
408
408
  }
409
409
  /**
410
410
  * Whether we are weakening the pre (input type of a method)
411
411
  *
412
412
  * Weakening preconditions is allowed!
413
413
  */
414
- function isCompatibleArgumentType(original, updated) {
414
+ function isCompatibleArgumentType(original, updated, fqnRemapping) {
415
415
  // Input can never be void, so no need to check
416
- return (0, type_analysis_1.isSuperType)(updated, original, updated.system);
416
+ return new type_analysis_1.TypeAnalysis(updated.system, fqnRemapping).isSuperType(updated, original);
417
417
  }
418
418
  /**
419
419
  * Verify assignability to supertypes
@@ -428,9 +428,9 @@ function isCompatibleArgumentType(original, updated) {
428
428
  * B an updated type B' needs to exist in the new assembly which is
429
429
  * still a supertype of T'.
430
430
  */
431
- function assignableToAllBaseTypes(original, updated) {
431
+ function assignableToAllBaseTypes(original, updated, fqnRemapping) {
432
432
  for (const B of baseTypes(original)) {
433
- const result = (0, type_analysis_1.isNominalSuperType)(B.reference, updated.reference, updated.system);
433
+ const result = new type_analysis_1.TypeAnalysis(updated.system, fqnRemapping).isNominalSuperType(B.reference, updated.reference);
434
434
  if (!result.success) {
435
435
  return result;
436
436
  }
package/lib/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** The qualified version number for this JSII compiler. */
2
- export declare const VERSION = "1.117.0 (build b8499c7)";
2
+ export declare const VERSION = "1.119.0 (build 1634eac)";
3
3
  //# sourceMappingURL=version.d.ts.map
package/lib/version.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
- // Generated at 2025-10-22T16:34:07Z by generate.sh
2
+ // Generated at 2025-11-10T14:26:38Z by generate.sh
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.VERSION = void 0;
5
5
  /** The qualified version number for this JSII compiler. */
6
- exports.VERSION = '1.117.0 (build b8499c7)';
6
+ exports.VERSION = '1.119.0 (build 1634eac)';
7
7
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jsii-diff",
3
- "version": "1.117.0",
3
+ "version": "1.119.0",
4
4
  "description": "Assembly comparison for jsii",
5
5
  "license": "Apache-2.0",
6
6
  "author": {
@@ -33,10 +33,10 @@
33
33
  "package": "package-js"
34
34
  },
35
35
  "dependencies": {
36
- "@jsii/check-node": "1.117.0",
37
- "@jsii/spec": "1.117.0",
36
+ "@jsii/check-node": "1.119.0",
37
+ "@jsii/spec": "1.119.0",
38
38
  "fs-extra": "^10.1.0",
39
- "jsii-reflect": "^1.117.0",
39
+ "jsii-reflect": "^1.119.0",
40
40
  "log4js": "^6.9.1",
41
41
  "yargs": "^17.7.2"
42
42
  },
@@ -46,6 +46,6 @@
46
46
  "@types/yargs": "^17.0.33",
47
47
  "jest-expect-message": "^1.1.3",
48
48
  "jsii": "^5.9.10",
49
- "jsii-build-tools": "^1.117.0"
49
+ "jsii-build-tools": "^1.119.0"
50
50
  }
51
51
  }
@@ -547,4 +547,14 @@ test('will find mismatches in submodules', () => (0, util_1.expectError)(/number
547
547
  'index.ts': 'export * as submodule from "./subdir"',
548
548
  'subdir/index.ts': 'export class Foo { public static readonly PROP = 42; }',
549
549
  }));
550
+ // ----------------------------------------------------------------------
551
+ test('allow remapping of FQNs', () => {
552
+ const original = `export class Foo1 { }`;
553
+ const updated = `export class Foo2 { }`;
554
+ // This should give no error because we remapped Foo1 to Foo2
555
+ const mms = (0, util_1.compare)(original, updated, {
556
+ fqnRemapping: { 'testpkg.Foo1': 'testpkg.Foo2' },
557
+ });
558
+ expect(Array.from(mms.messages())).toEqual([]);
559
+ });
550
560
  //# sourceMappingURL=classes.test.js.map
package/test/util.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MultipleSourceFiles } from 'jsii';
2
- import { Mismatches } from '../lib/types';
2
+ import { ComparisonOptions, Mismatches } from '../lib/types';
3
3
  export declare function expectNoError(original: string | MultipleSourceFiles, updated: string | MultipleSourceFiles): void;
4
4
  export declare function expectError(error: RegExp | undefined, original: string | MultipleSourceFiles, updated: string | MultipleSourceFiles): void;
5
- export declare function compare(original: string | MultipleSourceFiles, updated: string | MultipleSourceFiles): Mismatches;
5
+ export declare function compare(original: string | MultipleSourceFiles, updated: string | MultipleSourceFiles, options?: ComparisonOptions): Mismatches;
6
6
  //# sourceMappingURL=util.d.ts.map
package/test/util.js CHANGED
@@ -25,13 +25,13 @@ function expectError(error, original, updated) {
25
25
  expect(msgs.join(',')).toMatch(error);
26
26
  }
27
27
  }
28
- function compare(original, updated) {
28
+ function compare(original, updated, options = {}) {
29
29
  const ass1 = (0, jsii_1.sourceToAssemblyHelper)(original);
30
30
  const ts1 = new reflect.TypeSystem();
31
31
  const originalAssembly = ts1.addAssembly(new reflect.Assembly(ts1, ass1));
32
32
  const ass2 = (0, jsii_1.sourceToAssemblyHelper)(updated);
33
33
  const ts2 = new reflect.TypeSystem();
34
34
  const updatedAssembly = ts2.addAssembly(new reflect.Assembly(ts2, ass2));
35
- return (0, lib_1.compareAssemblies)(originalAssembly, updatedAssembly);
35
+ return (0, lib_1.compareAssemblies)(originalAssembly, updatedAssembly, options);
36
36
  }
37
37
  //# sourceMappingURL=util.js.map