versioned-d.ts-tools 0.6.0 → 0.7.1

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/README.md CHANGED
@@ -105,44 +105,71 @@ whats-new office-scripts.d.ts office-scripts-old.d.ts office-scripts-whats-new j
105
105
 
106
106
  This generates a markdown file (e.g., `excel_whats_new.md`) containing a table showing what's new between the two versions.
107
107
 
108
- #### Link Configuration File
108
+ #### Configuration File
109
109
 
110
- You can provide an optional JSON configuration file to customize how URLs are generated for different API types using flexible templates with placeholders.
110
+ You can provide an optional JSON configuration file to customize the output by excluding specific fields, classes, and controlling what types of declarations are included.
111
111
 
112
112
  **Configuration file format:**
113
113
 
114
114
  ```json
115
115
  {
116
+ "excludedFieldNames": [
117
+ "load", "set", "toJSON", "context", "track", "untrack"
118
+ ],
119
+ "excludedClassPatterns": [
120
+ "LoadOptions$", "Data$"
121
+ ],
122
+ "excludedFieldPatterns": [
123
+ "\\w+\\??:\\s*\".*\""
124
+ ],
125
+ "includeStaticFields": false,
126
+ "includeEnums": false,
116
127
  "linkConfigs": [
117
128
  {
118
- "name": "Office Scripts",
119
129
  "pathPattern": "office-scripts",
120
- "description": "Special URL pattern for Office Scripts",
121
130
  "globalFunctionTemplate": "/{basePath}#officescript-officescript-{fieldName}-function(1)",
122
131
  "classTemplate": "/{basePath}/officescript.{className}",
123
132
  "classMemberTemplate": "/{basePath}/officescript.{className}#officescript-officescript-{className}-{fieldName}{suffix}"
124
- },
125
- {
126
- "name": "Standard Office Applications",
127
- "pathPattern": ".*",
128
- "description": "Standard URL pattern for Excel, Word, PowerPoint, Outlook",
129
- "globalFunctionTemplate": "/{basePath}#{hostName}-{fileName}-{fieldName}-function(1)",
130
- "classTemplate": "/{basePath}.{className}",
131
- "classMemberTemplate": "/{basePath}.{className}#{hostName}-{fileName}-{className}-{fieldName}{suffix}"
132
133
  }
133
134
  ]
134
135
  }
135
136
  ```
136
137
 
138
+ **Configuration Options:**
139
+
140
+ - **`excludedFieldNames`** - Array of exact field names to exclude from output
141
+ - **`excludedClassPatterns`** - Array of regex patterns for class names to exclude
142
+ - **`excludedFieldPatterns`** - Array of regex patterns for field declarations to exclude
143
+ - **`includeStaticFields`** - Boolean to include/exclude static fields (default: true)
144
+ - **`includeEnums`** - Boolean to include/exclude enum declarations (default: true when loading from config, false for backward compatibility when called directly)
145
+ - **`linkConfigs`** - Array of custom URL generation templates (see Link Configuration section below)
146
+
147
+ **Enum Configurability:**
148
+
149
+ The `includeEnums` option provides fine-grained control over enum inclusion:
150
+
151
+ - **Default behavior**: When calling the API directly, enums are excluded by default (`includeEnums: false`) for backward compatibility
152
+ - **Config file behavior**: When loading from a config file, enums are included by default (`includeEnums: true`) unless explicitly set to false
153
+ - **Explicit control**: Set `"includeEnums": true` to include enums, or `"includeEnums": false` to exclude them
154
+
155
+ This dual-default approach ensures existing integrations continue working while enabling new functionality when explicitly configured.
156
+
157
+ #### Link Configuration
158
+
159
+ The `linkConfigs` section allows you to customize how URLs are generated for different API types using flexible templates with placeholders.
160
+ ```
161
+
137
162
  **Available Template Placeholders:**
163
+
138
164
  - `{basePath}` - relativePath without the trailing dot (e.g., 'javascript/api/excel/excel')
139
- - `{hostName}` - extracted host name (e.g., 'excel', 'office-scripts')
165
+ - `{hostName}` - extracted host name (e.g., 'excel', 'office-scripts')
140
166
  - `{fileName}` - extracted file name (e.g., 'excel', 'officescript')
141
167
  - `{className}` - class name in lowercase
142
168
  - `{fieldName}` - field/method name in lowercase
143
169
  - `{suffix}` - '-member(1)' for methods/functions, '-member' for properties
144
170
 
145
171
  **Template Types:**
172
+
146
173
  - `globalFunctionTemplate` - For namespace-level functions (global functions)
147
174
  - `classTemplate` - For class/interface URLs in the first column
148
175
  - `classMemberTemplate` - For class members (methods, properties, events)
@@ -4,6 +4,24 @@ export interface LinkConfig {
4
4
  classTemplate: string;
5
5
  classMemberTemplate: string;
6
6
  }
7
+ export interface WhatsNewConfig {
8
+ excludedFieldNames?: string[];
9
+ excludedClassPatterns?: string[];
10
+ excludedFieldPatterns?: string[];
11
+ includeStaticFields?: boolean;
12
+ includeEnums?: boolean;
13
+ linkConfigs?: LinkConfig[];
14
+ replacements?: any[];
15
+ }
16
+ export interface MarkdownOptions {
17
+ relativePath: string;
18
+ linkConfigs?: LinkConfig[];
19
+ excludedFieldNames?: string[];
20
+ excludedClassPatterns?: string[];
21
+ excludedFieldPatterns?: string[];
22
+ includeStaticFields?: boolean;
23
+ includeEnums?: boolean;
24
+ }
7
25
  export declare const DEFAULT_LINK_CONFIGS: LinkConfig[];
8
26
  declare enum ClassType {
9
27
  Class = "Class",
@@ -42,7 +60,15 @@ export declare class APISet {
42
60
  containsField(clas: ClassStruct, field: FieldStruct): boolean;
43
61
  diff(other: APISet): APISet;
44
62
  getAsDTS(): string;
45
- getAsMarkdown(relativePath: string, linkConfigs?: LinkConfig[]): string;
63
+ /**
64
+ * Generates markdown documentation for API differences.
65
+ * By default, all classes and fields are included in the output.
66
+ * Exclusions must be explicitly configured via the options.
67
+ *
68
+ * @param options - Configuration options for markdown generation
69
+ * @returns Markdown table string
70
+ */
71
+ getAsMarkdown(options: MarkdownOptions): string;
46
72
  sort(): void;
47
73
  }
48
74
  export declare function parseDTS(fileName: string, fileContents: string): APISet;
@@ -65,6 +65,21 @@ function buildLinkFromTemplate(template, relativePath, className, field) {
65
65
  }
66
66
  return result;
67
67
  }
68
+ // Helper functions for pattern matching optimization
69
+ function compilePatterns(patterns) {
70
+ if (!patterns || patterns.length === 0) {
71
+ return [];
72
+ }
73
+ return patterns.map(pattern => {
74
+ try {
75
+ return new RegExp(pattern);
76
+ }
77
+ catch (error) {
78
+ console.warn(`Invalid regex pattern "${pattern}": ${error.message}`);
79
+ return null;
80
+ }
81
+ }).filter(Boolean);
82
+ }
68
83
  // Default configurations for known Office applications
69
84
  exports.DEFAULT_LINK_CONFIGS = [
70
85
  {
@@ -80,10 +95,26 @@ exports.DEFAULT_LINK_CONFIGS = [
80
95
  classMemberTemplate: "/{basePath}.{className}#{hostName}-{fileName}-{className}-{fieldName}{suffix}"
81
96
  }
82
97
  ];
83
- // capturing these because of eccentricities with the compiler ordering
84
- let topClass = null;
85
- let lastItem = null;
86
- let globalFunctionsClass = null;
98
+ // Parsing context to encapsulate state during DTS parsing
99
+ class ParsingContext {
100
+ constructor() {
101
+ this.topClass = null;
102
+ this.lastItem = null;
103
+ this.globalFunctionsClass = null;
104
+ }
105
+ reset() {
106
+ this.topClass = null;
107
+ this.lastItem = null;
108
+ this.globalFunctionsClass = null;
109
+ }
110
+ ensureGlobalFunctionsClass(allClasses) {
111
+ if (this.globalFunctionsClass === null) {
112
+ this.globalFunctionsClass = new ClassStruct("<global>", "", ClassType.Interface);
113
+ allClasses.addClass(this.globalFunctionsClass);
114
+ }
115
+ return this.globalFunctionsClass;
116
+ }
117
+ }
87
118
  var ClassType;
88
119
  (function (ClassType) {
89
120
  ClassType["Class"] = "Class";
@@ -138,26 +169,11 @@ class APISet {
138
169
  this.api.push(clas);
139
170
  }
140
171
  containsClass(clas) {
141
- let found = false;
142
- this.api.forEach((element) => {
143
- if (element.declarationString === clas.declarationString) {
144
- found = true;
145
- }
146
- });
147
- return found;
172
+ return this.api.some(element => element.declarationString === clas.declarationString);
148
173
  }
149
174
  containsField(clas, field) {
150
- let found = false;
151
- this.api.forEach((element) => {
152
- if (element.declarationString === clas.declarationString) {
153
- element.fields.forEach((thisField) => {
154
- if (thisField.declarationString === field.declarationString) {
155
- found = true;
156
- }
157
- });
158
- }
159
- });
160
- return found;
175
+ const targetClass = this.api.find(element => element.declarationString === clas.declarationString);
176
+ return targetClass ? targetClass.fields.some(thisField => thisField.declarationString === field.declarationString) : false;
161
177
  }
162
178
  // finds the new fields and classes
163
179
  diff(other) {
@@ -200,18 +216,37 @@ class APISet {
200
216
  });
201
217
  return output.join("\n");
202
218
  }
203
- getAsMarkdown(relativePath, linkConfigs = exports.DEFAULT_LINK_CONFIGS) {
219
+ /**
220
+ * Generates markdown documentation for API differences.
221
+ * By default, all classes and fields are included in the output.
222
+ * Exclusions must be explicitly configured via the options.
223
+ *
224
+ * @param options - Configuration options for markdown generation
225
+ * @returns Markdown table string
226
+ */
227
+ getAsMarkdown(options) {
228
+ const finalOptions = {
229
+ linkConfigs: exports.DEFAULT_LINK_CONFIGS,
230
+ excludedFieldNames: [],
231
+ excludedClassPatterns: [],
232
+ excludedFieldPatterns: [],
233
+ includeStaticFields: true,
234
+ includeEnums: false,
235
+ ...options // Spread user options to override defaults
236
+ };
204
237
  this.sort();
238
+ // Pre-compile regex patterns for better performance (class patterns only)
239
+ const compiledClassPatterns = compilePatterns(finalOptions.excludedClassPatterns);
205
240
  // table header
206
241
  let output = "| Class | Fields | Description |\n|:---|:---|:---|\n";
207
242
  this.api.forEach((clas) => {
208
243
  // Ignore the following:
209
- // - Enums.
210
- // - LoadOptions interfaces
211
- // - *Data classes for set/load methods
212
- if (clas.type !== ClassType.Enum &&
213
- !clas.getClassName().endsWith("LoadOptions") &&
214
- !clas.getClassName().endsWith("Data")) {
244
+ // - Enums (configurable via includeEnums, default: true - enums included by default).
245
+ // - Classes matching excluded patterns (configurable, no defaults - all classes included unless explicitly excluded)
246
+ const className = clas.getClassName();
247
+ const isExcludedByPattern = compiledClassPatterns.some(regex => regex.test(className));
248
+ const isEnum = clas.type === ClassType.Enum;
249
+ if ((finalOptions.includeEnums || !isEnum) && !isExcludedByPattern) {
215
250
  const className = clas.getClassName();
216
251
  // Special handling for <global> - no link
217
252
  if (className === "<global>") {
@@ -219,23 +254,29 @@ class APISet {
219
254
  }
220
255
  else {
221
256
  output += "|[" + className + "]("
222
- + buildClassLink(relativePath, className, linkConfigs) + ")|";
257
+ + buildClassLink(finalOptions.relativePath, className, finalOptions.linkConfigs) + ")|";
223
258
  }
224
259
  // Ignore the following:
225
- // - String literal overloads.
226
- // - `load`, `set`, `track`, `untrack`, and `toJSON` methods
227
- // - The `context` property.
228
- // - Static fields.
260
+ // - Fields matching excluded patterns (configurable, no defaults - all fields included unless explicitly excluded)
261
+ // - Excluded field names (configurable, no defaults - all field names included unless explicitly excluded)
262
+ // - Static fields (configurable via includeStaticFields, default: true - static fields included by default)
229
263
  let filteredFields = clas.fields.filter((field) => {
230
- let isLiteral = field.declarationString.search(/([a-zA-Z]+)(\??:)([\n]?([ |]*\"[\w]*\"[|,\n]*)+?)([ ]*[\),])/g) >= 0;
231
- return (!isLiteral &&
232
- field.name !== "load" &&
233
- field.name !== "set" &&
234
- field.name !== "toJSON" &&
235
- field.name !== "context" &&
236
- field.name !== "track" &&
237
- field.name !== "untrack" &&
238
- !field.declarationString.includes("static "));
264
+ // Check if field matches any excluded pattern
265
+ // Note: Test against field declaration string, just like the original code
266
+ const isExcludedByPattern = (finalOptions.excludedFieldPatterns || []).some(pattern => {
267
+ try {
268
+ return new RegExp(pattern, 'g').test(field.declarationString);
269
+ }
270
+ catch (error) {
271
+ console.warn(`Invalid field regex pattern "${pattern}": ${error.message}`);
272
+ return false;
273
+ }
274
+ });
275
+ // Check if field is static and should be excluded
276
+ const isStaticField = field.declarationString.includes("static ");
277
+ return (!isExcludedByPattern &&
278
+ !(finalOptions.excludedFieldNames || []).includes(field.name) &&
279
+ (finalOptions.includeStaticFields || !isStaticField));
239
280
  });
240
281
  let first = true;
241
282
  if (filteredFields.length > 0) {
@@ -270,7 +311,7 @@ class APISet {
270
311
  newItemText = newItemText.replace(/[\s][\s]+/g, " ").replace(/\( /g, "(").replace(/ \)/g, ")").replace(/,\)/g, ")").replace(/([\w]\??: )\\\| /g, "$1"); // dprint formatting quirks
271
312
  newItemText = newItemText.replace(/\<any\>/g, "");
272
313
  let tableLine = "[" + newItemText + "]("
273
- + buildFieldLink(relativePath, className, field, linkConfigs) + ")|";
314
+ + buildFieldLink(finalOptions.relativePath, className, field, finalOptions.linkConfigs) + ")|";
274
315
  tableLine += removeAtLink(extractFirstSentenceFromComment(field.comment));
275
316
  output += tableLine + "|\n";
276
317
  });
@@ -317,18 +358,33 @@ function extractFirstSentenceFromComment(commentText) {
317
358
  function removeAtLink(commentText) {
318
359
  // Replace links with the format "{@link Foo}" with "Foo".
319
360
  commentText = commentText.replace(/{@link ([^|]*?)}/gm, "$1");
320
- // Replace links with the format "{@link Foo | URL}" with "[Foo](URL)".
321
- commentText = commentText.replace(/{@link ([^}]*?) \| (http.*?)}/gm, "[$1]($2)");
361
+ // Replace links with the format "{@link URL | text}" with just the text part.
362
+ commentText = commentText.replace(/{@link ([^}]*?) \| ([^}]*?)}/gm, "$2");
322
363
  return commentText;
323
364
  }
365
+ // Cache for compiled link config patterns to avoid recompilation
366
+ const linkConfigCache = new Map();
367
+ function getCompiledLinkConfigs(linkConfigs) {
368
+ if (!linkConfigCache.has(linkConfigs)) {
369
+ const compiled = linkConfigs.map(config => ({
370
+ config,
371
+ regex: new RegExp(config.pathPattern)
372
+ }));
373
+ linkConfigCache.set(linkConfigs, compiled);
374
+ }
375
+ return linkConfigCache.get(linkConfigs);
376
+ }
377
+ function findMatchingLinkConfig(relativePath, linkConfigs = exports.DEFAULT_LINK_CONFIGS) {
378
+ const compiledConfigs = getCompiledLinkConfigs(linkConfigs);
379
+ const matchingConfig = compiledConfigs.find(({ regex }) => regex.test(relativePath));
380
+ return matchingConfig ? matchingConfig.config : exports.DEFAULT_LINK_CONFIGS[exports.DEFAULT_LINK_CONFIGS.length - 1];
381
+ }
324
382
  function buildClassLink(relativePath, className, linkConfigs = exports.DEFAULT_LINK_CONFIGS) {
325
- // Find the first matching configuration
326
- const config = linkConfigs.find(config => new RegExp(config.pathPattern).test(relativePath)) || exports.DEFAULT_LINK_CONFIGS[exports.DEFAULT_LINK_CONFIGS.length - 1]; // fallback to last config
383
+ const config = findMatchingLinkConfig(relativePath, linkConfigs);
327
384
  return buildLinkFromTemplate(config.classTemplate, relativePath, className);
328
385
  }
329
386
  function buildFieldLink(relativePath, className, field, linkConfigs = exports.DEFAULT_LINK_CONFIGS) {
330
- // Find the first matching configuration
331
- const config = linkConfigs.find(config => new RegExp(config.pathPattern).test(relativePath)) || exports.DEFAULT_LINK_CONFIGS[exports.DEFAULT_LINK_CONFIGS.length - 1]; // fallback to last config
387
+ const config = findMatchingLinkConfig(relativePath, linkConfigs);
332
388
  // Use appropriate template based on whether it's a global function or class member
333
389
  if (className.trim() === "<global>") {
334
390
  return buildLinkFromTemplate(config.globalFunctionTemplate, relativePath, className, field);
@@ -338,43 +394,42 @@ function buildFieldLink(relativePath, className, field, linkConfigs = exports.DE
338
394
  }
339
395
  }
340
396
  function parseDTS(fileName, fileContents) {
341
- // Reset global state for new parse
342
- topClass = null;
343
- lastItem = null;
344
- globalFunctionsClass = null;
397
+ // Create parsing context to encapsulate state
398
+ const context = new ParsingContext();
399
+ context.reset();
345
400
  const node = ts.createSourceFile(fileName, fileContents, ts.ScriptTarget.ES2015, true);
346
401
  const allClasses = new APISet();
347
- parseDTSInternal(node, allClasses);
402
+ parseDTSInternal(node, allClasses, context);
348
403
  return allClasses;
349
404
  }
350
- function parseDTSInternal(node, allClasses) {
405
+ function parseDTSInternal(node, allClasses, context) {
351
406
  switch (node.kind) {
352
407
  case ts.SyntaxKind.InterfaceDeclaration:
353
- parseDTSTopLevelItem(node, allClasses, ClassType.Interface);
408
+ parseDTSTopLevelItem(node, allClasses, ClassType.Interface, context);
354
409
  break;
355
410
  case ts.SyntaxKind.ClassDeclaration:
356
- parseDTSTopLevelItem(node, allClasses, ClassType.Class);
411
+ parseDTSTopLevelItem(node, allClasses, ClassType.Class, context);
357
412
  break;
358
413
  case ts.SyntaxKind.EnumDeclaration:
359
- parseDTSTopLevelItem(node, allClasses, ClassType.Enum);
414
+ parseDTSTopLevelItem(node, allClasses, ClassType.Enum, context);
360
415
  break;
361
416
  case ts.SyntaxKind.FunctionDeclaration:
362
- parseDTSGlobalFunctionItem(node, allClasses);
417
+ parseDTSGlobalFunctionItem(node, allClasses, context);
363
418
  break;
364
419
  case ts.SyntaxKind.PropertySignature:
365
- parseDTSFieldItem(node, FieldType.Property);
420
+ parseDTSFieldItem(node, FieldType.Property, context);
366
421
  break;
367
422
  case ts.SyntaxKind.PropertyDeclaration:
368
- parseDTSFieldItem(node, FieldType.Property);
423
+ parseDTSFieldItem(node, FieldType.Property, context);
369
424
  break;
370
425
  case ts.SyntaxKind.EnumMember:
371
- parseDTSFieldItem(node, FieldType.Enum);
426
+ parseDTSFieldItem(node, FieldType.Enum, context);
372
427
  break;
373
428
  case ts.SyntaxKind.MethodSignature:
374
- parseDTSFieldItem(node, FieldType.Method);
429
+ parseDTSFieldItem(node, FieldType.Method, context);
375
430
  break;
376
431
  case ts.SyntaxKind.MethodDeclaration:
377
- parseDTSFieldItem(node, FieldType.Method);
432
+ parseDTSFieldItem(node, FieldType.Method, context);
378
433
  break;
379
434
  case ts.SyntaxKind.TypeLiteral:
380
435
  return;
@@ -382,39 +437,36 @@ function parseDTSInternal(node, allClasses) {
382
437
  // the compiler parses comments after the class/field, therefore this connects to the previous item
383
438
  if (node.getText().indexOf("/**") >= 0 &&
384
439
  node.getText().indexOf("*/") >= 0 &&
385
- lastItem !== null &&
386
- lastItem.comment === "") {
440
+ context.lastItem !== null &&
441
+ context.lastItem.comment === "") {
387
442
  // clean up spacing as best we can for the diffed d.ts
388
- lastItem.comment = node.getText().replace(/ \*/g, "*");
389
- if (lastItem.comment.indexOf("@eventproperty") >= 0) {
443
+ context.lastItem.comment = node.getText().replace(/ \*/g, "*");
444
+ if (context.lastItem.comment.indexOf("@eventproperty") >= 0) {
390
445
  // events are indistinguishable from properties aside from this tag
391
- lastItem.type = FieldType.Event;
446
+ context.lastItem.type = FieldType.Event;
392
447
  }
393
448
  }
394
449
  }
395
450
  node.getChildren().forEach((element) => {
396
- parseDTSInternal(element, allClasses);
451
+ parseDTSInternal(element, allClasses, context);
397
452
  });
398
453
  }
399
- function parseDTSTopLevelItem(node, allClasses, type) {
400
- topClass = new ClassStruct("export " + type.toLowerCase() + " " + node.name.text, "", type);
401
- allClasses.addClass(topClass);
402
- lastItem = topClass;
454
+ function parseDTSTopLevelItem(node, allClasses, type, context) {
455
+ context.topClass = new ClassStruct("export " + type.toLowerCase() + " " + node.name.text, "", type);
456
+ allClasses.addClass(context.topClass);
457
+ context.lastItem = context.topClass;
403
458
  }
404
- function parseDTSFieldItem(node, type) {
459
+ function parseDTSFieldItem(node, type, context) {
405
460
  const newField = new FieldStruct(node.getText(), "", type, node.name.getText());
406
- topClass.fields.push(newField);
407
- lastItem = newField;
461
+ context.topClass.fields.push(newField);
462
+ context.lastItem = newField;
408
463
  }
409
- function parseDTSGlobalFunctionItem(node, allClasses) {
464
+ function parseDTSGlobalFunctionItem(node, allClasses, context) {
410
465
  // Create a "<global>" class to hold top-level functions if it doesn't exist
411
- if (globalFunctionsClass === null) {
412
- globalFunctionsClass = new ClassStruct("<global>", "", ClassType.Interface);
413
- allClasses.addClass(globalFunctionsClass);
414
- }
466
+ const globalClass = context.ensureGlobalFunctionsClass(allClasses);
415
467
  const functionName = node.name ? node.name.getText() : "anonymous";
416
468
  const newFunction = new FieldStruct(node.getText(), "", FieldType.Function, functionName);
417
- globalFunctionsClass.fields.push(newFunction);
418
- lastItem = newFunction;
469
+ globalClass.fields.push(newFunction);
470
+ context.lastItem = newFunction;
419
471
  }
420
472
  //# sourceMappingURL=dts-utilities.js.map
@@ -1,3 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import { LinkConfig } from './dts-utilities';
3
- export declare function generateWhatsNew(newDtsPath: string, oldDtsPath: string, outputPath: string, relativePath: string, linkConfigs?: LinkConfig[], configFilePath?: string): void;
3
+ export interface WhatsNewOptions {
4
+ newDtsPath: string;
5
+ oldDtsPath: string;
6
+ outputPath: string;
7
+ relativePath: string;
8
+ linkConfigs?: LinkConfig[];
9
+ configFilePath?: string;
10
+ excludedFieldNames?: string[];
11
+ excludedClassPatterns?: string[];
12
+ excludedFieldPatterns?: string[];
13
+ includeStaticFields?: boolean;
14
+ includeEnums?: boolean;
15
+ }
16
+ /**
17
+ * Generates "what's new" documentation by comparing two TypeScript definition files.
18
+ * @param options - Configuration options for the generation
19
+ */
20
+ export declare function generateWhatsNew(options: WhatsNewOptions): void;
package/dist/whats-new.js CHANGED
@@ -38,48 +38,95 @@ exports.generateWhatsNew = generateWhatsNew;
38
38
  const fsx = __importStar(require("fs-extra"));
39
39
  const dts_utilities_1 = require("./dts-utilities");
40
40
  /**
41
- * Loads link configuration from a JSON file
41
+ * Loads configuration from a JSON file
42
42
  * @param configFilePath Path to the configuration file
43
- * @returns Array of LinkConfig objects
43
+ * @returns Configuration object with linkConfigs, excludedFieldNames, excludedClassPatterns, excludedFieldPatterns, includeStaticFields, and includeEnums
44
44
  */
45
- function loadLinkConfig(configFilePath) {
45
+ function loadWhatsNewConfig(configFilePath) {
46
46
  try {
47
47
  const configContent = fsx.readFileSync(configFilePath, 'utf8');
48
48
  const config = JSON.parse(configContent);
49
- // Validate that the config has the required template properties
50
- return config.linkConfigs.map((item) => {
51
- if (!item.globalFunctionTemplate || !item.classTemplate || !item.classMemberTemplate) {
52
- throw new Error(`Configuration item missing required template properties: ${JSON.stringify(item)}`);
53
- }
54
- return {
55
- pathPattern: item.pathPattern,
56
- globalFunctionTemplate: item.globalFunctionTemplate,
57
- classTemplate: item.classTemplate,
58
- classMemberTemplate: item.classMemberTemplate
59
- };
60
- });
49
+ let linkConfigs = undefined;
50
+ // Handle linkConfigs if present
51
+ if (config.linkConfigs) {
52
+ linkConfigs = config.linkConfigs.map((item) => {
53
+ if (!item.globalFunctionTemplate || !item.classTemplate || !item.classMemberTemplate) {
54
+ throw new Error(`Configuration item missing required template properties: ${JSON.stringify(item)}`);
55
+ }
56
+ return {
57
+ pathPattern: item.pathPattern,
58
+ globalFunctionTemplate: item.globalFunctionTemplate,
59
+ classTemplate: item.classTemplate,
60
+ classMemberTemplate: item.classMemberTemplate
61
+ };
62
+ });
63
+ }
64
+ return {
65
+ linkConfigs,
66
+ excludedFieldNames: config.excludedFieldNames,
67
+ excludedClassPatterns: config.excludedClassPatterns,
68
+ excludedFieldPatterns: config.excludedFieldPatterns,
69
+ includeStaticFields: config.includeStaticFields,
70
+ includeEnums: config.includeEnums
71
+ };
61
72
  }
62
73
  catch (error) {
63
74
  console.warn(`Could not load config file ${configFilePath}: ${error}. Using default configuration.`);
64
- return [];
75
+ return {};
65
76
  }
66
77
  }
67
- function generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath, linkConfigs, configFilePath) {
78
+ /**
79
+ * Generates "what's new" documentation by comparing two TypeScript definition files.
80
+ * @param options - Configuration options for the generation
81
+ */
82
+ function generateWhatsNew(options) {
68
83
  // Load configuration from file if provided
69
- let effectiveLinkConfigs = linkConfigs;
70
- if (configFilePath && !linkConfigs) {
71
- effectiveLinkConfigs = loadLinkConfig(configFilePath);
84
+ let effectiveLinkConfigs = options.linkConfigs;
85
+ let effectiveExcludedFieldNames = options.excludedFieldNames;
86
+ let effectiveExcludedClassPatterns = options.excludedClassPatterns;
87
+ let effectiveExcludedFieldPatterns = options.excludedFieldPatterns;
88
+ let effectiveIncludeStaticFields = options.includeStaticFields;
89
+ let effectiveIncludeEnums = options.includeEnums;
90
+ if (options.configFilePath && (!options.linkConfigs || !options.excludedFieldNames || !options.excludedClassPatterns || !options.excludedFieldPatterns || options.includeStaticFields === undefined || options.includeEnums === undefined)) {
91
+ const config = loadWhatsNewConfig(options.configFilePath);
92
+ if (!options.linkConfigs && config.linkConfigs) {
93
+ effectiveLinkConfigs = config.linkConfigs;
94
+ }
95
+ if (!options.excludedFieldNames && config.excludedFieldNames) {
96
+ effectiveExcludedFieldNames = config.excludedFieldNames;
97
+ }
98
+ if (!options.excludedClassPatterns && config.excludedClassPatterns) {
99
+ effectiveExcludedClassPatterns = config.excludedClassPatterns;
100
+ }
101
+ if (!options.excludedFieldPatterns && config.excludedFieldPatterns) {
102
+ effectiveExcludedFieldPatterns = config.excludedFieldPatterns;
103
+ }
104
+ if (options.includeStaticFields === undefined && config.includeStaticFields !== undefined) {
105
+ effectiveIncludeStaticFields = config.includeStaticFields;
106
+ }
107
+ if (options.includeEnums === undefined) {
108
+ // Default to true when loading from config (inclusive by default)
109
+ effectiveIncludeEnums = config.includeEnums !== undefined ? config.includeEnums : true;
110
+ }
72
111
  }
73
112
  // read whole files
74
- let wholeRelease = fsx.readFileSync(oldDtsPath).toString();
75
- let wholePreview = fsx.readFileSync(newDtsPath).toString();
113
+ let wholeRelease = fsx.readFileSync(options.oldDtsPath).toString();
114
+ let wholePreview = fsx.readFileSync(options.newDtsPath).toString();
76
115
  const releaseAPI = (0, dts_utilities_1.parseDTS)("release", wholeRelease);
77
116
  const previewAPI = (0, dts_utilities_1.parseDTS)("preview", wholePreview);
78
117
  const diffAPI = previewAPI.diff(releaseAPI);
79
- if (!fsx.existsSync(outputPath + ".md")) {
80
- fsx.createFileSync(outputPath + ".md");
118
+ if (!fsx.existsSync(options.outputPath + ".md")) {
119
+ fsx.createFileSync(options.outputPath + ".md");
81
120
  }
82
- fsx.writeFileSync(outputPath + ".md", diffAPI.getAsMarkdown(relativePath, effectiveLinkConfigs));
121
+ fsx.writeFileSync(options.outputPath + ".md", diffAPI.getAsMarkdown({
122
+ relativePath: options.relativePath,
123
+ linkConfigs: effectiveLinkConfigs,
124
+ excludedFieldNames: effectiveExcludedFieldNames,
125
+ excludedClassPatterns: effectiveExcludedClassPatterns,
126
+ excludedFieldPatterns: effectiveExcludedFieldPatterns,
127
+ includeStaticFields: effectiveIncludeStaticFields,
128
+ includeEnums: effectiveIncludeEnums
129
+ }));
83
130
  }
84
131
  // CLI entry point
85
132
  if (require.main === module) {
@@ -99,7 +146,13 @@ if (require.main === module) {
99
146
  console.log(`Using configuration file: ${configFilePath}`);
100
147
  }
101
148
  tryCatch(async () => {
102
- generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath, undefined, configFilePath);
149
+ generateWhatsNew({
150
+ newDtsPath,
151
+ oldDtsPath,
152
+ outputPath,
153
+ relativePath,
154
+ configFilePath
155
+ });
103
156
  });
104
157
  }
105
158
  async function tryCatch(call) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "versioned-d.ts-tools",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "Tools for managing versioned TypeScript definition files",
5
5
  "main": "dist/index.js",
6
6
  "bin": {