Skip to content

Commit 3c6c32b

Browse files
committed
Merge branch 'master' into projectReferenceInputDetection
2 parents 0d5aeee + 865b3e7 commit 3c6c32b

File tree

101 files changed

+3006
-228
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+3006
-228
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
"gulp-typescript": "latest",
7676
"istanbul": "latest",
7777
"jake": "latest",
78+
"lodash": "4.17.10",
7879
"merge2": "latest",
7980
"minimist": "latest",
8081
"mkdirp": "latest",

src/compiler/checker.ts

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,8 @@ namespace ts {
601601
FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
602602
UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy,
603603
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy,
604+
EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull),
605+
EmptyObjectFacts = All,
604606
}
605607

606608
const typeofEQFacts = createMapFromTemplate({
@@ -11836,8 +11838,12 @@ namespace ts {
1183611838
const simplified = getSimplifiedType((<IndexType>target).type);
1183711839
const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
1183811840
if (constraint) {
11839-
if (result = isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors)) {
11840-
return result;
11841+
// We require Ternary.True here such that circular constraints don't cause
11842+
// false positives. For example, given 'T extends { [K in keyof T]: string }',
11843+
// 'keyof T' has itself as its constraint and produces a Ternary.Maybe when
11844+
// related to other types.
11845+
if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors) === Ternary.True) {
11846+
return Ternary.True;
1184111847
}
1184211848
}
1184311849
}
@@ -14241,9 +14247,11 @@ namespace ts {
1424114247
(type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts;
1424214248
}
1424314249
if (flags & TypeFlags.Object) {
14244-
return isFunctionObjectType(<ObjectType>type) ?
14245-
strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
14246-
strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
14250+
return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(<ObjectType>type) ?
14251+
strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts :
14252+
isFunctionObjectType(<ObjectType>type) ?
14253+
strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
14254+
strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
1424714255
}
1424814256
if (flags & (TypeFlags.Void | TypeFlags.Undefined)) {
1424914257
return TypeFacts.UndefinedFacts;
@@ -15163,23 +15171,24 @@ namespace ts {
1516315171
return getTypeWithFacts(assumeTrue ? mapType(type, narrowTypeForTypeof) : type, facts);
1516415172

1516515173
function narrowTypeForTypeof(type: Type) {
15166-
if (assumeTrue && !(type.flags & TypeFlags.Union)) {
15167-
if (type.flags & TypeFlags.Unknown && literal.text === "object") {
15168-
return getUnionType([nonPrimitiveType, nullType]);
15169-
}
15170-
// We narrow a non-union type to an exact primitive type if the non-union type
15171-
// is a supertype of that primitive type. For example, type 'any' can be narrowed
15172-
// to one of the primitive types.
15173-
const targetType = literal.text === "function" ? globalFunctionType : typeofTypesByName.get(literal.text);
15174-
if (targetType) {
15175-
if (isTypeSubtypeOf(targetType, type)) {
15176-
return isTypeAny(type) ? targetType : getIntersectionType([type, targetType]); // Intersection to handle `string` being a subtype of `keyof T`
15177-
}
15178-
if (type.flags & TypeFlags.Instantiable) {
15179-
const constraint = getBaseConstraintOfType(type) || anyType;
15180-
if (isTypeSubtypeOf(targetType, constraint)) {
15181-
return getIntersectionType([type, targetType]);
15182-
}
15174+
if (type.flags & TypeFlags.Unknown && literal.text === "object") {
15175+
return getUnionType([nonPrimitiveType, nullType]);
15176+
}
15177+
// We narrow a non-union type to an exact primitive type if the non-union type
15178+
// is a supertype of that primitive type. For example, type 'any' can be narrowed
15179+
// to one of the primitive types.
15180+
const targetType = literal.text === "function" ? globalFunctionType : typeofTypesByName.get(literal.text);
15181+
if (targetType) {
15182+
if (isTypeSubtypeOf(type, targetType)) {
15183+
return type;
15184+
}
15185+
if (isTypeSubtypeOf(targetType, type)) {
15186+
return targetType;
15187+
}
15188+
if (type.flags & TypeFlags.Instantiable) {
15189+
const constraint = getBaseConstraintOfType(type) || anyType;
15190+
if (isTypeSubtypeOf(targetType, constraint)) {
15191+
return getIntersectionType([type, targetType]);
1518315192
}
1518415193
}
1518515194
}

src/compiler/core.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1409,9 +1409,12 @@ namespace ts {
14091409
/**
14101410
* Tests whether a value is string
14111411
*/
1412-
export function isString(text: any): text is string {
1412+
export function isString(text: unknown): text is string {
14131413
return typeof text === "string";
14141414
}
1415+
export function isNumber(x: unknown): x is number {
1416+
return typeof x === "number";
1417+
}
14151418

14161419
export function tryCast<TOut extends TIn, TIn = any>(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined;
14171420
export function tryCast<T>(value: T, test: (value: T) => boolean): T | undefined;
@@ -1534,6 +1537,7 @@ namespace ts {
15341537
* Every function should be assignable to this, but this should not be assignable to every function.
15351538
*/
15361539
export type AnyFunction = (...args: never[]) => void;
1540+
export type AnyConstructor = new (...args: unknown[]) => unknown;
15371541

15381542
export namespace Debug {
15391543
export let currentAssertionLevel = AssertionLevel.None;
@@ -2125,4 +2129,8 @@ namespace ts {
21252129
deleted(oldItems[oldIndex++]);
21262130
}
21272131
}
2132+
2133+
export function fill<T>(length: number, cb: (index: number) => T): T[] {
2134+
return new Array(length).fill(0).map((_, i) => cb(i));
2135+
}
21282136
}

src/compiler/diagnosticMessages.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4671,5 +4671,13 @@
46714671
"Convert all to async functions": {
46724672
"category": "Message",
46734673
"code": 95066
4674+
},
4675+
"Generate types for '{0}'": {
4676+
"category": "Message",
4677+
"code": 95067
4678+
},
4679+
"Generate types for all packages without types": {
4680+
"category": "Message",
4681+
"code": 95068
46744682
}
4675-
}
4683+
}

src/compiler/factory.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ namespace ts {
235235

236236
// Modifiers
237237

238-
export function createModifier<T extends Modifier["kind"]>(kind: T) {
238+
export function createModifier<T extends Modifier["kind"]>(kind: T): Token<T> {
239239
return createToken(kind);
240240
}
241241

src/compiler/inspectValue.ts

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
/* @internal */
2+
namespace ts {
3+
export interface InspectValueOptions {
4+
readonly fileNameToRequire: string;
5+
}
6+
7+
export const enum ValueKind { Const, Array, FunctionOrClass, Object }
8+
export interface ValueInfoBase {
9+
readonly name: string;
10+
}
11+
export type ValueInfo = ValueInfoSimple | ValueInfoArray | ValueInfoFunctionOrClass | ValueInfoObject;
12+
export interface ValueInfoSimple extends ValueInfoBase {
13+
readonly kind: ValueKind.Const;
14+
readonly typeName: string;
15+
readonly comment?: string | undefined;
16+
}
17+
export interface ValueInfoFunctionOrClass extends ValueInfoBase {
18+
readonly kind: ValueKind.FunctionOrClass;
19+
readonly source: string | number; // For a native function, this is the length.
20+
readonly prototypeMembers: ReadonlyArray<ValueInfo>;
21+
readonly namespaceMembers: ReadonlyArray<ValueInfo>;
22+
}
23+
export interface ValueInfoArray extends ValueInfoBase {
24+
readonly kind: ValueKind.Array;
25+
readonly inner: ValueInfo;
26+
}
27+
export interface ValueInfoObject extends ValueInfoBase {
28+
readonly kind: ValueKind.Object;
29+
readonly members: ReadonlyArray<ValueInfo>;
30+
}
31+
32+
export function inspectModule(fileNameToRequire: string): ValueInfo {
33+
return inspectValue(removeFileExtension(getBaseFileName(fileNameToRequire)), tryRequire(fileNameToRequire));
34+
}
35+
36+
export function inspectValue(name: string, value: unknown): ValueInfo {
37+
return getValueInfo(name, value, getRecurser());
38+
}
39+
40+
type Recurser = <T>(obj: unknown, name: string, cbOk: () => T, cbFail: (isCircularReference: boolean, keyStack: ReadonlyArray<string>) => T) => T;
41+
function getRecurser(): Recurser {
42+
const seen = new Set<unknown>();
43+
const nameStack: string[] = [];
44+
return (obj, name, cbOk, cbFail) => {
45+
if (seen.has(obj) || nameStack.length > 4) {
46+
return cbFail(seen.has(obj), nameStack);
47+
}
48+
49+
seen.add(obj);
50+
nameStack.push(name);
51+
const res = cbOk();
52+
nameStack.pop();
53+
seen.delete(obj);
54+
return res;
55+
};
56+
}
57+
58+
function getValueInfo(name: string, value: unknown, recurser: Recurser): ValueInfo {
59+
return recurser(value, name,
60+
(): ValueInfo => {
61+
if (typeof value === "function") return getFunctionOrClassInfo(value as AnyFunction, name, recurser);
62+
if (typeof value === "object") {
63+
const builtin = getBuiltinType(name, value as object, recurser);
64+
if (builtin !== undefined) return builtin;
65+
const entries = getEntriesOfObject(value as object);
66+
return { kind: ValueKind.Object, name, members: flatMap(entries, ({ key, value }) => getValueInfo(key, value, recurser)) };
67+
}
68+
return { kind: ValueKind.Const, name, typeName: isNullOrUndefined(value) ? "any" : typeof value };
69+
},
70+
(isCircularReference, keyStack) => anyValue(name, ` ${isCircularReference ? "Circular reference" : "Too-deep object hierarchy"} from ${keyStack.join(".")}`));
71+
}
72+
73+
function getFunctionOrClassInfo(fn: AnyFunction, name: string, recurser: Recurser): ValueInfoFunctionOrClass {
74+
const prototypeMembers = getPrototypeMembers(fn, recurser);
75+
const namespaceMembers = flatMap(getEntriesOfObject(fn), ({ key, value }) => getValueInfo(key, value, recurser));
76+
const toString = cast(Function.prototype.toString.call(fn), isString);
77+
const source = stringContains(toString, "{ [native code] }") ? getFunctionLength(fn) : toString;
78+
return { kind: ValueKind.FunctionOrClass, name, source, namespaceMembers, prototypeMembers };
79+
}
80+
81+
const builtins: () => ReadonlyMap<AnyConstructor> = memoize(() => {
82+
const map = createMap<AnyConstructor>();
83+
for (const { key, value } of getEntriesOfObject(global)) {
84+
if (typeof value === "function" && typeof value.prototype === "object" && value !== Object) {
85+
map.set(key, value as AnyConstructor);
86+
}
87+
}
88+
return map;
89+
});
90+
function getBuiltinType(name: string, value: object, recurser: Recurser): ValueInfo | undefined {
91+
return isArray(value)
92+
? { name, kind: ValueKind.Array, inner: value.length && getValueInfo("element", first(value), recurser) || anyValue(name) }
93+
: forEachEntry(builtins(), (builtin, builtinName): ValueInfo | undefined =>
94+
value instanceof builtin ? { kind: ValueKind.Const, name, typeName: builtinName } : undefined);
95+
}
96+
97+
function getPrototypeMembers(fn: AnyFunction, recurser: Recurser): ReadonlyArray<ValueInfo> {
98+
const prototype = fn.prototype as unknown;
99+
// tslint:disable-next-line no-unnecessary-type-assertion (TODO: update LKG and it will really be unnecessary)
100+
return typeof prototype !== "object" || prototype === null ? emptyArray : mapDefined(getEntriesOfObject(prototype as object), ({ key, value }) =>
101+
key === "constructor" ? undefined : getValueInfo(key, value, recurser));
102+
}
103+
104+
const ignoredProperties: ReadonlySet<string> = new Set(["arguments", "caller", "constructor", "eval", "super_"]);
105+
const reservedFunctionProperties: ReadonlySet<string> = new Set(Object.getOwnPropertyNames(noop));
106+
interface ObjectEntry { readonly key: string; readonly value: unknown; }
107+
function getEntriesOfObject(obj: object): ReadonlyArray<ObjectEntry> {
108+
const seen = createMap<true>();
109+
const entries: ObjectEntry[] = [];
110+
let chain = obj;
111+
while (!isNullOrUndefined(chain) && chain !== Object.prototype && chain !== Function.prototype) {
112+
for (const key of Object.getOwnPropertyNames(chain)) {
113+
if (!isJsPrivate(key) &&
114+
!ignoredProperties.has(key) &&
115+
(typeof obj !== "function" || !reservedFunctionProperties.has(key)) &&
116+
// Don't add property from a higher prototype if it already exists in a lower one
117+
addToSeen(seen, key)) {
118+
const value = safeGetPropertyOfObject(chain, key);
119+
// Don't repeat "toString" that matches signature from Object.prototype
120+
if (!(key === "toString" && typeof value === "function" && value.length === 0)) {
121+
entries.push({ key, value });
122+
}
123+
}
124+
}
125+
chain = Object.getPrototypeOf(chain);
126+
}
127+
return entries.sort((e1, e2) => compareStringsCaseSensitive(e1.key, e2.key));
128+
}
129+
130+
function getFunctionLength(fn: AnyFunction): number {
131+
return tryCast(safeGetPropertyOfObject(fn, "length"), isNumber) || 0;
132+
}
133+
134+
function safeGetPropertyOfObject(obj: object, key: string): unknown {
135+
const desc = Object.getOwnPropertyDescriptor(obj, key);
136+
return desc && desc.value;
137+
}
138+
139+
function isNullOrUndefined(value: unknown): value is null | undefined {
140+
return value == null; // tslint:disable-line
141+
}
142+
143+
function anyValue(name: string, comment?: string): ValueInfo {
144+
return { kind: ValueKind.Const, name, typeName: "any", comment };
145+
}
146+
147+
export function isJsPrivate(name: string): boolean {
148+
return name.startsWith("_");
149+
}
150+
151+
function tryRequire(fileNameToRequire: string): unknown {
152+
try {
153+
return require(fileNameToRequire);
154+
}
155+
catch {
156+
return undefined;
157+
}
158+
}
159+
}

src/compiler/moduleNameResolver.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -779,14 +779,23 @@ namespace ts {
779779
*/
780780
/* @internal */
781781
export function resolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
782-
const { resolvedModule, failedLookupLocations } =
783-
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
782+
const { resolvedModule, failedLookupLocations } = tryResolveJSModuleWorker(moduleName, initialDir, host);
784783
if (!resolvedModule) {
785784
throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`);
786785
}
787786
return resolvedModule.resolvedFileName;
788787
}
789788

789+
/* @internal */
790+
export function tryResolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string | undefined {
791+
const { resolvedModule } = tryResolveJSModuleWorker(moduleName, initialDir, host);
792+
return resolvedModule && resolvedModule.resolvedFileName;
793+
}
794+
795+
function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
796+
return nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
797+
}
798+
790799
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
791800
return nodeModuleNameResolverWorker(moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, /*jsOnly*/ false);
792801
}

0 commit comments

Comments
 (0)