/// interface DiagnosticDetails { category: string; code: number; isEarly?: boolean; } type InputDiagnosticMessageTable = ts.Map; function main(): void { var sys = ts.sys; if (sys.args.length < 1) { sys.write("Usage:" + sys.newLine) sys.write("\tnode processDiagnosticMessages.js " + sys.newLine); return; } function writeFile(fileName: string, contents: string) { // TODO: Fix path joining var inputDirectory = inputFilePath.substr(0,inputFilePath.lastIndexOf("/")); var fileOutputPath = inputDirectory + "/" + fileName; sys.writeFile(fileOutputPath, contents); } var inputFilePath = sys.args[0].replace(/\\/g, "/"); var inputStr = sys.readFile(inputFilePath); var diagnosticMessagesJson: { [key: string]: DiagnosticDetails } = JSON.parse(inputStr); // Check that there are no duplicates. const seenNames = ts.createMap(); for (const name of Object.keys(diagnosticMessagesJson)) { if (seenNames.has(name)) throw new Error(`Name ${name} appears twice`); seenNames.set(name, true); } const diagnosticMessages: InputDiagnosticMessageTable = ts.createMapFromTemplate(diagnosticMessagesJson); var infoFileOutput = buildInfoFileOutput(diagnosticMessages); checkForUniqueCodes(diagnosticMessages); writeFile("diagnosticInformationMap.generated.ts", infoFileOutput); var messageOutput = buildDiagnosticMessageOutput(diagnosticMessages); writeFile("diagnosticMessages.generated.json", messageOutput); } 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): string { var result = '// \r\n' + '/// \r\n' + '/* @internal */\r\n' + 'namespace ts {\r\n' + " function diag(code: number, category: DiagnosticCategory, key: string, message: string): DiagnosticMessage {\r\n" + " return { code, category, key, message };\r\n" + " }\r\n" + ' export const Diagnostics = {\r\n'; messageTable.forEach(({ code, category }, name) => { const propName = convertPropertyName(name); result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}),\r\n`; }); result += ' };\r\n}'; return result; } function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable): string { let result = '{'; let first = true; messageTable.forEach(({ code }, name) => { if (!first) { first = false; } else { result += ','; } const propName = convertPropertyName(name); result += `\r\n "${createKey(propName, code)}": "${name.replace(/[\"]/g, '\\"')}"`; }); result += '\r\n}'; return result; } function createKey(name: string, code: number) : string { return name.slice(0, 100) + '_' + code; } function convertPropertyName(origName: string): string { var 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();