diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000000..03c21f2cf91 --- /dev/null +++ b/.mailmap @@ -0,0 +1,145 @@ + +Alexander # Alexander Kuvaev +AbubakerB # Abubaker Bashir +Adam Freidin Adam Freidin +Adi Dahiya Adi Dahiya +Ahmad Farid ahmad-farid +Alex Eagle +Anders Hejlsberg unknown unknown +Andrew Z Allen +Andy Hanson Andy +Anil Anar +Anton Tolmachev +Arnavion # Arnav Singh +Arthur Ozga Arthur Ozga +Asad Saeeduddin +Schmavery # Avery Morin +Basarat Ali Syed Basarat Syed basarat +Bill Ticehurst Bill Ticehurst +Ben Duffield +Blake Embrey +Bowden Kelly +Brett Mayen +Bryan Forbes +Caitlin Potter +ChrisBubernak unknown # Chris Bubernak +Chuck Jazdzewski +Colby Russell +Colin Snover +Cyrus Najmabadi CyrusNajmabadi unknown +Dan Corder +Dan Quirk Dan Quirk nknown +Daniel Rosenwasser Daniel Rosenwasser Daniel Rosenwasser Daniel Rosenwasser Daniel Rosenwasser +David Li +David Souther +Denis Nedelyaev +Dick van den Brink unknown unknown +Dirk Baeumer Dirk Bäumer # Dirk Bäumer +Dirk Holtwick +Doug Ilijev +Erik Edrosa +Ethan Rubio +Evan Martin +Evan Sebastian +Eyas # Eyas Sharaiha +falsandtru # @falsandtru +Frank Wallis +František Žiačik František Žiačik +Gabriel Isenberg +Gilad Peleg +Graeme Wicksted +Guillaume Salles +Guy Bedford guybedford +Harald Niesche +Iain Monro +Ingvar Stepanyan +impinball # Isiah Meadows +Ivo Gabe de Wolff +James Whitney +Jason Freeman Jason Freeman +Jason Killian +Jason Ramsay jramsay +Jed Mao +Jeffrey Morlan +tobisek # Jiri Tobisek +Johannes Rieken +John Vilk +jbondc jbondc jbondc # Jonathan Bond-Caron +Jonathan Park +Jonathan Turner Jonathan Turner +Jonathan Toland +Jesse Schalken +Josh Kalderimis +Josh Soref +Juan Luis Boya García +Julian Williams +Herrington Darkholme +Kagami Sascha Rosylight SaschaNaz +Kanchalai Tanglertsampan Yui +Kanchalai Tanglertsampan Yui T +Kanchalai Tanglertsampan Yui +Kanchalai Tanglertsampan Yui +Kanchalai Tanglertsampan yui T +Keith Mashinter kmashint +Ken Howard +kimamula # Kenji Imamula +Kyle Kelley +Lorant Pinter +Lucien Greathouse +Martin Vseticka Martin Všeticka MartyIX +vvakame # Masahiro Wakame +Matt McCutchen +Max Deepfield +Micah Zoltu +Mohamed Hegazy +Nathan Shively-Sanders +Nathan Yee +Nima Zahedi +Noj Vek +mihailik # Oleg Mihailik +Oleksandr Chekhovskyi +Paul van Brenk Paul van Brenk unknown unknown unknown +Oskar Segersva¨rd +pcan # Piero Cangianiello +pcbro <2bux89+dk3zspjmuh16o@sharklasers.com> # @pcbro +Pedro Maltez # Pedro Maltez +piloopin # @piloopin +milkisevil # Philip Bulley +progre # @progre +Prayag Verma +Punya Biswal +Rado Kirov +Ron Buckton Ron Buckton +Richard Knoll Richard Knoll +Rowan Wyborn +Ryan Cavanaugh Ryan Cavanaugh Ryan Cavanaugh +Ryohei Ikegami +Sarangan Rajamanickam +Sébastien Arod +Sheetal Nandi +Shengping Zhong +shyyko.serhiy@gmail.com # Shyyko Serhiy +Simon Hürlimann +Solal Pirelli +Stan Thomas +Stanislav Sysoev +Steve Lucco steveluc +Tarik # Tarik Ozket +Tien Nguyen tien unknown #Tien Hoanhtien +Tim Perry +Tim Viiding-Spader +Tingan Ho +togru # togru +Tomas Grubliauskas +ToddThomson # Todd Thomson +TruongSinh Tran-Nguyen +vilicvane # Vilic Vane +Vladimir Matveev vladima v2m +Wesley Wigham Wesley Wigham +York Yao york yao yaoyao +Yuichi Nukiyama YuichiNukiyama +Zev Spitz +Zhengbo Li zhengbli Zhengbo Li Zhengbo Li tinza123 unknown Zhengbo Li +zhongsp # Patrick Zhong +T18970237136 # @T18970237136 +JBerger \ No newline at end of file diff --git a/AUTHORS.md b/AUTHORS.md index 0501514d758..08039127d9d 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,105 +1,141 @@ TypeScript is authored by: - +* Abubaker Bashir * Adam Freidin -* Ahmad Farid -* Akshar Patel +* Adi Dahiya +* Ahmad Farid +* Alex Eagle +* Alexander Kuvaev * Anders Hejlsberg +* Andrew Z Allen +* Andy Hanson +* Anil Anar +* Anton Tolmachev * Arnav Singh * Arthur Ozga * Asad Saeeduddin -* Basarat Ali Syed +* Avery Morin +* Basarat Ali Syed * Ben Duffield -* Bill Ticehurst +* Bill Ticehurst +* Blake Embrey +* Bowden Kelly * Brett Mayen -* Bryan Forbes -* Caitlin Potter +* Bryan Forbes +* Caitlin Potter * Chris Bubernak -* Colby Russell +* Chuck Jazdzewski +* Colby Russell * Colin Snover * Cyrus Najmabadi * Dan Corder -* Dan Quirk +* Dan Quirk * Daniel Rosenwasser -* @dashaus -* David Li +* David Li +* David Souther * Denis Nedelyaev * Dick van den Brink * Dirk Bäumer * Dirk Holtwick +* Doug Ilijev +* Erik Edrosa +* Ethan Rubio +* Evan Martin +* Evan Sebastian * Eyas Sharaiha * @falsandtru -* Frank Wallis +* Frank Wallis +* František Žiačik * Gabriel Isenberg -* Gilad Peleg +* Gilad Peleg * Graeme Wicksted -* Guillaume Salles +* Guillaume Salles * Guy Bedford * Harald Niesche +* Herrington Darkholme * Iain Monro * Ingvar Stepanyan -* Ivo Gabe de Wolff -* James Whitney +* Isiah Meadows +* Ivo Gabe de Wolff +* James Whitney * Jason Freeman * Jason Killian -* Jason Ramsay +* Jason Ramsay +* JBerger * Jed Mao * Jeffrey Morlan -* Johannes Rieken +* Jesse Schalken +* Jiri Tobisek +* Johannes Rieken * John Vilk * Jonathan Bond-Caron * Jonathan Park +* Jonathan Toland * Jonathan Turner -* Jonathon Smith * Josh Kalderimis +* Josh Soref +* Juan Luis Boya García * Julian Williams * Kagami Sascha Rosylight +* Kanchalai Tanglertsampan * Keith Mashinter * Ken Howard * Kenji Imamula -* Lorant Pinter +* Kyle Kelley +* Lorant Pinter * Lucien Greathouse -* Martin Všetička +* Martin Vseticka * Masahiro Wakame -* Mattias Buelens +* Matt McCutchen * Max Deepfield -* Micah Zoltu -* Mohamed Hegazy +* Micah Zoltu +* Mohamed Hegazy * Nathan Shively-Sanders * Nathan Yee +* Nima Zahedi +* Noj Vek * Oleg Mihailik -* Oleksandr Chekhovskyi -* Paul van Brenk +* Oleksandr Chekhovskyi +* Oskar Segersva¨rd +* Patrick Zhong +* Paul van Brenk * @pcbro -* Pedro Maltez +* Pedro Maltez * Philip Bulley -* piloopin +* Piero Cangianiello +* @piloopin +* Prayag Verma * @progre * Punya Biswal -* Richard Sentino -* Ron Buckton +* Rado Kirov +* Richard Knoll +* Ron Buckton * Rowan Wyborn -* Ryan Cavanaugh +* Ryan Cavanaugh * Ryohei Ikegami -* Sébastien Arod +* Sarangan Rajamanickam * Sheetal Nandi * Shengping Zhong * Shyyko Serhiy * Simon Hürlimann * Solal Pirelli * Stan Thomas +* Stanislav Sysoev * Steve Lucco -* Thomas Loubiou +* Sébastien Arod +* @T18970237136 +* Tarik Ozket * Tien Hoanhtien * Tim Perry +* Tim Viiding-Spader * Tingan Ho +* Todd Thomson * togru * Tomas Grubliauskas * TruongSinh Tran-Nguyen -* Viliv Vane +* Vilic Vane * Vladimir Matveev * Wesley Wigham * York Yao -* Yui Tanglertsampan * Yuichi Nukiyama -* Zev Spitz -* Zhengbo Li +* Zev Spitz +* Zhengbo Li \ No newline at end of file diff --git a/scripts/authors.ts b/scripts/authors.ts new file mode 100644 index 00000000000..fd9d27acd00 --- /dev/null +++ b/scripts/authors.ts @@ -0,0 +1,182 @@ +import fs = require('fs'); +import path = require('path'); +import child_process = require("child_process"); + +type Author = { + displayNames: string[]; + preferedName?: string; + emails: string[]; +}; + +type AuthorMap = { [s: string]: Author }; + +type Command = { + (...arg: string[]): void; + description?: string; +}; + +const mailMapPath = path.resolve("../.mailmap"); +const authorsPath = path.resolve("../AUTHORS.md"); + +function getKnownAuthors(): Author[] { + const segmentRegExp = /\s?([^<]+)\s+<([^>]+)>/g; + const preferedNameRegeExp = /\s?#\s?([^#]+)$/; + const knownAuthors: Author[] = []; + + if (!fs.existsSync(mailMapPath)) { + throw new Error(`Could not load known users form .mailmap file at: ${mailMapPath}`); + } + + const mailMap = fs.readFileSync(mailMapPath).toString(); + + for (const line of mailMap.split("\r\n")) { + const author: Author = { displayNames: [], emails: [] }; + let match: RegExpMatchArray | null; + + while (match = segmentRegExp.exec(line)) { + author.displayNames.push(match[1]); + author.emails.push(match[2]); + } + if (match = preferedNameRegeExp.exec(line)) { + author.preferedName = match[1]; + } + if (!author.emails) continue; + knownAuthors.push(author); + if (line.indexOf("#") > 0 && !author.preferedName) { + throw new Error("Could not match prefered name for: " + line); + } + // console.log("===> line: " + line); + // console.log(JSON.stringify(author, undefined, 2)); + } + return knownAuthors; +} + +function getAuthorName(author: Author) { + return author.preferedName || author.displayNames[0]; +} + +function getKnownAuthorMaps() { + const knownAuthors = getKnownAuthors(); + const authorsByName: AuthorMap = {}; + const authorsByEmail: AuthorMap = {}; + knownAuthors.forEach(author => { + author.displayNames.forEach(n => authorsByName[n] = author); + author.emails.forEach(e => authorsByEmail[e.toLocaleLowerCase()] = author); + }); + return { + knownAuthors, + authorsByName, + authorsByEmail + }; +} + +function deduplicate(array: T[]): T[] { + let result: T[] = [] + if (array) { + for (const item of array) { + if (result.indexOf(item) < 0) { + result.push(item); + } + } + } + return result; +} + +function log(s: string) { + console.log(` ${s}`); +} + +function sortAuthors(a: string, b: string) { + if (a.charAt(0) === "@") a = a.substr(1); + if (b.charAt(0) === "@") b = b.substr(1); + if (a.toLocaleLowerCase() < b.toLocaleLowerCase()) { + return -1; + } + else { + return 1; + } +} + +namespace Commands { + export const writeAuthors: Command = function () { + const output = deduplicate(getKnownAuthors().map(getAuthorName).filter(a => !!a)).sort(sortAuthors).join("\r\n* "); + fs.writeFileSync(authorsPath, "TypeScript is authored by:\r\n* " + output); + }; + writeAuthors.description = "Write known authors to AUTHORS.md file."; + + export const listKnownAuthors: Command = function () { + deduplicate(getKnownAuthors().map(getAuthorName)).filter(a => !!a).sort(sortAuthors).forEach(log); + }; + listKnownAuthors.description = "List known authors as listed in .mailmap file."; + + export const listAuthors: Command = function (...specs:string[]) { + const cmd = "git shortlog -se " + specs.join(" "); + console.log(cmd); + const outputRegExp = /\d+\s+([^<]+)<([^>]+)>/; + const tty = process.platform === 'win32' ? 'CON' : '/dev/tty'; + const authors: { name: string, email: string, knownAuthor?: Author }[] = []; + child_process.exec(`${cmd} < ${tty}`, { cwd: path.resolve("../") }, function (error, stdout, stderr) { + if (error) { + console.log(stderr.toString()); + } + else { + const output = stdout.toString(); + const lines = output.split("\n"); + lines.forEach(line => { + if (line) { + let match: RegExpExecArray | null; + if (match = outputRegExp.exec(line)) { + authors.push({ name: match[1], email: match[2] }); + } + else { + throw new Error("Could not parse output: " + line); + } + } + }); + + const maps = getKnownAuthorMaps(); + + const lookupAuthor = function ({name, email}: { name: string, email: string }) { + return maps.authorsByEmail[email.toLocaleLowerCase()] || maps.authorsByName[name]; + }; + + const knownAuthors = authors + .map(lookupAuthor) + .filter(a => !!a) + .map(getAuthorName); + const unknownAuthors = authors + .filter(a => !lookupAuthor(a)) + .map(a => `${a.name} <${a.email}>`); + + if (knownAuthors.length) { + console.log("\r\n"); + console.log("Found known authors: "); + console.log("====================="); + deduplicate(knownAuthors).sort(sortAuthors).forEach(log); + } + + if (unknownAuthors.length) { + console.log("\r\n"); + console.log("Found unknown authors: "); + console.log("====================="); + deduplicate(unknownAuthors).sort(sortAuthors).forEach(log); + } + } + }); + }; + listAuthors.description = "List known and unknown authors for a given spec"; +} + +var args = process.argv.slice(2); +if (args.length < 1) { + console.log('Usage: node authors.js [command]'); + console.log('List of commands: '); + Object.keys(Commands).forEach(k => console.log(` ${k}: ${(Commands as any)[k]['description']}`)); +} else { + var cmd: Function = (Commands as any)[args[0]]; + if (cmd === undefined) { + console.log('Unknown command ' + args[1]); + } else { + cmd.apply(undefined, args.slice(1)); + } +}