versioned-d.ts-tools 0.4.1 → 0.5.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 CHANGED
@@ -90,16 +90,50 @@ 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
- **Example:**
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
104
+ ```
105
+
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. This is useful when different Office applications have different URL patterns.
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
+ },
122
+ {
123
+ "name": "Standard Office Applications",
124
+ "pathPattern": ".*",
125
+ "description": "Standard URL pattern for Excel, Word, PowerPoint, Outlook"
126
+ }
127
+ ]
128
+ }
100
129
  ```
101
130
 
102
- This generates a `excel_whats_new.md` file containing a markdown table showing what's new between the two versions.
131
+ When a configuration file is provided, the tool will use the appropriate URL pattern based on the relative path. For example:
132
+
133
+ - Office Scripts APIs will use the Office Scripts-specific URL format
134
+ - Other Office applications will use the standard URL format
135
+
136
+ See `example-link-config.json` for a complete example.
103
137
 
104
138
  ## Programmatic Usage
105
139
 
@@ -1,3 +1,8 @@
1
+ export interface LinkConfig {
2
+ pathPattern: string;
3
+ buildLink: (relativePath: string, className: string, field: FieldStruct) => string;
4
+ }
5
+ export declare const DEFAULT_LINK_CONFIGS: LinkConfig[];
1
6
  declare enum ClassType {
2
7
  Class = "Class",
3
8
  Interface = "Interface",
@@ -35,7 +40,7 @@ export declare class APISet {
35
40
  containsField(clas: ClassStruct, field: FieldStruct): boolean;
36
41
  diff(other: APISet): APISet;
37
42
  getAsDTS(): string;
38
- getAsMarkdown(relativePath: string): string;
43
+ getAsMarkdown(relativePath: string, linkConfigs?: LinkConfig[]): string;
39
44
  sort(): void;
40
45
  }
41
46
  export declare function parseDTS(fileName: string, fileContents: string): APISet;
@@ -33,9 +33,52 @@ 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
+ // Default link builder for Office Scripts
40
+ function buildOfficeScriptsLink(relativePath, className, field) {
41
+ if (className === "<global>") {
42
+ const basePath = relativePath.substring(0, relativePath.lastIndexOf("."));
43
+ return "/" + basePath + "#officescript-officescript-" + field.name.toLowerCase() + "-function(1)";
44
+ }
45
+ else {
46
+ const suffix = (field.type === FieldType.Method || field.type === FieldType.Function) ? "-member(1)" : "-member";
47
+ const url = "/" + relativePath + className.toLowerCase();
48
+ const anchor = "officescript-officescript-" + className.toLowerCase() + "-" + field.name.toLowerCase() + suffix;
49
+ return url + "#" + anchor;
50
+ }
51
+ }
52
+ // Default link builder for standard Office applications
53
+ function buildStandardLink(relativePath, className, field) {
54
+ if (className === "<global>") {
55
+ const hostName = relativePath.substring(relativePath.indexOf("/api/") + 5, relativePath.lastIndexOf("/"));
56
+ const fileName = relativePath.substring(relativePath.lastIndexOf("/") + 1, relativePath.lastIndexOf("."));
57
+ const basePath = relativePath.substring(0, relativePath.lastIndexOf("."));
58
+ const anchorPrefix = hostName + "-" + fileName + "-";
59
+ return "/" + basePath + "#" + anchorPrefix + field.name.toLowerCase() + "-function(1)";
60
+ }
61
+ else {
62
+ const hostName = relativePath.substring(relativePath.indexOf("/api/") + 5, relativePath.lastIndexOf("/"));
63
+ const fileName = relativePath.substring(relativePath.lastIndexOf("/") + 1, relativePath.lastIndexOf("."));
64
+ const suffix = (field.type === FieldType.Method || field.type === FieldType.Function) ? "-member(1)" : "-member";
65
+ const url = "/" + relativePath + className.toLowerCase();
66
+ const anchorPrefix = hostName + "-" + fileName + "-";
67
+ const anchor = anchorPrefix + className.toLowerCase() + "-" + field.name.toLowerCase() + suffix;
68
+ return url + "#" + anchor;
69
+ }
70
+ }
71
+ // Default configurations for known Office applications
72
+ exports.DEFAULT_LINK_CONFIGS = [
73
+ {
74
+ pathPattern: "office-scripts",
75
+ buildLink: buildOfficeScriptsLink
76
+ },
77
+ {
78
+ pathPattern: ".*", // matches any path as fallback
79
+ buildLink: buildStandardLink
80
+ }
81
+ ];
39
82
  // capturing these because of eccentricities with the compiler ordering
40
83
  let topClass = null;
41
84
  let lastItem = null;
@@ -156,7 +199,7 @@ class APISet {
156
199
  });
157
200
  return output.join("\n");
158
201
  }
159
- getAsMarkdown(relativePath) {
202
+ getAsMarkdown(relativePath, linkConfigs = exports.DEFAULT_LINK_CONFIGS) {
160
203
  this.sort();
161
204
  // table header
162
205
  let output = "| Class | Fields | Description |\n|:---|:---|:---|\n";
@@ -171,7 +214,7 @@ class APISet {
171
214
  const className = clas.getClassName();
172
215
  // Special handling for <global> - no link
173
216
  if (className === "<global>") {
174
- output += "|*" + className + "*|";
217
+ output += "|*global*|";
175
218
  }
176
219
  else {
177
220
  output += "|[" + className + "](/"
@@ -226,7 +269,7 @@ class APISet {
226
269
  newItemText = newItemText.replace(/[\s][\s]+/g, " ").replace(/\( /g, "(").replace(/ \)/g, ")").replace(/,\)/g, ")").replace(/([\w]\??: )\\\| /g, "$1"); // dprint formatting quirks
227
270
  newItemText = newItemText.replace(/\<any\>/g, "");
228
271
  let tableLine = "[" + newItemText + "]("
229
- + buildFieldLink(relativePath, className, field) + ")|";
272
+ + buildFieldLink(relativePath, className, field, linkConfigs) + ")|";
230
273
  tableLine += removeAtLink(extractFirstSentenceFromComment(field.comment));
231
274
  output += tableLine + "|\n";
232
275
  });
@@ -277,20 +320,11 @@ function removeAtLink(commentText) {
277
320
  commentText = commentText.replace(/{@link ([^}]*?) \| (http.*?)}/gm, "[$1]($2)");
278
321
  return commentText;
279
322
  }
280
- function buildFieldLink(relativePath, className, field) {
281
- // Special handling for global functions - use a different link format
282
- if (className === "<global>") {
283
- let hostName = relativePath.substring(relativePath.indexOf("/api/") + 5, relativePath.lastIndexOf("/"));
284
- let fileName = relativePath.substring(relativePath.lastIndexOf("/") + 1, relativePath.lastIndexOf("."));
285
- let anchorPrefix = hostName + "-" + fileName + "-";
286
- return "/" + relativePath.substring(0, relativePath.lastIndexOf(".")) + "#" + anchorPrefix + field.name.toLowerCase() + "-function";
287
- }
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;
323
+ function buildFieldLink(relativePath, className, field, linkConfigs = exports.DEFAULT_LINK_CONFIGS) {
324
+ // Find the first matching configuration
325
+ 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
326
+ // Use the configuration's link builder
327
+ return config.buildLink(relativePath, className, field);
294
328
  }
295
329
  function parseDTS(fileName, fileContents) {
296
330
  // Reset global state for new parse
@@ -1,2 +1,3 @@
1
1
  #!/usr/bin/env node
2
- export declare function generateWhatsNew(newDtsPath: string, oldDtsPath: string, outputPath: string, relativePath: string): void;
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,38 @@ 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
- function generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath) {
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
+ // Convert the config to LinkConfig objects with actual functions
50
+ return config.linkConfigs.map((item) => ({
51
+ pathPattern: new RegExp(item.pathPattern),
52
+ buildLink: item.pathPattern === "office-scripts"
53
+ ? (namespace, className) => className === "*global*"
54
+ ? `/javascript/api/office-scripts/officescript/officescript#officescript-officescript-${namespace.toLowerCase()}-function(1)`
55
+ : `/javascript/api/office-scripts/officescript/officescript.${className.toLowerCase()}#officescript-officescript-${className.toLowerCase()}-${namespace.toLowerCase()}-member(1)`
56
+ : (namespace, className) => className === "*global*"
57
+ ? `/javascript/api/${namespace}/${namespace}#${namespace}-${namespace}-${namespace.toLowerCase()}-function(1)`
58
+ : `/javascript/api/${namespace}/${namespace}.${className.toLowerCase()}#${namespace}-${namespace}-${className.toLowerCase()}-${namespace.toLowerCase()}-member(1)`
59
+ }));
60
+ }
61
+ catch (error) {
62
+ console.warn(`Could not load config file ${configFilePath}: ${error}. Using default configuration.`);
63
+ return [];
64
+ }
65
+ }
66
+ function generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath, linkConfigs, configFilePath) {
67
+ // Load configuration from file if provided
68
+ let effectiveLinkConfigs = linkConfigs;
69
+ if (configFilePath && !linkConfigs) {
70
+ effectiveLinkConfigs = loadLinkConfig(configFilePath);
71
+ }
41
72
  // read whole files
42
73
  let wholeRelease = fsx.readFileSync(oldDtsPath).toString();
43
74
  let wholePreview = fsx.readFileSync(newDtsPath).toString();
@@ -47,22 +78,27 @@ function generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath) {
47
78
  if (!fsx.existsSync(outputPath + ".md")) {
48
79
  fsx.createFileSync(outputPath + ".md");
49
80
  }
50
- fsx.writeFileSync(outputPath + ".md", diffAPI.getAsMarkdown(relativePath));
81
+ fsx.writeFileSync(outputPath + ".md", diffAPI.getAsMarkdown(relativePath, effectiveLinkConfigs));
51
82
  }
52
83
  // CLI entry point
53
84
  if (require.main === module) {
54
- if (process.argv.length !== 6 || process.argv.find((x) => { return x === "-?"; })) {
55
- console.log("usage: whats-new [new d.ts] [old d.ts] [output file name (minus extension)] [relative path]");
85
+ if (process.argv.length < 6 || process.argv.length > 7 || process.argv.find((x) => { return x === "-?"; })) {
86
+ console.log("usage: whats-new [new d.ts] [old d.ts] [output file name (minus extension)] [relative path] [config file (optional)]");
56
87
  console.log("example: whats-new excel_1_9.d.ts excel_1_8.d.ts excel_whats_new javascript/api/excel/excel.");
88
+ 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
89
  process.exit(0);
58
90
  }
59
91
  const newDtsPath = process.argv[2];
60
92
  const oldDtsPath = process.argv[3];
61
93
  const outputPath = process.argv[4];
62
94
  const relativePath = process.argv[5];
95
+ const configFilePath = process.argv.length === 7 ? process.argv[6] : undefined;
63
96
  console.log(`What's New between ${newDtsPath} and ${oldDtsPath}?`);
97
+ if (configFilePath) {
98
+ console.log(`Using configuration file: ${configFilePath}`);
99
+ }
64
100
  tryCatch(async () => {
65
- generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath);
101
+ generateWhatsNew(newDtsPath, oldDtsPath, outputPath, relativePath, undefined, configFilePath);
66
102
  });
67
103
  }
68
104
  async function tryCatch(call) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "versioned-d.ts-tools",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Tools for managing versioned TypeScript definition files",
5
5
  "main": "dist/index.js",
6
6
  "bin": {