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 +40 -13
- package/dist/dts-utilities.d.ts +27 -1
- package/dist/dts-utilities.js +137 -85
- package/dist/whats-new.d.ts +18 -1
- package/dist/whats-new.js +79 -26
- package/package.json +1 -1
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
|
-
####
|
|
108
|
+
#### Configuration File
|
|
109
109
|
|
|
110
|
-
You can provide an optional JSON configuration file to customize
|
|
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)
|
package/dist/dts-utilities.d.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/dist/dts-utilities.js
CHANGED
|
@@ -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
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
-
|
|
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
|
-
|
|
151
|
-
|
|
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
|
-
|
|
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
|
-
// -
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
-
// -
|
|
226
|
-
// -
|
|
227
|
-
// -
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
|
321
|
-
commentText = commentText.replace(/{@link ([^}]*?) \| (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
342
|
-
|
|
343
|
-
|
|
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
|
-
|
|
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
|
-
|
|
418
|
-
lastItem = newFunction;
|
|
469
|
+
globalClass.fields.push(newFunction);
|
|
470
|
+
context.lastItem = newFunction;
|
|
419
471
|
}
|
|
420
472
|
//# sourceMappingURL=dts-utilities.js.map
|
package/dist/whats-new.d.ts
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { LinkConfig } from './dts-utilities';
|
|
3
|
-
export
|
|
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
|
|
41
|
+
* Loads configuration from a JSON file
|
|
42
42
|
* @param configFilePath Path to the configuration file
|
|
43
|
-
* @returns
|
|
43
|
+
* @returns Configuration object with linkConfigs, excludedFieldNames, excludedClassPatterns, excludedFieldPatterns, includeStaticFields, and includeEnums
|
|
44
44
|
*/
|
|
45
|
-
function
|
|
45
|
+
function loadWhatsNewConfig(configFilePath) {
|
|
46
46
|
try {
|
|
47
47
|
const configContent = fsx.readFileSync(configFilePath, 'utf8');
|
|
48
48
|
const config = JSON.parse(configContent);
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
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(
|
|
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(
|
|
149
|
+
generateWhatsNew({
|
|
150
|
+
newDtsPath,
|
|
151
|
+
oldDtsPath,
|
|
152
|
+
outputPath,
|
|
153
|
+
relativePath,
|
|
154
|
+
configFilePath
|
|
155
|
+
});
|
|
103
156
|
});
|
|
104
157
|
}
|
|
105
158
|
async function tryCatch(call) {
|