TypeScript/scripts/processDiagnosticMessages.ts
2014-07-12 17:30:19 -07:00

182 lines
5.7 KiB
TypeScript

/// <reference path="../src/compiler/sys.ts" />
interface DiagnosticDetails {
category: string;
code: number;
}
interface InputDiagnosticMessageTable {
[msg: string]: DiagnosticDetails;
}
interface IIndexable<V> {
[key: string]: V;
}
function main(): void {
if (sys.args.length < 1) {
sys.write("Usage:" + sys.newLine)
sys.write("\tnode processDiagnosticMessages.js <diagnostic-json-input-file>" + sys.newLine);
return;
}
var inputFilePath = sys.args[0].replace(/\\/g, "/");
var inputStr = sys.readFile(inputFilePath);
var diagnosticMesages: InputDiagnosticMessageTable = JSON.parse(inputStr);
var names = Utilities.getObjectKeys(diagnosticMesages);
var nameMap = buildUniqueNameMap(names);
var infoFileOutput = buildInfoFileOutput(diagnosticMesages, nameMap);
// TODO: Fix path joining
var inputDirectory = inputFilePath.substr(0,inputFilePath.lastIndexOf("/"));
var fileOutputPath = inputDirectory + "/diagnosticInformationMap.generated.ts";
sys.writeFile(fileOutputPath, infoFileOutput);
}
function buildUniqueNameMap(names: string[]): IIndexable<string> {
var nameMap: IIndexable<string> = {};
var uniqueNames = NameGenerator.ensureUniqueness(names, /*isFixed */ undefined, /* isCaseSensitive */ false);
for (var i = 0; i < names.length; i++) {
nameMap[names[i]] = uniqueNames[i];
}
return nameMap;
}
function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, nameMap: IIndexable<string>): string {
var result =
'// <auto-generated />\r\n' +
'/// <reference path="types.ts" />\r\n' +
'module ts {\r\n' +
' export var Diagnostics = {\r\n';
var names = Utilities.getObjectKeys(messageTable);
for (var i = 0; i < names.length; i++) {
var name = names[i];
var diagnosticDetails = messageTable[name];
result +=
' ' + convertPropertyName(nameMap[name]) +
': { code: ' + diagnosticDetails.code +
', category: DiagnosticCategory.' + diagnosticDetails.category +
', key: "' + name.replace('"', '\\"') +
'" },\r\n';
}
result += ' };\r\n}';
return result;
}
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;
}
module NameGenerator {
export function ensureUniqueness(
names: string[],
isFixed: boolean[]= names.map(() => false),
isCaseSensitive: boolean = true): string[] {
var names = names.map(x => x);
ensureUniquenessInPlace(names, isFixed, isCaseSensitive);
return names;
}
function ensureUniquenessInPlace(names: string[], isFixed: boolean[], isCaseSensitive: boolean): void {
for (var i = 0; i < names.length; i++) {
var name = names[i];
var collisionIndices = Utilities.collectMatchingIndices(name, names, isCaseSensitive);
// We will always have one "collision" because getCollisionIndices returns the index of name itself as well;
// so if we only have one collision, then there are no issues.
if (collisionIndices.length < 2) {
continue;
}
handleCollisions(name, names, isFixed, collisionIndices, isCaseSensitive);
}
}
function handleCollisions(name: string, proposedNames: string[], isFixed: boolean[], collisionIndices: number[], isCaseSensitive: boolean): void {
var suffix = 1;
for (var i = 0; i < collisionIndices.length; i++) {
var collisionIndex = collisionIndices[i];
if (isFixed[collisionIndex]) {
// can't do anything about this name.
continue;
}
while (true) {
var newName = name + suffix++;
if (proposedNames.some((name) => Utilities.stringEquals(name, newName, isCaseSensitive))) {
proposedNames[collisionIndex] = newName;
break;
}
}
}
}
}
module Utilities {
/// Return a list of all indices where a string occurs.
export function collectMatchingIndices(name: string, proposedNames: string[], isCaseSensitive: boolean = true): number[] {
var matchingIndices: number[] = [];
for (var i = 0; i < proposedNames.length; i++) {
if (stringEquals(name, proposedNames[i], isCaseSensitive)) {
matchingIndices.push(i);
}
}
return matchingIndices;
}
export function stringEquals(s1: string, s2: string, caseSensitive: boolean = true): boolean {
if (!caseSensitive) {
s1 = s1.toLowerCase();
s2 = s2.toLowerCase();
}
return s1 == s2;
}
// Like Object.keys
export function getObjectKeys(obj: any): string[]{
var result: string[] = [];
for (var name in obj) {
if (obj.hasOwnProperty(name)) {
result.push(name);
}
}
return result;
}
}
main();