TypeScript/scripts/processDiagnosticMessages.ts

124 строки
4.9 KiB
TypeScript
Исходник Обычный вид История

import path = require("path");
import fs = require("fs");
2014-07-13 03:04:16 +04:00
interface DiagnosticDetails {
category: string;
code: number;
reportsUnnecessary?: {};
isEarly?: boolean;
elidedInCompatabilityPyramid?: boolean;
2014-07-13 03:04:16 +04:00
}
type InputDiagnosticMessageTable = Map<string, DiagnosticDetails>;
2014-07-13 03:04:16 +04:00
function main(): void {
if (process.argv.length < 3) {
console.log("Usage:");
console.log("\tnode processDiagnosticMessages.js <diagnostic-json-input-file>");
2014-07-13 03:04:16 +04:00
return;
}
function writeFile(fileName: string, contents: string) {
fs.writeFile(path.join(path.dirname(inputFilePath), fileName), contents, { encoding: "utf-8" }, err => {
if (err) throw err;
2019-06-14 09:46:02 +03:00
});
}
const inputFilePath = process.argv[2].replace(/\\/g, "/");
console.log(`Reading diagnostics from ${inputFilePath}`);
const inputStr = fs.readFileSync(inputFilePath, { encoding: "utf-8" });
2016-12-06 01:13:32 +03:00
const diagnosticMessagesJson: { [key: string]: DiagnosticDetails } = JSON.parse(inputStr);
2014-07-13 03:04:16 +04:00
const diagnosticMessages: InputDiagnosticMessageTable = new Map();
for (const key in diagnosticMessagesJson) {
if (Object.hasOwnProperty.call(diagnosticMessagesJson, key)) {
diagnosticMessages.set(key, diagnosticMessagesJson[key]);
}
}
const outputFilesDir = path.dirname(inputFilePath);
const thisFilePathRel = path.relative(process.cwd(), outputFilesDir);
const infoFileOutput = buildInfoFileOutput(diagnosticMessages, "./diagnosticInformationMap.generated.ts", thisFilePathRel);
checkForUniqueCodes(diagnosticMessages);
writeFile("diagnosticInformationMap.generated.ts", infoFileOutput);
const messageOutput = buildDiagnosticMessageOutput(diagnosticMessages);
writeFile("diagnosticMessages.generated.json", messageOutput);
2014-07-13 03:04:16 +04:00
}
function checkForUniqueCodes(diagnosticTable: InputDiagnosticMessageTable) {
const allCodes: { [key: number]: true | undefined } = [];
diagnosticTable.forEach(({ code }) => {
if (allCodes[code]) {
throw new Error(`Diagnostic code ${code} appears more than once.`);
}
allCodes[code] = true;
});
}
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, inputFilePathRel: string, thisFilePathRel: string): string {
let result =
"// <auto-generated />\r\n" +
2019-06-14 12:18:27 +03:00
"// generated from '" + inputFilePathRel + "' by '" + thisFilePathRel.replace(/\\/g, "/") + "'\r\n" +
"/* @internal */\r\n" +
"namespace ts {\r\n" +
" function diag(code: number, category: DiagnosticCategory, key: string, message: string, reportsUnnecessary?: {}, elidedInCompatabilityPyramid?: boolean): DiagnosticMessage {\r\n" +
" return { code, category, key, message, reportsUnnecessary, elidedInCompatabilityPyramid };\r\n" +
" }\r\n" +
" export const Diagnostics = {\r\n";
messageTable.forEach(({ code, category, reportsUnnecessary, elidedInCompatabilityPyramid }, name) => {
const propName = convertPropertyName(name);
const argReportsUnnecessary = reportsUnnecessary ? `, /*reportsUnnecessary*/ ${reportsUnnecessary}` : "";
const argElidedInCompatabilityPyramid = elidedInCompatabilityPyramid ? `${!reportsUnnecessary ? ", /*reportsUnnecessary*/ undefined" : ""}, /*elidedInCompatabilityPyramid*/ ${elidedInCompatabilityPyramid}` : "";
result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}${argReportsUnnecessary}${argElidedInCompatabilityPyramid}),\r\n`;
});
2014-07-13 03:04:16 +04:00
result += " };\r\n}";
2014-07-13 03:04:16 +04:00
return result;
}
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable): string {
let result = "{";
messageTable.forEach(({ code }, name) => {
const propName = convertPropertyName(name);
result += `\r\n "${createKey(propName, code)}" : "${name.replace(/[\"]/g, '\\"')}",`;
});
// Shave trailing comma, then add newline and ending brace
result = result.slice(0, result.length - 1) + "\r\n}";
// Assert that we generated valid JSON
JSON.parse(result);
return result;
}
function createKey(name: string, code: number): string {
return name.slice(0, 100) + "_" + code;
}
2014-07-13 03:04:16 +04:00
function convertPropertyName(origName: string): string {
let result = origName.split("").map(char => {
if (char === "*") { return "_Asterisk"; }
if (char === "/") { return "_Slash"; }
if (char === ":") { return "_Colon"; }
2014-07-13 03:04:16 +04:00
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");
2014-07-13 03:04:16 +04:00
// get rid of all trailing underscores.
result = result.replace(/_$/, "");
return result;
}
main();