mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-12-11 17:41:26 -06:00
If these are regular comments, then they won't appear in our d.ts files. But, now we are relying on an external d.ts bundler to produce our final merged, so they need to be present in the "input" d.ts files, meaning they have to be JSDoc comments. These comments only work today because all of our builds load their TS files from scratch, so they see the actual source files and their non-JSDoc comments. The comments also need to be attached to a declaration, not floating, otherwise they won't be used by api-extractor, so move them if needed.
154 lines
5.3 KiB
JavaScript
154 lines
5.3 KiB
JavaScript
import path from "path";
|
|
import fs from "fs";
|
|
|
|
/** @typedef {{
|
|
category: string;
|
|
code: number;
|
|
reportsUnnecessary?: {};
|
|
reportsDeprecated?: {};
|
|
isEarly?: boolean;
|
|
elidedInCompatabilityPyramid?: boolean;
|
|
}} DiagnosticDetails */
|
|
void 0;
|
|
|
|
/** @typedef {Map<string, DiagnosticDetails>} InputDiagnosticMessageTable */
|
|
|
|
function main() {
|
|
if (process.argv.length < 3) {
|
|
console.log("Usage:");
|
|
console.log("\tnode processDiagnosticMessages.mjs <diagnostic-json-input-file>");
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @param {string} fileName
|
|
* @param {string} contents
|
|
*/
|
|
function writeFile(fileName, contents) {
|
|
fs.writeFile(path.join(path.dirname(inputFilePath), fileName), contents, { encoding: "utf-8" }, err => {
|
|
if (err) throw err;
|
|
});
|
|
}
|
|
|
|
const inputFilePath = process.argv[2].replace(/\\/g, "/");
|
|
console.log(`Reading diagnostics from ${inputFilePath}`);
|
|
const inputStr = fs.readFileSync(inputFilePath, { encoding: "utf-8" });
|
|
|
|
/** @type {{ [key: string]: DiagnosticDetails }} */
|
|
const diagnosticMessagesJson = JSON.parse(inputStr);
|
|
|
|
/** @type {InputDiagnosticMessageTable} */
|
|
const diagnosticMessages = new Map();
|
|
for (const key in diagnosticMessagesJson) {
|
|
if (Object.hasOwnProperty.call(diagnosticMessagesJson, key)) {
|
|
diagnosticMessages.set(key, diagnosticMessagesJson[key]);
|
|
}
|
|
}
|
|
|
|
const infoFileOutput = buildInfoFileOutput(diagnosticMessages, inputFilePath);
|
|
checkForUniqueCodes(diagnosticMessages);
|
|
writeFile("diagnosticInformationMap.generated.ts", infoFileOutput);
|
|
|
|
const messageOutput = buildDiagnosticMessageOutput(diagnosticMessages);
|
|
writeFile("diagnosticMessages.generated.json", messageOutput);
|
|
}
|
|
|
|
/**
|
|
* @param {InputDiagnosticMessageTable} diagnosticTable
|
|
*/
|
|
function checkForUniqueCodes(diagnosticTable) {
|
|
/** @type {Record<number, true | undefined>} */
|
|
const allCodes = [];
|
|
diagnosticTable.forEach(({ code }) => {
|
|
if (allCodes[code]) {
|
|
throw new Error(`Diagnostic code ${code} appears more than once.`);
|
|
}
|
|
allCodes[code] = true;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param {InputDiagnosticMessageTable} messageTable
|
|
* @param {string} inputFilePathRel
|
|
* @returns {string}
|
|
*/
|
|
function buildInfoFileOutput(messageTable, inputFilePathRel) {
|
|
const result = [
|
|
"// <auto-generated />",
|
|
`// generated from '${inputFilePathRel}'`,
|
|
"",
|
|
"import { DiagnosticCategory, DiagnosticMessage } from \"./types\";",
|
|
"",
|
|
"function diag(code: number, category: DiagnosticCategory, key: string, message: string, reportsUnnecessary?: {}, elidedInCompatabilityPyramid?: boolean, reportsDeprecated?: {}): DiagnosticMessage {",
|
|
" return { code, category, key, message, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated };",
|
|
"}",
|
|
"",
|
|
"/** @internal */",
|
|
"export const Diagnostics = {",
|
|
];
|
|
messageTable.forEach(({ code, category, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated }, name) => {
|
|
const propName = convertPropertyName(name);
|
|
const argReportsUnnecessary = reportsUnnecessary ? `, /*reportsUnnecessary*/ ${reportsUnnecessary}` : "";
|
|
const argElidedInCompatabilityPyramid = elidedInCompatabilityPyramid ? `${!reportsUnnecessary ? ", /*reportsUnnecessary*/ undefined" : ""}, /*elidedInCompatabilityPyramid*/ ${elidedInCompatabilityPyramid}` : "";
|
|
const argReportsDeprecated = reportsDeprecated ? `${!argElidedInCompatabilityPyramid ? ", /*reportsUnnecessary*/ undefined, /*elidedInCompatabilityPyramid*/ undefined" : ""}, /*reportsDeprecated*/ ${reportsDeprecated}` : "";
|
|
|
|
result.push(` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}${argReportsUnnecessary}${argElidedInCompatabilityPyramid}${argReportsDeprecated}),`);
|
|
});
|
|
|
|
result.push("};");
|
|
|
|
return result.join("\r\n");
|
|
}
|
|
|
|
/**
|
|
* @param {InputDiagnosticMessageTable} messageTable
|
|
* @returns {string}
|
|
*/
|
|
function buildDiagnosticMessageOutput(messageTable) {
|
|
/** @type {Record<string, string>} */
|
|
const result = {};
|
|
|
|
messageTable.forEach(({ code }, name) => {
|
|
const propName = convertPropertyName(name);
|
|
result[createKey(propName, code)] = name;
|
|
});
|
|
|
|
return JSON.stringify(result, undefined, 2).replace(/\r?\n/g, "\r\n");
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {string} name
|
|
* @param {number} code
|
|
* @returns {string}
|
|
*/
|
|
function createKey(name, code) {
|
|
return name.slice(0, 100) + "_" + code;
|
|
}
|
|
|
|
/**
|
|
* @param {string} origName
|
|
* @returns {string}
|
|
*/
|
|
function convertPropertyName(origName) {
|
|
let result = origName.split("").map(char => {
|
|
if (char === "*") return "_Asterisk";
|
|
if (char === "/") return "_Slash";
|
|
if (char === ":") return "_Colon";
|
|
return /\w/.test(char) ? char : "_";
|
|
}).join("");
|
|
|
|
// get rid of all multi-underscores
|
|
result = result.replace(/_+/g, "_");
|
|
|
|
// remove any leading underscore, unless it is followed by a number.
|
|
result = result.replace(/^_([^\d])/, "$1");
|
|
|
|
// get rid of all trailing underscores.
|
|
result = result.replace(/_$/, "");
|
|
|
|
return result;
|
|
}
|
|
|
|
main();
|