versioned-d.ts-tools 0.7.2 → 0.7.4
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/dts-utilities.d.ts +19 -1
- package/dist/dts-utilities.js +166 -16
- package/dist/version-remover.js +3 -3
- package/dist/whats-new.d.ts +1 -0
- package/dist/whats-new.js +11 -5
- package/package.json +1 -1
package/dist/dts-utilities.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export interface WhatsNewConfig {
|
|
|
10
10
|
excludedFieldPatterns?: string[];
|
|
11
11
|
includeStaticFields?: boolean;
|
|
12
12
|
includeEnums?: boolean;
|
|
13
|
+
filterUnionAdditions?: boolean;
|
|
13
14
|
linkConfigs?: LinkConfig[];
|
|
14
15
|
replacements?: any[];
|
|
15
16
|
}
|
|
@@ -21,6 +22,7 @@ export interface MarkdownOptions {
|
|
|
21
22
|
excludedFieldPatterns?: string[];
|
|
22
23
|
includeStaticFields?: boolean;
|
|
23
24
|
includeEnums?: boolean;
|
|
25
|
+
filterUnionAdditions?: boolean;
|
|
24
26
|
}
|
|
25
27
|
export declare const DEFAULT_LINK_CONFIGS: LinkConfig[];
|
|
26
28
|
declare enum ClassType {
|
|
@@ -57,8 +59,24 @@ export declare class APISet {
|
|
|
57
59
|
constructor();
|
|
58
60
|
addClass(clas: ClassStruct): void;
|
|
59
61
|
containsClass(clas: ClassStruct): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Checks if two field declaration strings are equivalent except for additional union types.
|
|
64
|
+
* This helps filter out noise from new union options being added to existing parameters.
|
|
65
|
+
*/
|
|
66
|
+
private isOnlyUnionAddition;
|
|
60
67
|
containsField(clas: ClassStruct, field: FieldStruct): boolean;
|
|
61
|
-
|
|
68
|
+
containsFieldOrUnionAddition(clas: ClassStruct, field: FieldStruct): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Checks if a class name appears only in union type contexts and not as standalone types.
|
|
71
|
+
* Returns true if the class only appears in union expressions like "Range | RangeAreas"
|
|
72
|
+
* and doesn't appear as standalone return types or parameters.
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* Checks if a class with filtered fields should be excluded due to union-only changes.
|
|
76
|
+
* This is called during markdown generation after field exclusions have been applied.
|
|
77
|
+
*/
|
|
78
|
+
private shouldExcludeClassForUnionFiltering;
|
|
79
|
+
diff(other: APISet, filterUnionAdditions?: boolean): APISet;
|
|
62
80
|
getAsDTS(): string;
|
|
63
81
|
/**
|
|
64
82
|
* Generates markdown documentation for API differences.
|
package/dist/dts-utilities.js
CHANGED
|
@@ -165,27 +165,167 @@ class APISet {
|
|
|
165
165
|
containsClass(clas) {
|
|
166
166
|
return this.api.some(element => element.declarationString === clas.declarationString);
|
|
167
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Checks if two field declaration strings are equivalent except for additional union types.
|
|
170
|
+
* This helps filter out noise from new union options being added to existing parameters.
|
|
171
|
+
*/
|
|
172
|
+
isOnlyUnionAddition(newDeclaration, oldDeclaration) {
|
|
173
|
+
// If they're identical, no difference at all
|
|
174
|
+
if (newDeclaration === oldDeclaration) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
// Quick check: if the method/field names are different, this is not a union addition
|
|
178
|
+
// Extract method/field name from the beginning of each declaration
|
|
179
|
+
const getMethodName = (decl) => {
|
|
180
|
+
const match = decl.match(/^\s*(\w+)\s*[\(:]/) || decl.match(/^\s*(\w+)\s*\??\s*:/);
|
|
181
|
+
return match ? match[1] : '';
|
|
182
|
+
};
|
|
183
|
+
const oldMethodName = getMethodName(oldDeclaration);
|
|
184
|
+
const newMethodName = getMethodName(newDeclaration);
|
|
185
|
+
// If method names are different, this is a new method, not a union addition
|
|
186
|
+
if (oldMethodName !== newMethodName || !oldMethodName) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
// More sophisticated approach: extract and compare union types from specific parameters
|
|
190
|
+
// This handles cases where union additions are in the middle of parameter lists
|
|
191
|
+
// Normalize whitespace first
|
|
192
|
+
const oldNormalized = oldDeclaration.replace(/\s+/g, ' ').trim();
|
|
193
|
+
const newNormalized = newDeclaration.replace(/\s+/g, ' ').trim();
|
|
194
|
+
// Find all union type patterns in both declarations
|
|
195
|
+
// Pattern matches: paramName: Type1 | Type2 | Type3 or paramName?: Type1 | Type2 | Type3
|
|
196
|
+
const unionPattern = /(\w+\??\s*:\s*)([^;,)]+)/g;
|
|
197
|
+
const oldUnions = new Map();
|
|
198
|
+
const newUnions = new Map();
|
|
199
|
+
let match;
|
|
200
|
+
// Extract union types from old declaration
|
|
201
|
+
unionPattern.lastIndex = 0;
|
|
202
|
+
while ((match = unionPattern.exec(oldNormalized)) !== null) {
|
|
203
|
+
const paramName = match[1].trim();
|
|
204
|
+
const unionString = match[2].trim();
|
|
205
|
+
const unionTypes = unionString.split('|').map(t => t.trim().replace(/^["']|["']$/g, ''));
|
|
206
|
+
oldUnions.set(paramName, unionTypes);
|
|
207
|
+
}
|
|
208
|
+
// Extract union types from new declaration
|
|
209
|
+
unionPattern.lastIndex = 0;
|
|
210
|
+
while ((match = unionPattern.exec(newNormalized)) !== null) {
|
|
211
|
+
const paramName = match[1].trim();
|
|
212
|
+
const unionString = match[2].trim();
|
|
213
|
+
const unionTypes = unionString.split('|').map(t => t.trim().replace(/^["']|["']$/g, ''));
|
|
214
|
+
newUnions.set(paramName, unionTypes);
|
|
215
|
+
}
|
|
216
|
+
// Check if we found any union parameters
|
|
217
|
+
if (oldUnions.size === 0 || newUnions.size === 0) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
// Check if the parameters are the same except for union additions
|
|
221
|
+
let hasUnionAddition = false;
|
|
222
|
+
for (const [paramName, oldTypes] of oldUnions) {
|
|
223
|
+
const newTypes = newUnions.get(paramName);
|
|
224
|
+
if (!newTypes) {
|
|
225
|
+
// Parameter removed, not a union addition
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
// Check if all old types are present in new types
|
|
229
|
+
const allOldTypesPresent = oldTypes.every(oldType => newTypes.some(newType => newType === oldType));
|
|
230
|
+
if (!allOldTypesPresent) {
|
|
231
|
+
// Types were removed or changed, not just added
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
// Check if new types were added
|
|
235
|
+
if (newTypes.length > oldTypes.length) {
|
|
236
|
+
hasUnionAddition = true;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Check for any completely new parameters (not allowed for union addition)
|
|
240
|
+
for (const paramName of newUnions.keys()) {
|
|
241
|
+
if (!oldUnions.has(paramName)) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return hasUnionAddition;
|
|
246
|
+
}
|
|
168
247
|
containsField(clas, field) {
|
|
169
248
|
const targetClass = this.api.find(element => element.declarationString === clas.declarationString);
|
|
170
249
|
return targetClass ? targetClass.fields.some(thisField => thisField.declarationString === field.declarationString) : false;
|
|
171
250
|
}
|
|
251
|
+
containsFieldOrUnionAddition(clas, field) {
|
|
252
|
+
const targetClass = this.api.find(element => element.declarationString === clas.declarationString);
|
|
253
|
+
if (!targetClass) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
return targetClass.fields.some(thisField => {
|
|
257
|
+
// Exact match
|
|
258
|
+
if (thisField.declarationString === field.declarationString) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
// Check if it's only a union addition
|
|
262
|
+
return this.isOnlyUnionAddition(field.declarationString, thisField.declarationString);
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Checks if a class name appears only in union type contexts and not as standalone types.
|
|
267
|
+
* Returns true if the class only appears in union expressions like "Range | RangeAreas"
|
|
268
|
+
* and doesn't appear as standalone return types or parameters.
|
|
269
|
+
*/
|
|
270
|
+
/**
|
|
271
|
+
* Checks if a class with filtered fields should be excluded due to union-only changes.
|
|
272
|
+
* This is called during markdown generation after field exclusions have been applied.
|
|
273
|
+
*/
|
|
274
|
+
shouldExcludeClassForUnionFiltering(clas, originalFields, excludedFieldPatterns = [], excludedFieldNames = []) {
|
|
275
|
+
// If no fields in the class, don't exclude for union reasons
|
|
276
|
+
if (originalFields.length === 0) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
// First filter out excluded fields to see what would actually be displayed
|
|
280
|
+
const visibleFields = originalFields.filter(field => {
|
|
281
|
+
const isExcludedByPattern = excludedFieldPatterns.some(pattern => {
|
|
282
|
+
try {
|
|
283
|
+
return new RegExp(pattern, 'g').test(field.declarationString);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
const isExcludedByName = excludedFieldNames.includes(field.name);
|
|
290
|
+
return !isExcludedByPattern && !isExcludedByName;
|
|
291
|
+
});
|
|
292
|
+
// If no fields would be visible after exclusions, and all original fields contain unions,
|
|
293
|
+
// then this class likely appears only due to union additions in other classes
|
|
294
|
+
if (visibleFields.length === 0 && originalFields.every(field => field.declarationString.includes('|'))) {
|
|
295
|
+
return true;
|
|
296
|
+
}
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
172
299
|
// finds the new fields and classes
|
|
173
|
-
diff(other) {
|
|
300
|
+
diff(other, filterUnionAdditions = false) {
|
|
174
301
|
const diffAPI = new APISet();
|
|
175
302
|
this.api.forEach((element) => {
|
|
176
303
|
if (other.containsClass(element)) {
|
|
177
304
|
let classShell = null;
|
|
178
305
|
element.fields.forEach((field) => {
|
|
179
|
-
|
|
306
|
+
let fieldExists;
|
|
307
|
+
if (filterUnionAdditions) {
|
|
308
|
+
// Use union-aware field comparison when filtering is enabled
|
|
309
|
+
fieldExists = other.containsFieldOrUnionAddition(element, field);
|
|
310
|
+
}
|
|
311
|
+
else {
|
|
312
|
+
// Use exact match comparison
|
|
313
|
+
fieldExists = other.containsField(element, field);
|
|
314
|
+
}
|
|
315
|
+
if (!fieldExists) {
|
|
180
316
|
if (classShell === null) {
|
|
181
317
|
classShell = element.copyWithoutFields();
|
|
182
|
-
diffAPI.addClass(classShell);
|
|
183
318
|
}
|
|
184
319
|
classShell.fields.push(field);
|
|
185
320
|
}
|
|
186
321
|
});
|
|
322
|
+
// Only add the class to diffAPI if it has fields after filtering
|
|
323
|
+
if (classShell !== null && classShell.fields.length > 0) {
|
|
324
|
+
diffAPI.addClass(classShell);
|
|
325
|
+
}
|
|
187
326
|
}
|
|
188
327
|
else {
|
|
328
|
+
// Add new classes to the diff
|
|
189
329
|
diffAPI.addClass(element);
|
|
190
330
|
}
|
|
191
331
|
});
|
|
@@ -242,19 +382,15 @@ class APISet {
|
|
|
242
382
|
const isEnum = clas.type === ClassType.Enum;
|
|
243
383
|
if ((finalOptions.includeEnums || !isEnum) && !isExcludedByPattern) {
|
|
244
384
|
const className = clas.getClassName();
|
|
245
|
-
//
|
|
246
|
-
if (
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
+ buildClassLink(finalOptions.relativePath, className, finalOptions.linkConfigs) + ")|";
|
|
385
|
+
// Apply union filtering if enabled - check if this class should be filtered out BEFORE field filtering
|
|
386
|
+
if (finalOptions.filterUnionAdditions) {
|
|
387
|
+
if (this.shouldExcludeClassForUnionFiltering(clas, clas.fields, finalOptions.excludedFieldPatterns || [], finalOptions.excludedFieldNames || [])) {
|
|
388
|
+
// Skip this class as it only contains union-related changes
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
252
391
|
}
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
// - Excluded field names (configurable, no defaults - all field names included unless explicitly excluded)
|
|
256
|
-
// - Static fields (configurable via includeStaticFields, default: true - static fields included by default)
|
|
257
|
-
let filteredFields = clas.fields.filter((field) => {
|
|
392
|
+
// Apply field filtering after union filtering check
|
|
393
|
+
const filteredFields = clas.fields.filter((field) => {
|
|
258
394
|
// Check if field matches any excluded pattern
|
|
259
395
|
// Note: Test against field declaration string, just like the original code
|
|
260
396
|
const isExcludedByPattern = (finalOptions.excludedFieldPatterns || []).some(pattern => {
|
|
@@ -272,6 +408,19 @@ class APISet {
|
|
|
272
408
|
!(finalOptions.excludedFieldNames || []).includes(field.name) &&
|
|
273
409
|
(finalOptions.includeStaticFields || !isStaticField));
|
|
274
410
|
});
|
|
411
|
+
// Special handling for <global> - no link
|
|
412
|
+
if (className === "<global>") {
|
|
413
|
+
output += "|*global*|";
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
output += "|[" + className + "]("
|
|
417
|
+
+ buildClassLink(finalOptions.relativePath, className, finalOptions.linkConfigs) + ")|";
|
|
418
|
+
}
|
|
419
|
+
// Ignore the following:
|
|
420
|
+
// - Fields matching excluded patterns (configurable, no defaults - all fields included unless explicitly excluded)
|
|
421
|
+
// - Excluded field names (configurable, no defaults - all field names included unless explicitly excluded)
|
|
422
|
+
// - Static fields (configurable via includeStaticFields, default: true - static fields included by default)
|
|
423
|
+
// (filteredFields already computed above)
|
|
275
424
|
let first = true;
|
|
276
425
|
if (filteredFields.length > 0) {
|
|
277
426
|
filteredFields.forEach((field) => {
|
|
@@ -311,7 +460,8 @@ class APISet {
|
|
|
311
460
|
});
|
|
312
461
|
}
|
|
313
462
|
else {
|
|
314
|
-
|
|
463
|
+
// When all fields are excluded, still show the class description
|
|
464
|
+
output += "|" + removeAtLink(extractFirstSentenceFromComment(clas.comment)) + "|\n";
|
|
315
465
|
}
|
|
316
466
|
}
|
|
317
467
|
});
|
package/dist/version-remover.js
CHANGED
|
@@ -114,9 +114,9 @@ if (require.main === module) {
|
|
|
114
114
|
const args = process.argv.slice(2);
|
|
115
115
|
const hasHelp = args.find((x) => x === "-?" || x === "--help");
|
|
116
116
|
if ((args.length !== 3 && args.length !== 4) || hasHelp) {
|
|
117
|
-
console.log("usage:
|
|
118
|
-
console.log("example:
|
|
119
|
-
console.log("example:
|
|
117
|
+
console.log("usage: version-remover [source d.ts] [output file name] [version string] [optional config file]");
|
|
118
|
+
console.log("example: version-remover excel.d.ts excel_1_7.d.ts \"Api set: ExcelApi 1.8\"");
|
|
119
|
+
console.log("example: version-remover excel.d.ts excel_1_18.d.ts \"Api set: ExcelApi 1.19\" my-config.json");
|
|
120
120
|
console.log("");
|
|
121
121
|
console.log("Note: For specific API sets that require custom replacements, you may need to create");
|
|
122
122
|
console.log("configuration files to handle type union cleanups and parameter removals.");
|
package/dist/whats-new.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface WhatsNewOptions {
|
|
|
12
12
|
excludedFieldPatterns?: string[];
|
|
13
13
|
includeStaticFields?: boolean;
|
|
14
14
|
includeEnums?: boolean;
|
|
15
|
+
filterUnionAdditions?: boolean;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* Generates "what's new" documentation by comparing two TypeScript definition files.
|
package/dist/whats-new.js
CHANGED
|
@@ -40,7 +40,7 @@ const dts_utilities_1 = require("./dts-utilities");
|
|
|
40
40
|
/**
|
|
41
41
|
* Loads configuration from a JSON file
|
|
42
42
|
* @param configFilePath Path to the configuration file
|
|
43
|
-
* @returns Configuration object with linkConfigs, excludedFieldNames, excludedClassPatterns, excludedFieldPatterns, includeStaticFields, and
|
|
43
|
+
* @returns Configuration object with linkConfigs, excludedFieldNames, excludedClassPatterns, excludedFieldPatterns, includeStaticFields, includeEnums, and filterUnionAdditions
|
|
44
44
|
*/
|
|
45
45
|
function loadWhatsNewConfig(configFilePath) {
|
|
46
46
|
try {
|
|
@@ -67,7 +67,8 @@ function loadWhatsNewConfig(configFilePath) {
|
|
|
67
67
|
excludedClassPatterns: config.excludedClassPatterns,
|
|
68
68
|
excludedFieldPatterns: config.excludedFieldPatterns,
|
|
69
69
|
includeStaticFields: config.includeStaticFields,
|
|
70
|
-
includeEnums: config.includeEnums
|
|
70
|
+
includeEnums: config.includeEnums,
|
|
71
|
+
filterUnionAdditions: config.filterUnionAdditions
|
|
71
72
|
};
|
|
72
73
|
}
|
|
73
74
|
catch (error) {
|
|
@@ -87,7 +88,8 @@ function generateWhatsNew(options) {
|
|
|
87
88
|
let effectiveExcludedFieldPatterns = options.excludedFieldPatterns;
|
|
88
89
|
let effectiveIncludeStaticFields = options.includeStaticFields;
|
|
89
90
|
let effectiveIncludeEnums = options.includeEnums;
|
|
90
|
-
|
|
91
|
+
let effectiveFilterUnionAdditions = options.filterUnionAdditions;
|
|
92
|
+
if (options.configFilePath && (!options.linkConfigs || !options.excludedFieldNames || !options.excludedClassPatterns || !options.excludedFieldPatterns || options.includeStaticFields === undefined || options.includeEnums === undefined || options.filterUnionAdditions === undefined)) {
|
|
91
93
|
const config = loadWhatsNewConfig(options.configFilePath);
|
|
92
94
|
if (!options.linkConfigs && config.linkConfigs) {
|
|
93
95
|
effectiveLinkConfigs = config.linkConfigs;
|
|
@@ -108,13 +110,16 @@ function generateWhatsNew(options) {
|
|
|
108
110
|
// Default to true when loading from config (inclusive by default)
|
|
109
111
|
effectiveIncludeEnums = config.includeEnums !== undefined ? config.includeEnums : true;
|
|
110
112
|
}
|
|
113
|
+
if (options.filterUnionAdditions === undefined && config.filterUnionAdditions !== undefined) {
|
|
114
|
+
effectiveFilterUnionAdditions = config.filterUnionAdditions;
|
|
115
|
+
}
|
|
111
116
|
}
|
|
112
117
|
// read whole files
|
|
113
118
|
let wholeRelease = fsx.readFileSync(options.oldDtsPath).toString();
|
|
114
119
|
let wholePreview = fsx.readFileSync(options.newDtsPath).toString();
|
|
115
120
|
const releaseAPI = (0, dts_utilities_1.parseDTS)("release", wholeRelease);
|
|
116
121
|
const previewAPI = (0, dts_utilities_1.parseDTS)("preview", wholePreview);
|
|
117
|
-
const diffAPI = previewAPI.diff(releaseAPI);
|
|
122
|
+
const diffAPI = previewAPI.diff(releaseAPI, effectiveFilterUnionAdditions);
|
|
118
123
|
if (!fsx.existsSync(options.outputPath + ".md")) {
|
|
119
124
|
fsx.createFileSync(options.outputPath + ".md");
|
|
120
125
|
}
|
|
@@ -125,7 +130,8 @@ function generateWhatsNew(options) {
|
|
|
125
130
|
excludedClassPatterns: effectiveExcludedClassPatterns,
|
|
126
131
|
excludedFieldPatterns: effectiveExcludedFieldPatterns,
|
|
127
132
|
includeStaticFields: effectiveIncludeStaticFields,
|
|
128
|
-
includeEnums: effectiveIncludeEnums
|
|
133
|
+
includeEnums: effectiveIncludeEnums,
|
|
134
|
+
filterUnionAdditions: effectiveFilterUnionAdditions
|
|
129
135
|
}));
|
|
130
136
|
}
|
|
131
137
|
// CLI entry point
|