versioned-d.ts-tools 0.4.2 → 0.6.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.
- package/README.md +53 -3
- package/dist/dts-utilities.d.ts +8 -1
- package/dist/dts-utilities.js +63 -18
- package/dist/whats-new.d.ts +2 -1
- package/dist/whats-new.js +42 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -90,16 +90,66 @@ You can provide an optional JSON configuration file to specify additional text r
|
|
|
90
90
|
Compares two TypeScript definition files and generates a markdown report of the differences.
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
|
-
whats-new [new d.ts] [old d.ts] [output file name (minus extension)] [relative path]
|
|
93
|
+
whats-new [new d.ts] [old d.ts] [output file name (minus extension)] [relative path] [config file (optional)]
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
**
|
|
96
|
+
**Examples:**
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
+
# Basic usage
|
|
99
100
|
whats-new excel_1_9.d.ts excel_1_8.d.ts excel_whats_new javascript/api/excel/excel.
|
|
101
|
+
|
|
102
|
+
# With configuration file for custom link patterns
|
|
103
|
+
whats-new office-scripts.d.ts office-scripts-old.d.ts office-scripts-whats-new javascript/api/office-scripts/ my-link-config.json
|
|
100
104
|
```
|
|
101
105
|
|
|
102
|
-
This generates a `excel_whats_new.md`
|
|
106
|
+
This generates a markdown file (e.g., `excel_whats_new.md`) containing a table showing what's new between the two versions.
|
|
107
|
+
|
|
108
|
+
#### Link Configuration File
|
|
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.
|
|
111
|
+
|
|
112
|
+
**Configuration file format:**
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"linkConfigs": [
|
|
117
|
+
{
|
|
118
|
+
"name": "Office Scripts",
|
|
119
|
+
"pathPattern": "office-scripts",
|
|
120
|
+
"description": "Special URL pattern for Office Scripts",
|
|
121
|
+
"globalFunctionTemplate": "/{basePath}#officescript-officescript-{fieldName}-function(1)",
|
|
122
|
+
"classTemplate": "/{basePath}/officescript.{className}",
|
|
123
|
+
"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
|
+
]
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Available Template Placeholders:**
|
|
138
|
+
- `{basePath}` - relativePath without the trailing dot (e.g., 'javascript/api/excel/excel')
|
|
139
|
+
- `{hostName}` - extracted host name (e.g., 'excel', 'office-scripts')
|
|
140
|
+
- `{fileName}` - extracted file name (e.g., 'excel', 'officescript')
|
|
141
|
+
- `{className}` - class name in lowercase
|
|
142
|
+
- `{fieldName}` - field/method name in lowercase
|
|
143
|
+
- `{suffix}` - '-member(1)' for methods/functions, '-member' for properties
|
|
144
|
+
|
|
145
|
+
**Template Types:**
|
|
146
|
+
- `globalFunctionTemplate` - For namespace-level functions (global functions)
|
|
147
|
+
- `classTemplate` - For class/interface URLs in the first column
|
|
148
|
+
- `classMemberTemplate` - For class members (methods, properties, events)
|
|
149
|
+
|
|
150
|
+
When a configuration file is provided, the tool will use the appropriate URL template based on the pattern matching. The first matching `pathPattern` (regex) wins.
|
|
151
|
+
|
|
152
|
+
See `example-link-config.json` for a complete example.
|
|
103
153
|
|
|
104
154
|
## Programmatic Usage
|
|
105
155
|
|
package/dist/dts-utilities.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export interface LinkConfig {
|
|
2
|
+
pathPattern: string;
|
|
3
|
+
globalFunctionTemplate: string;
|
|
4
|
+
classTemplate: string;
|
|
5
|
+
classMemberTemplate: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const DEFAULT_LINK_CONFIGS: LinkConfig[];
|
|
1
8
|
declare enum ClassType {
|
|
2
9
|
Class = "Class",
|
|
3
10
|
Interface = "Interface",
|
|
@@ -35,7 +42,7 @@ export declare class APISet {
|
|
|
35
42
|
containsField(clas: ClassStruct, field: FieldStruct): boolean;
|
|
36
43
|
diff(other: APISet): APISet;
|
|
37
44
|
getAsDTS(): string;
|
|
38
|
-
getAsMarkdown(relativePath: string): string;
|
|
45
|
+
getAsMarkdown(relativePath: string, linkConfigs?: LinkConfig[]): string;
|
|
39
46
|
sort(): void;
|
|
40
47
|
}
|
|
41
48
|
export declare function parseDTS(fileName: string, fileContents: string): APISet;
|
package/dist/dts-utilities.js
CHANGED
|
@@ -33,9 +33,53 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.APISet = void 0;
|
|
36
|
+
exports.APISet = exports.DEFAULT_LINK_CONFIGS = void 0;
|
|
37
37
|
exports.parseDTS = parseDTS;
|
|
38
38
|
const ts = __importStar(require("typescript"));
|
|
39
|
+
// Available placeholders:
|
|
40
|
+
// {basePath} - relativePath without the trailing dot
|
|
41
|
+
// {hostName} - extracted host name (e.g., "excel", "office-scripts")
|
|
42
|
+
// {fileName} - extracted file name (e.g., "excel", "officescript")
|
|
43
|
+
// {className} - class name in lowercase
|
|
44
|
+
// {fieldName} - field/method name in lowercase
|
|
45
|
+
// {suffix} - "-member(1)" for methods/functions, "-member" for properties
|
|
46
|
+
// Default link builder using templates
|
|
47
|
+
function buildLinkFromTemplate(template, relativePath, className, field) {
|
|
48
|
+
const basePath = relativePath.substring(0, relativePath.lastIndexOf("."));
|
|
49
|
+
const hostName = relativePath.includes("/api/")
|
|
50
|
+
? relativePath.substring(relativePath.indexOf("/api/") + 5, relativePath.lastIndexOf("/"))
|
|
51
|
+
: "";
|
|
52
|
+
const fileName = relativePath.substring(relativePath.lastIndexOf("/") + 1, relativePath.lastIndexOf("."));
|
|
53
|
+
let result = template
|
|
54
|
+
.replace(/{basePath}/g, basePath)
|
|
55
|
+
.replace(/{hostName}/g, hostName)
|
|
56
|
+
.replace(/{fileName}/g, fileName);
|
|
57
|
+
if (className && className !== "<global>") {
|
|
58
|
+
result = result.replace(/{className}/g, className.toLowerCase());
|
|
59
|
+
}
|
|
60
|
+
if (field) {
|
|
61
|
+
const suffix = (field.type === FieldType.Method || field.type === FieldType.Function) ? "-member(1)" : "-member";
|
|
62
|
+
result = result
|
|
63
|
+
.replace(/{fieldName}/g, field.name.toLowerCase())
|
|
64
|
+
.replace(/{suffix}/g, suffix);
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
// Default configurations for known Office applications
|
|
69
|
+
exports.DEFAULT_LINK_CONFIGS = [
|
|
70
|
+
{
|
|
71
|
+
pathPattern: "office-scripts",
|
|
72
|
+
globalFunctionTemplate: "/{basePath}#officescript-officescript-{fieldName}-function(1)",
|
|
73
|
+
classTemplate: "/{basePath}/officescript.{className}",
|
|
74
|
+
classMemberTemplate: "/{basePath}/officescript.{className}#officescript-officescript-{className}-{fieldName}{suffix}"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
pathPattern: ".*", // matches any path as fallback
|
|
78
|
+
globalFunctionTemplate: "/{basePath}#{hostName}-{fileName}-{fieldName}-function(1)",
|
|
79
|
+
classTemplate: "/{basePath}.{className}",
|
|
80
|
+
classMemberTemplate: "/{basePath}.{className}#{hostName}-{fileName}-{className}-{fieldName}{suffix}"
|
|
81
|
+
}
|
|
82
|
+
];
|
|
39
83
|
// capturing these because of eccentricities with the compiler ordering
|
|
40
84
|
let topClass = null;
|
|
41
85
|
let lastItem = null;
|
|
@@ -156,7 +200,7 @@ class APISet {
|
|
|
156
200
|
});
|
|
157
201
|
return output.join("\n");
|
|
158
202
|
}
|
|
159
|
-
getAsMarkdown(relativePath) {
|
|
203
|
+
getAsMarkdown(relativePath, linkConfigs = exports.DEFAULT_LINK_CONFIGS) {
|
|
160
204
|
this.sort();
|
|
161
205
|
// table header
|
|
162
206
|
let output = "| Class | Fields | Description |\n|:---|:---|:---|\n";
|
|
@@ -174,8 +218,8 @@ class APISet {
|
|
|
174
218
|
output += "|*global*|";
|
|
175
219
|
}
|
|
176
220
|
else {
|
|
177
|
-
output += "|[" + className + "](
|
|
178
|
-
+ relativePath
|
|
221
|
+
output += "|[" + className + "]("
|
|
222
|
+
+ buildClassLink(relativePath, className, linkConfigs) + ")|";
|
|
179
223
|
}
|
|
180
224
|
// Ignore the following:
|
|
181
225
|
// - String literal overloads.
|
|
@@ -226,7 +270,7 @@ class APISet {
|
|
|
226
270
|
newItemText = newItemText.replace(/[\s][\s]+/g, " ").replace(/\( /g, "(").replace(/ \)/g, ")").replace(/,\)/g, ")").replace(/([\w]\??: )\\\| /g, "$1"); // dprint formatting quirks
|
|
227
271
|
newItemText = newItemText.replace(/\<any\>/g, "");
|
|
228
272
|
let tableLine = "[" + newItemText + "]("
|
|
229
|
-
+ buildFieldLink(relativePath, className, field) + ")|";
|
|
273
|
+
+ buildFieldLink(relativePath, className, field, linkConfigs) + ")|";
|
|
230
274
|
tableLine += removeAtLink(extractFirstSentenceFromComment(field.comment));
|
|
231
275
|
output += tableLine + "|\n";
|
|
232
276
|
});
|
|
@@ -277,20 +321,21 @@ function removeAtLink(commentText) {
|
|
|
277
321
|
commentText = commentText.replace(/{@link ([^}]*?) \| (http.*?)}/gm, "[$1]($2)");
|
|
278
322
|
return commentText;
|
|
279
323
|
}
|
|
280
|
-
function
|
|
281
|
-
//
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
324
|
+
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
|
|
327
|
+
return buildLinkFromTemplate(config.classTemplate, relativePath, className);
|
|
328
|
+
}
|
|
329
|
+
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
|
|
332
|
+
// Use appropriate template based on whether it's a global function or class member
|
|
333
|
+
if (className.trim() === "<global>") {
|
|
334
|
+
return buildLinkFromTemplate(config.globalFunctionTemplate, relativePath, className, field);
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
return buildLinkFromTemplate(config.classMemberTemplate, relativePath, className, field);
|
|
287
338
|
}
|
|
288
|
-
// Build the standard link anchor format based on host.
|
|
289
|
-
let hostName = relativePath.substring(relativePath.indexOf("/api/") + 5, relativePath.lastIndexOf("/"));
|
|
290
|
-
let fileName = relativePath.substring(relativePath.lastIndexOf("/") + 1, relativePath.lastIndexOf("."));
|
|
291
|
-
let anchorPrefix = hostName + "-" + fileName + "-";
|
|
292
|
-
let fieldLink = "/" + relativePath + className.toLowerCase() + "#" + anchorPrefix + className.toLowerCase() + "-" + field.name.toLowerCase() + ((field.type === FieldType.Method || field.type === FieldType.Function) ? "-member(1)" : "-member");
|
|
293
|
-
return fieldLink;
|
|
294
339
|
}
|
|
295
340
|
function parseDTS(fileName, fileContents) {
|
|
296
341
|
// Reset global state for new parse
|
package/dist/whats-new.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
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;
|
package/dist/whats-new.js
CHANGED
|
@@ -37,7 +37,39 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
37
37
|
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
|
|
42
|
+
* @param configFilePath Path to the configuration file
|
|
43
|
+
* @returns Array of LinkConfig objects
|
|
44
|
+
*/
|
|
45
|
+
function loadLinkConfig(configFilePath) {
|
|
46
|
+
try {
|
|
47
|
+
const configContent = fsx.readFileSync(configFilePath, 'utf8');
|
|
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
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.warn(`Could not load config file ${configFilePath}: ${error}. Using default configuration.`);
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath, linkConfigs, configFilePath) {
|
|
68
|
+
// Load configuration from file if provided
|
|
69
|
+
let effectiveLinkConfigs = linkConfigs;
|
|
70
|
+
if (configFilePath && !linkConfigs) {
|
|
71
|
+
effectiveLinkConfigs = loadLinkConfig(configFilePath);
|
|
72
|
+
}
|
|
41
73
|
// read whole files
|
|
42
74
|
let wholeRelease = fsx.readFileSync(oldDtsPath).toString();
|
|
43
75
|
let wholePreview = fsx.readFileSync(newDtsPath).toString();
|
|
@@ -47,22 +79,27 @@ function generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath) {
|
|
|
47
79
|
if (!fsx.existsSync(outputPath + ".md")) {
|
|
48
80
|
fsx.createFileSync(outputPath + ".md");
|
|
49
81
|
}
|
|
50
|
-
fsx.writeFileSync(outputPath + ".md", diffAPI.getAsMarkdown(relativePath));
|
|
82
|
+
fsx.writeFileSync(outputPath + ".md", diffAPI.getAsMarkdown(relativePath, effectiveLinkConfigs));
|
|
51
83
|
}
|
|
52
84
|
// CLI entry point
|
|
53
85
|
if (require.main === module) {
|
|
54
|
-
if (process.argv.length
|
|
55
|
-
console.log("usage: whats-new [new d.ts] [old d.ts] [output file name (minus extension)] [relative path]");
|
|
86
|
+
if (process.argv.length < 6 || process.argv.length > 7 || process.argv.find((x) => { return x === "-?"; })) {
|
|
87
|
+
console.log("usage: whats-new [new d.ts] [old d.ts] [output file name (minus extension)] [relative path] [config file (optional)]");
|
|
56
88
|
console.log("example: whats-new excel_1_9.d.ts excel_1_8.d.ts excel_whats_new javascript/api/excel/excel.");
|
|
89
|
+
console.log("example with config: whats-new excel_1_9.d.ts excel_1_8.d.ts excel_whats_new javascript/api/excel/excel. my-config.json");
|
|
57
90
|
process.exit(0);
|
|
58
91
|
}
|
|
59
92
|
const newDtsPath = process.argv[2];
|
|
60
93
|
const oldDtsPath = process.argv[3];
|
|
61
94
|
const outputPath = process.argv[4];
|
|
62
95
|
const relativePath = process.argv[5];
|
|
96
|
+
const configFilePath = process.argv.length === 7 ? process.argv[6] : undefined;
|
|
63
97
|
console.log(`What's New between ${newDtsPath} and ${oldDtsPath}?`);
|
|
98
|
+
if (configFilePath) {
|
|
99
|
+
console.log(`Using configuration file: ${configFilePath}`);
|
|
100
|
+
}
|
|
64
101
|
tryCatch(async () => {
|
|
65
|
-
generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath);
|
|
102
|
+
generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath, undefined, configFilePath);
|
|
66
103
|
});
|
|
67
104
|
}
|
|
68
105
|
async function tryCatch(call) {
|