Issue 1:
Problems

/// <reference path="..." /> comments (hereafter "reference directives") currently serve

multiple purposes:

Including another definition file containing global declarations

Including another definition file containing ambient module declarations

Including another implementation file

The current mechanism has some common shortcomings:

Relative paths to a common typings folder can be come unwieldy

There's no mechanism to "override" a reference path

Reference directives only ever look in one place to find a file.

This has resulted in multiple issue reports of people trying to address this:

#5893 Multiple source roots - or something like classpath, like python_path, like include_path

#4615 Support environment variables in reference paths

#6482 Support a 'declarationPath' option

New Use Case in Bundled Type Acquisition

An important scenario we need to address is the case where multiple typings

files need to refer to the same global set of types or namespaces. If these

libraries refer to multiple versions of the same global types, we have no

existing mechanism for resolving the conflict

Solution: Library include directive

Syntax

The proposed syntax (🚲 🏠 of course) would look like this

/// <reference library="jquery/jquery.d.ts" />

Behavior

This syntax means that the compiler should include the first file found

when searching the following paths, where relative paths are resolved relative

to the project root (either the location of tsconfig.json, or the common

root of all input files):

./typings/jquery/jquery.d.ts

./node_modules/jquery/jquery.d.ts

./node_modules/@types/jquery/jquery.d.ts

This search order provides the following desirable behavior:

When needed, the user can resolve a version conflict by placing a definitive

global version in the local typings folder

A bundled .d.ts file will be found automatically

A types package can fill in for libraries which don't have bundled definitions

We could conceivably allow for configuration of this search order in tsconfig.json if

needed for complex scenarios.

UMD

Additionally, when a UMD module definition is found, its global export declaration (if present)

is added to the global scope.

All-up World

Along with the rest of the typings acquisition story, we can now have a very coherent way to

explain how file references should be managed in TypeScript programs:

Modules which are part of your program are always imported using import

Modules which have definition files are always imported using import, and those imports should resolve to proper modules

Global definitions should always be located via /// <reference library = ... directives

File ordering for concatenated output is managed with /// <reference path = .... directives

Issue 2:
Background:

The build does a preprocessing step to build the Diagnostics map, which contains items naming tsc error codes and their corresponding human-readable messages. The generate-diagnostics target runs before the actual compilation step for tsc. It takes the diagnostic message from a JSON source and mangles it to create a suitable property name for the Diagnostics object.

For example, given the 1100 diagnostic ("Invalid use of '{0}' in strict mode."), we create Diagnostic.Invalid_use_of_0_in_strict_mode.

Because we're mangling these, processDiagnosticMessages.ts tries to go through some effort to avoid collisions in the generated property names. See ts.buildUniqueNameMap, ts.NameGenerator.handleCollisions, and others.

For example, when dealing with two hypothetical diagnostic messages "Found '{0}'" and "Found 0", we wouldn't want the name-mangling to produce colliding Found_0 keys for both messages.

Problem:

processDiagnosticMessages.ts does not succeed in its goal to properly deal with collisions.

Analysis and Cause:

During a visual audit of the code, before actually performing any tests against different inputs, I originally fingered the following line as problematic while eyeballing processDiagnosticMessages.ts:

nameMap[names[i]] = uniqueNames[i];

This is in the context of having just produced the uniqueNames from the orginal elements of names (where names actually contains elements whose values are the diagnostic messages). The use of the two arrays are inverted.

nameMap[uniqueNames[i]] = names[i];

(Again, names[i] is a bit of a misnomer. It actually contains the human-readable text of the diagnostic.)

However, this does not resolve the problem. We can process Example Input 1 (adapted from the example above) and it will produce identical Found_0 keys both before and after making the change above. There are actually several other problems in processDiagnosticMessages.ts wrt collision handling.

The use of buildUniqueNameMap actually happens before the name-mangling (convertPropertyName) occurs, so the only time we would ever encounter a collision is if the diagnostic messages are exactly the same (rather than their would-be mangled names being the same as in Example Input). But in fact, it's not even possible for the messages to be the same, because they come from a JSON source keyed off that message, so they're already guaranteed to be unique. (Side note: add build preconditions to make sure there are no duplicate messages in the source JSON?)

There's also a problem with the isFixed parameter in handleCollisions, but I will file a separate issue about that, for various reasons.

Example Input:

{
"Found '{0}'.": {
"category": "Error",
"code": 9999
},
"Found 0.": {
"category": "Error",
"code": 9998
}
}