Skip to content

Commit 0a0653e

Browse files
author
Andy Hanson
committed
Merge branch 'master' into undefinedzilla
2 parents 32d0421 + 1541599 commit 0a0653e

36 files changed

+1379
-949
lines changed

package-lock.json

Lines changed: 670 additions & 892 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,12 @@
4848
"@types/q": "latest",
4949
"@types/run-sequence": "latest",
5050
"@types/through2": "latest",
51+
"@types/travis-fold": "latest",
5152
"@types/xml2js": "^0.4.0",
52-
"xml2js": "^0.4.19",
5353
"browser-resolve": "^1.11.2",
5454
"browserify": "latest",
5555
"chai": "latest",
56+
"chalk": "latest",
5657
"convert-source-map": "latest",
5758
"del": "latest",
5859
"gulp": "3.X",
@@ -77,9 +78,9 @@
7778
"through2": "latest",
7879
"travis-fold": "latest",
7980
"tslint": "latest",
81+
"typescript": "next",
8082
"vinyl": "latest",
81-
"chalk": "latest",
82-
"typescript": "next"
83+
"xml2js": "^0.4.19"
8384
},
8485
"scripts": {
8586
"pretest": "jake tests",

scripts/types/ambient.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,3 @@ declare module "gulp-insert" {
1414
}
1515

1616
declare module "sorcery";
17-
declare module "travis-fold";

src/compiler/checker.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4443,7 +4443,7 @@ namespace ts {
44434443
const special = getSpecialPropertyAssignmentKind(expression);
44444444
if (special === SpecialPropertyAssignmentKind.ThisProperty) {
44454445
const thisContainer = getThisContainer(expression, /*includeArrowFunctions*/ false);
4446-
// Properties defined in a constructor (or javascript constructor function) don't get undefined added.
4446+
// Properties defined in a constructor (or base constructor, or javascript constructor function) don't get undefined added.
44474447
// Function expressions that are assigned to the prototype count as methods.
44484448
declarationInConstructor = thisContainer.kind === SyntaxKind.Constructor ||
44494449
thisContainer.kind === SyntaxKind.FunctionDeclaration ||
@@ -4513,8 +4513,15 @@ namespace ts {
45134513
}
45144514
let type = jsDocType;
45154515
if (!type) {
4516-
// use only the constructor types unless only null | undefined (including widening variants) were assigned there
4517-
const sourceTypes = constructorTypes && constructorTypes.some(t => !!(t.flags & ~(TypeFlags.Nullable | TypeFlags.ContainsWideningType))) ? constructorTypes : types;
4516+
// use only the constructor types unless they were only assigned null | undefined (including widening variants)
4517+
if (definedInMethod) {
4518+
const propType = getTypeOfSpecialPropertyOfBaseType(symbol);
4519+
if (propType) {
4520+
(constructorTypes || (constructorTypes = [])).push(propType);
4521+
definedInConstructor = true;
4522+
}
4523+
}
4524+
const sourceTypes = some(constructorTypes, t => !!(t.flags & ~(TypeFlags.Nullable | TypeFlags.ContainsWideningType))) ? constructorTypes! : types; // TODO: GH#18217
45184525
type = getUnionType(sourceTypes, UnionReduction.Subtype);
45194526
}
45204527
const widened = getWidenedType(addOptionality(type, definedInMethod && !definedInConstructor));
@@ -4527,6 +4534,20 @@ namespace ts {
45274534
return widened;
45284535
}
45294536

4537+
/** check for definition in base class if any declaration is in a class */
4538+
function getTypeOfSpecialPropertyOfBaseType(specialProperty: Symbol) {
4539+
const parentDeclaration = forEach(specialProperty.declarations, d => {
4540+
const parent = getThisContainer(d, /*includeArrowFunctions*/ false).parent;
4541+
return isClassLike(parent) && parent;
4542+
});
4543+
if (parentDeclaration) {
4544+
const classType = getDeclaredTypeOfSymbol(getSymbolOfNode(parentDeclaration)!) as InterfaceType;
4545+
const baseClassType = classType && getBaseTypes(classType)[0];
4546+
if (baseClassType) {
4547+
return getTypeOfPropertyOfType(baseClassType, specialProperty.escapedName);
4548+
}
4549+
}
4550+
}
45304551

45314552
// Return the type implied by a binding pattern element. This is the type of the initializer of the element if
45324553
// one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding
@@ -7316,7 +7337,8 @@ namespace ts {
73167337
}
73177338

73187339
function getConstraintDeclaration(type: TypeParameter) {
7319-
return type.symbol && getDeclarationOfKind<TypeParameterDeclaration>(type.symbol, SyntaxKind.TypeParameter)!.constraint;
7340+
const decl = type.symbol && getDeclarationOfKind<TypeParameterDeclaration>(type.symbol, SyntaxKind.TypeParameter);
7341+
return decl && decl.constraint;
73207342
}
73217343

73227344
function getInferredTypeParameterConstraint(typeParameter: TypeParameter) {

src/compiler/utilities.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4038,12 +4038,14 @@ namespace ts {
40384038
}
40394039

40404040
/** Add a value to a set, and return true if it wasn't already present. */
4041-
export function addToSeen(seen: Map<true>, key: string | number): boolean {
4041+
export function addToSeen(seen: Map<true>, key: string | number): boolean;
4042+
export function addToSeen<T>(seen: Map<T>, key: string | number, value: T): boolean;
4043+
export function addToSeen<T>(seen: Map<T>, key: string | number, value: T = true as any): boolean {
40424044
key = String(key);
40434045
if (seen.has(key)) {
40444046
return false;
40454047
}
4046-
seen.set(key, true);
4048+
seen.set(key, value);
40474049
return true;
40484050
}
40494051

src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,9 @@
899899
<Item ItemId=";Add_0_to_unresolved_variable_90008" ItemType="0" PsrId="306" Leaf="true">
900900
<Str Cat="Text">
901901
<Val><![CDATA[Add '{0}.' to unresolved variable]]></Val>
902+
<Tgt Cat="Text" Stat="Loc" Orig="New">
903+
<Val><![CDATA[Çözümlenmemiş değişkene '{0}.' ekle]]></Val>
904+
</Tgt>
902905
</Str>
903906
<Disp Icon="Str" />
904907
</Item>
@@ -1001,6 +1004,9 @@
10011004
<Item ItemId=";Add_qualifier_to_all_unresolved_variables_matching_a_member_name_95037" ItemType="0" PsrId="306" Leaf="true">
10021005
<Str Cat="Text">
10031006
<Val><![CDATA[Add qualifier to all unresolved variables matching a member name]]></Val>
1007+
<Tgt Cat="Text" Stat="Loc" Orig="New">
1008+
<Val><![CDATA[Bir üye adıyla eşleşen tüm çözülmemiş değişkenlere niteleyici ekle]]></Val>
1009+
</Tgt>
10041010
</Str>
10051011
<Disp Icon="Str" />
10061012
</Item>
@@ -6491,6 +6497,12 @@
64916497
</Str>
64926498
<Disp Icon="Str" />
64936499
</Item>
6500+
<Item ItemId=";Resolve_keyof_to_string_valued_property_names_only_no_numbers_or_symbols_6195" ItemType="0" PsrId="306" Leaf="true">
6501+
<Str Cat="Text">
6502+
<Val><![CDATA[Resolve 'keyof' to string valued property names only (no numbers or symbols).]]></Val>
6503+
</Str>
6504+
<Disp Icon="Str" />
6505+
</Item>
64946506
<Item ItemId=";Resolving_from_node_modules_folder_6118" ItemType="0" PsrId="306" Leaf="true">
64956507
<Str Cat="Text">
64966508
<Val><![CDATA[Resolving from node_modules folder...]]></Val>
@@ -8741,6 +8753,12 @@
87418753
</Str>
87428754
<Disp Icon="Str" />
87438755
</Item>
8756+
<Item ItemId=";_0_is_declared_but_never_used_6196" ItemType="0" PsrId="306" Leaf="true">
8757+
<Str Cat="Text">
8758+
<Val><![CDATA['{0}' is declared but never used.]]></Val>
8759+
</Str>
8760+
<Disp Icon="Str" />
8761+
</Item>
87448762
<Item ItemId=";_0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2_17012" ItemType="0" PsrId="306" Leaf="true">
87458763
<Str Cat="Text">
87468764
<Val><![CDATA['{0}' is not a valid meta-property for keyword '{1}'. Did you mean '{2}'?]]></Val>

src/services/codefixes/importFixes.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,21 @@ namespace ts.codefix {
9898
symbolToken: Node | undefined,
9999
preferences: UserPreferences,
100100
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
101-
const exportInfos = getAllReExportingModules(exportedSymbol, symbolName, checker, allSourceFiles);
101+
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, checker, allSourceFiles);
102102
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol));
103103
// We sort the best codefixes first, so taking `first` is best for completions.
104104
const moduleSpecifier = first(getNewImportInfos(program, sourceFile, exportInfos, compilerOptions, getCanonicalFileName, host, preferences)).moduleSpecifier;
105105
const ctx: ImportCodeFixContext = { host, program, checker, compilerOptions, sourceFile, formatContext, symbolName, getCanonicalFileName, symbolToken, preferences };
106106
return { moduleSpecifier, codeAction: first(getCodeActionsForImport(exportInfos, ctx)) };
107107
}
108-
function getAllReExportingModules(exportedSymbol: Symbol, symbolName: string, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
108+
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
109109
const result: SymbolExportInfo[] = [];
110-
forEachExternalModule(checker, allSourceFiles, moduleSymbol => {
110+
forEachExternalModule(checker, allSourceFiles, (moduleSymbol, moduleFile) => {
111+
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
112+
if (moduleFile && moduleSymbol !== exportingModuleSymbol && startsWith(sourceFile.fileName, getDirectoryPath(moduleFile.fileName))) {
113+
return;
114+
}
115+
111116
for (const exported of checker.getExportsOfModule(moduleSymbol)) {
112117
if (exported.escapedName === InternalSymbolName.Default || exported.name === symbolName && skipAlias(exported, checker) === exportedSymbol) {
113118
const isDefaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol) === exported;

src/services/textChanges.ts

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,7 @@ namespace ts.textChanges {
212212
export class ChangeTracker {
213213
private readonly changes: Change[] = [];
214214
private readonly deletedNodesInLists: true[] = []; // Stores ids of nodes in lists that we already deleted. Used to avoid deleting `, ` twice in `a, b`.
215-
// Map from class id to nodes to insert at the start
216-
private readonly nodesInsertedAtClassStarts = createMap<{ sourceFile: SourceFile, cls: ClassLikeDeclaration, members: ClassElement[] }>();
215+
private readonly classesWithNodesInsertedAtStart = createMap<ClassDeclaration>(); // Set<ClassDeclaration> implemented as Map<node id, ClassDeclaration>
217216

218217
public static fromContext(context: TextChangesContext): ChangeTracker {
219218
return new ChangeTracker(getNewLineOrDefaultFromHost(context.host, context.formatContext.options), context.formatContext);
@@ -343,8 +342,7 @@ namespace ts.textChanges {
343342
}
344343

345344
public insertNodeBefore(sourceFile: SourceFile, before: Node, newNode: Node, blankLineBetween = false) {
346-
const pos = getAdjustedStartPosition(sourceFile, before, {}, Position.Start);
347-
return this.replaceRange(sourceFile, { pos, end: pos }, newNode, this.getOptionsForInsertNodeBefore(before, blankLineBetween));
345+
this.insertNodeAt(sourceFile, getAdjustedStartPosition(sourceFile, before, {}, Position.Start), newNode, this.getOptionsForInsertNodeBefore(before, blankLineBetween));
348346
}
349347

350348
public insertModifierBefore(sourceFile: SourceFile, modifier: SyntaxKind, before: Node): void {
@@ -443,21 +441,20 @@ namespace ts.textChanges {
443441
}
444442

445443
public insertNodeAtClassStart(sourceFile: SourceFile, cls: ClassLikeDeclaration, newElement: ClassElement): void {
446-
const firstMember = firstOrUndefined(cls.members);
447-
if (!firstMember) {
448-
const id = getNodeId(cls).toString();
449-
const newMembers = this.nodesInsertedAtClassStarts.get(id);
450-
if (newMembers) {
451-
Debug.assert(newMembers.sourceFile === sourceFile && newMembers.cls === cls);
452-
newMembers.members.push(newElement);
444+
const clsStart = cls.getStart(sourceFile);
445+
let prefix = "";
446+
let suffix = this.newLineCharacter;
447+
if (addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(cls), cls)) {
448+
prefix = this.newLineCharacter;
449+
// For `class C {\n}`, don't add the trailing "\n"
450+
if (cls.members.length === 0 && !(positionsAreOnSameLine as any)(...getClassBraceEnds(cls, sourceFile), sourceFile)) { // TODO: GH#4130 remove 'as any'
451+
suffix = "";
453452
}
454-
else {
455-
this.nodesInsertedAtClassStarts.set(id, { sourceFile, cls, members: [newElement] });
456-
}
457-
}
458-
else {
459-
this.insertNodeBefore(sourceFile, firstMember, newElement);
460453
}
454+
455+
const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(clsStart, sourceFile), clsStart, sourceFile, this.formatContext.options)
456+
+ this.formatContext.options.indentSize!;
457+
this.insertNodeAt(sourceFile, cls.members.pos, newElement, { indentation, prefix, suffix });
461458
}
462459

463460
public insertNodeAfter(sourceFile: SourceFile, after: Node, newNode: Node): this {
@@ -638,12 +635,14 @@ namespace ts.textChanges {
638635
return this;
639636
}
640637

641-
private finishInsertNodeAtClassStart(): void {
642-
this.nodesInsertedAtClassStarts.forEach(({ sourceFile, cls, members }) => {
643-
const newCls = cls.kind === SyntaxKind.ClassDeclaration
644-
? updateClassDeclaration(cls, cls.decorators, cls.modifiers, cls.name, cls.typeParameters, cls.heritageClauses, members)
645-
: updateClassExpression(cls, cls.modifiers, cls.name, cls.typeParameters, cls.heritageClauses, members);
646-
this.replaceNode(sourceFile, cls, newCls);
638+
private finishClassesWithNodesInsertedAtStart(): void {
639+
this.classesWithNodesInsertedAtStart.forEach(cls => {
640+
const sourceFile = cls.getSourceFile();
641+
const [openBraceEnd, closeBraceEnd] = getClassBraceEnds(cls, sourceFile);
642+
// For `class C { }` remove the whitespace inside the braces.
643+
if (positionsAreOnSameLine(openBraceEnd, closeBraceEnd, sourceFile) && openBraceEnd !== closeBraceEnd - 1) {
644+
this.deleteRange(sourceFile, createTextRange(openBraceEnd, closeBraceEnd - 1));
645+
}
647646
});
648647
}
649648

@@ -654,11 +653,15 @@ namespace ts.textChanges {
654653
* so we can only call this once and can't get the non-formatted text separately.
655654
*/
656655
public getChanges(validate?: ValidateNonFormattedText): FileTextChanges[] {
657-
this.finishInsertNodeAtClassStart();
656+
this.finishClassesWithNodesInsertedAtStart();
658657
return changesToText.getTextChangesFromChanges(this.changes, this.newLineCharacter, this.formatContext, validate);
659658
}
660659
}
661660

661+
function getClassBraceEnds(cls: ClassLikeDeclaration, sourceFile: SourceFile): [number, number] {
662+
return [findChildOfKind(cls, SyntaxKind.OpenBraceToken, sourceFile)!.end, findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile)!.end];
663+
}
664+
662665
export type ValidateNonFormattedText = (node: Node, text: string) => void;
663666

664667
namespace changesToText {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=== tests/cases/conformance/salsa/a.js ===
2+
class Base {
3+
>Base : Symbol(Base, Decl(a.js, 0, 0))
4+
5+
constructor() {
6+
this.p = 1
7+
>this.p : Symbol(Base.p, Decl(a.js, 1, 19))
8+
>this : Symbol(Base, Decl(a.js, 0, 0))
9+
>p : Symbol(Base.p, Decl(a.js, 1, 19))
10+
}
11+
}
12+
class Derived extends Base {
13+
>Derived : Symbol(Derived, Decl(a.js, 4, 1))
14+
>Base : Symbol(Base, Decl(a.js, 0, 0))
15+
16+
m() {
17+
>m : Symbol(Derived.m, Decl(a.js, 5, 28))
18+
19+
this.p = 1
20+
>this.p : Symbol(Derived.p, Decl(a.js, 6, 9))
21+
>this : Symbol(Derived, Decl(a.js, 4, 1))
22+
>p : Symbol(Derived.p, Decl(a.js, 6, 9))
23+
}
24+
}
25+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
=== tests/cases/conformance/salsa/a.js ===
2+
class Base {
3+
>Base : Base
4+
5+
constructor() {
6+
this.p = 1
7+
>this.p = 1 : 1
8+
>this.p : number
9+
>this : this
10+
>p : number
11+
>1 : 1
12+
}
13+
}
14+
class Derived extends Base {
15+
>Derived : Derived
16+
>Base : Base
17+
18+
m() {
19+
>m : () => void
20+
21+
this.p = 1
22+
>this.p = 1 : 1
23+
>this.p : number
24+
>this : this
25+
>p : number
26+
>1 : 1
27+
}
28+
}
29+

0 commit comments

Comments
 (0)