Skip to content

Commit cf4f760

Browse files
author
Andy Hanson
committed
Merge branch 'master' into undefinedzilla
2 parents 1484c0a + c1128d6 commit cf4f760

20 files changed

+167
-97
lines changed

src/compiler/declarationEmitter.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,12 @@ namespace ts {
608608
"?");
609609
}
610610
write(": ");
611-
emitType(node.type!);
611+
if (node.type) {
612+
emitType(node.type);
613+
}
614+
else {
615+
write("any");
616+
}
612617
write(";");
613618
writeLine();
614619
decreaseIndent();

src/compiler/transformers/module/module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,7 +1728,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
17281728
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
17291729
result["default"] = mod;
17301730
return result;
1731-
}`
1731+
};`
17321732
};
17331733

17341734
// emit helper for `import Name from "foo"`
@@ -1738,6 +1738,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
17381738
text: `
17391739
var __importDefault = (this && this.__importDefault) || function (mod) {
17401740
return (mod && mod.__esModule) ? mod : { "default": mod };
1741-
}`
1741+
};`
17421742
};
17431743
}

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2473,7 +2473,7 @@ namespace ts {
24732473
*/
24742474
export interface SourceFileLike {
24752475
readonly text: string;
2476-
lineMap: ReadonlyArray<number>;
2476+
lineMap?: ReadonlyArray<number>;
24772477
}
24782478

24792479

src/harness/unittests/textChanges.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,14 @@ namespace ts {
2828
}
2929

3030
// validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed.
31-
function verifyPositions({ text, node }: textChanges.NonFormattedText): void {
31+
function verifyPositions(node: Node, text: string): void {
3232
const nodeList = flattenNodes(node);
3333
const sourceFile = createSourceFile("f.ts", text, ScriptTarget.ES2015);
3434
const parsedNodeList = flattenNodes(sourceFile.statements[0]);
35-
Debug.assert(nodeList.length === parsedNodeList.length);
36-
for (let i = 0; i < nodeList.length; i++) {
37-
const left = nodeList[i];
38-
const right = parsedNodeList[i];
35+
zipWith(nodeList, parsedNodeList, (left, right) => {
3936
Debug.assert(left.pos === right.pos);
4037
Debug.assert(left.end === right.end);
41-
}
38+
});
4239

4340
function flattenNodes(n: Node) {
4441
const data: (Node | NodeArray<Node>)[] = [];
@@ -57,9 +54,9 @@ namespace ts {
5754
Harness.Baseline.runBaseline(`textChanges/${caption}.js`, () => {
5855
const sourceFile = createSourceFile("source.ts", text, ScriptTarget.ES2015, /*setParentNodes*/ true);
5956
const rulesProvider = getRuleProvider(placeOpenBraceOnNewLineForFunctions);
60-
const changeTracker = new textChanges.ChangeTracker(newLineCharacter, rulesProvider, validateNodes ? verifyPositions : undefined);
57+
const changeTracker = new textChanges.ChangeTracker(newLineCharacter, rulesProvider);
6158
testBlock(sourceFile, changeTracker);
62-
const changes = changeTracker.getChanges();
59+
const changes = changeTracker.getChanges(validateNodes ? verifyPositions : undefined);
6360
assert.equal(changes.length, 1);
6461
assert.equal(changes[0].fileName, sourceFile.fileName);
6562
const modified = textChanges.applyChanges(sourceFile.text, changes[0].textChanges);

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,15 @@
893893
</Str>
894894
<Disp Icon="Str" />
895895
</Item>
896+
<Item ItemId=";Add_definite_assignment_assertion_to_property_0_95020" ItemType="0" PsrId="306" Leaf="true">
897+
<Str Cat="Text">
898+
<Val><![CDATA[Add definite assignment assertion to property '{0}']]></Val>
899+
<Tgt Cat="Text" Stat="Loc" Orig="New">
900+
<Val><![CDATA[Dodaj asercję określonego przypisania do właściwości „{0}”]]></Val>
901+
</Tgt>
902+
</Str>
903+
<Disp Icon="Str" />
904+
</Item>
896905
<Item ItemId=";Add_index_signature_for_property_0_90017" ItemType="0" PsrId="306" Leaf="true">
897906
<Str Cat="Text">
898907
<Val><![CDATA[Add index signature for property '{0}']]></Val>
@@ -905,6 +914,15 @@
905914
</Str>
906915
<Disp Icon="Str" />
907916
</Item>
917+
<Item ItemId=";Add_initializer_to_property_0_95019" ItemType="0" PsrId="306" Leaf="true">
918+
<Str Cat="Text">
919+
<Val><![CDATA[Add initializer to property '{0}']]></Val>
920+
<Tgt Cat="Text" Stat="Loc" Orig="New">
921+
<Val><![CDATA[Dodaj inicjator do właściwości „{0}”]]></Val>
922+
</Tgt>
923+
</Str>
924+
<Disp Icon="Str" />
925+
</Item>
908926
<Item ItemId=";Add_missing_super_call_90001" ItemType="0" PsrId="306" Leaf="true">
909927
<Str Cat="Text">
910928
<Val><![CDATA[Add missing 'super()' call]]></Val>
@@ -929,6 +947,15 @@
929947
</Str>
930948
<Disp Icon="Str" />
931949
</Item>
950+
<Item ItemId=";Add_undefined_type_to_property_0_95018" ItemType="0" PsrId="306" Leaf="true">
951+
<Str Cat="Text">
952+
<Val><![CDATA[Add 'undefined' type to property '{0}']]></Val>
953+
<Tgt Cat="Text" Stat="Loc" Orig="New">
954+
<Val><![CDATA[Dodaj typ „undefined” do właściwości „{0}”]]></Val>
955+
</Tgt>
956+
</Str>
957+
<Disp Icon="Str" />
958+
</Item>
932959
<Item ItemId=";Adding_a_tsconfig_json_file_will_help_organize_projects_that_contain_both_TypeScript_and_JavaScript__5068" ItemType="0" PsrId="306" Leaf="true">
933960
<Str Cat="Text">
934961
<Val><![CDATA[Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.]]></Val>

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,15 @@
893893
</Str>
894894
<Disp Icon="Str" />
895895
</Item>
896+
<Item ItemId=";Add_definite_assignment_assertion_to_property_0_95020" ItemType="0" PsrId="306" Leaf="true">
897+
<Str Cat="Text">
898+
<Val><![CDATA[Add definite assignment assertion to property '{0}']]></Val>
899+
<Tgt Cat="Text" Stat="Loc" Orig="New">
900+
<Val><![CDATA[Adicionar a asserção de atribuição definitiva à propriedade '{0}']]></Val>
901+
</Tgt>
902+
</Str>
903+
<Disp Icon="Str" />
904+
</Item>
896905
<Item ItemId=";Add_index_signature_for_property_0_90017" ItemType="0" PsrId="306" Leaf="true">
897906
<Str Cat="Text">
898907
<Val><![CDATA[Add index signature for property '{0}']]></Val>
@@ -905,6 +914,15 @@
905914
</Str>
906915
<Disp Icon="Str" />
907916
</Item>
917+
<Item ItemId=";Add_initializer_to_property_0_95019" ItemType="0" PsrId="306" Leaf="true">
918+
<Str Cat="Text">
919+
<Val><![CDATA[Add initializer to property '{0}']]></Val>
920+
<Tgt Cat="Text" Stat="Loc" Orig="New">
921+
<Val><![CDATA[Adicionar inicializador à propriedade '{0}']]></Val>
922+
</Tgt>
923+
</Str>
924+
<Disp Icon="Str" />
925+
</Item>
908926
<Item ItemId=";Add_missing_super_call_90001" ItemType="0" PsrId="306" Leaf="true">
909927
<Str Cat="Text">
910928
<Val><![CDATA[Add missing 'super()' call]]></Val>
@@ -929,6 +947,15 @@
929947
</Str>
930948
<Disp Icon="Str" />
931949
</Item>
950+
<Item ItemId=";Add_undefined_type_to_property_0_95018" ItemType="0" PsrId="306" Leaf="true">
951+
<Str Cat="Text">
952+
<Val><![CDATA[Add 'undefined' type to property '{0}']]></Val>
953+
<Tgt Cat="Text" Stat="Loc" Orig="New">
954+
<Val><![CDATA[Adicionar tipo 'indefinido' à propriedade '{0}']]></Val>
955+
</Tgt>
956+
</Str>
957+
<Disp Icon="Str" />
958+
</Item>
932959
<Item ItemId=";Adding_a_tsconfig_json_file_will_help_organize_projects_that_contain_both_TypeScript_and_JavaScript__5068" ItemType="0" PsrId="306" Leaf="true">
933960
<Str Cat="Text">
934961
<Val><![CDATA[Adding a tsconfig.json file will help organize projects that contain both TypeScript and JavaScript files. Learn more at https://aka.ms/tsconfig.]]></Val>

src/services/textChanges.ts

Lines changed: 50 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -212,11 +212,7 @@ namespace ts.textChanges {
212212
}
213213

214214
/** Public for tests only. Other callers should use `ChangeTracker.with`. */
215-
constructor(
216-
private readonly newLineCharacter: string,
217-
private readonly formatContext: ts.formatting.FormatContext,
218-
private readonly validator?: (text: NonFormattedText) => void) {
219-
}
215+
constructor(private readonly newLineCharacter: string, private readonly formatContext: ts.formatting.FormatContext) {}
220216

221217
public deleteRange(sourceFile: SourceFile, range: TextRange) {
222218
this.changes.push({ kind: ChangeKind.Remove, sourceFile, range });
@@ -590,104 +586,83 @@ namespace ts.textChanges {
590586
});
591587
}
592588

593-
public getChanges(): FileTextChanges[] {
589+
/**
590+
* Note: after calling this, the TextChanges object must be discarded!
591+
* @param validate only for tests
592+
* The reason we must validate as part of this method is that `getNonFormattedText` changes the node's positions,
593+
* so we can only call this once and can't get the non-formatted text separately.
594+
*/
595+
public getChanges(validate?: ValidateNonFormattedText): FileTextChanges[] {
594596
this.finishInsertNodeAtClassStart();
595-
return group(this.changes, c => c.sourceFile.path).map(changesInFile => {
597+
return changesToText.getTextChangesFromChanges(this.changes, this.newLineCharacter, this.formatContext, validate);
598+
}
599+
}
600+
601+
export type ValidateNonFormattedText = (node: Node, text: string) => void;
602+
603+
namespace changesToText {
604+
export function getTextChangesFromChanges(changes: ReadonlyArray<Change>, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): FileTextChanges[] {
605+
return group(changes, c => c.sourceFile.path).map(changesInFile => {
596606
const sourceFile = changesInFile[0].sourceFile;
597-
const textChanges = ChangeTracker.normalize(changesInFile).map(c =>
598-
createTextChange(createTextSpanFromRange(c.range), this.computeNewText(c, sourceFile)));
607+
// order changes by start position
608+
const normalized = stableSort(changesInFile, (a, b) => a.range.pos - b.range.pos);
609+
// verify that change intervals do not overlap, except possibly at end points.
610+
for (let i = 0; i < normalized.length - 2; i++) {
611+
Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos, "Changes overlap", () =>
612+
`${JSON.stringify(normalized[i].range)} and ${JSON.stringify(normalized[i + 1].range)}`);
613+
}
614+
const textChanges = normalized.map(c =>
615+
createTextChange(createTextSpanFromRange(c.range), computeNewText(c, sourceFile, newLineCharacter, formatContext, validate)));
599616
return { fileName: sourceFile.fileName, textChanges };
600617
});
601618
}
602619

603-
private computeNewText(change: Change, sourceFile: SourceFile): string {
620+
function computeNewText(change: Change, sourceFile: SourceFile, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string {
604621
if (change.kind === ChangeKind.Remove) {
605-
// deletion case
606622
return "";
607623
}
608624

609-
const options = change.options || {};
610-
let text: string;
611-
const pos = change.range.pos;
612-
const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos;
613-
if (change.kind === ChangeKind.ReplaceWithMultipleNodes) {
614-
const lastIndex = change.nodes.length - 1;
615-
const parts = change.nodes.map((n, index) => {
616-
const formatted = this.getFormattedTextOfNode(n, sourceFile, pos, options);
617-
return index === lastIndex || endsWith(formatted, this.newLineCharacter)
618-
? formatted
619-
: (formatted + this.newLineCharacter);
620-
});
621-
text = parts.join("");
622-
}
623-
else {
624-
Debug.assert(change.kind === ChangeKind.ReplaceWithSingleNode, "change.kind === ReplaceWithSingleNode");
625-
text = this.getFormattedTextOfNode(change.node, sourceFile, pos, options);
626-
}
625+
const { options = {}, range: { pos } } = change;
626+
const format = (n: Node) => getFormattedTextOfNode(n, sourceFile, pos, options, newLineCharacter, formatContext, validate);
627+
const text = change.kind === ChangeKind.ReplaceWithMultipleNodes
628+
? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join(newLineCharacter)
629+
: format(change.node);
627630
// strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line
628-
text = (posStartsLine || options.indentation !== undefined) ? text : text.replace(/^\s+/, "");
629-
return (options.prefix || "") + text + (options.suffix || "");
631+
const noIndent = (options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text : text.replace(/^\s+/, "");
632+
return (options.prefix || "") + noIndent + (options.suffix || "");
630633
}
631634

632-
private getFormattedTextOfNode(node: Node, sourceFile: SourceFile, pos: number, options: ChangeNodeOptions): string {
633-
const nonformattedText = getNonformattedText(node, sourceFile, this.newLineCharacter);
634-
if (this.validator) {
635-
this.validator(nonformattedText);
636-
}
637-
638-
const { options: formatOptions } = this.formatContext;
639-
const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos;
640-
635+
/** Note: this may mutate `nodeIn`. */
636+
function getFormattedTextOfNode(nodeIn: Node, sourceFile: SourceFile, pos: number, options: ChangeNodeOptions, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string {
637+
const { node, text } = getNonformattedText(nodeIn, sourceFile, newLineCharacter);
638+
if (validate) validate(node, text);
639+
const { options: formatOptions } = formatContext;
641640
const initialIndentation =
642641
options.indentation !== undefined
643642
? options.indentation
644643
: (options.useIndentationFromFile !== false)
645-
? formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, posStartsLine || (options.prefix === this.newLineCharacter))
644+
? formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, options.prefix === newLineCharacter || getLineStartPositionForPosition(pos, sourceFile) === pos)
646645
: 0;
647646
const delta =
648647
options.delta !== undefined
649648
? options.delta
650-
: formatting.SmartIndenter.shouldIndentChildNode(node)
649+
: formatting.SmartIndenter.shouldIndentChildNode(nodeIn)
651650
? (formatOptions.indentSize || 0)
652651
: 0;
653-
654-
return applyFormatting(nonformattedText, sourceFile, initialIndentation, delta, this.formatContext);
652+
const file: SourceFileLike = { text, getLineAndCharacterOfPosition(pos) { return getLineAndCharacterOfPosition(this, pos); } };
653+
const changes = formatting.formatNodeGivenIndentation(node, file, sourceFile.languageVariant, initialIndentation, delta, formatContext);
654+
return applyChanges(text, changes);
655655
}
656656

657-
private static normalize(changes: ReadonlyArray<Change>): ReadonlyArray<Change> {
658-
// order changes by start position
659-
const normalized = stableSort(changes, (a, b) => a.range.pos - b.range.pos);
660-
// verify that change intervals do not overlap, except possibly at end points.
661-
for (let i = 0; i < normalized.length - 2; i++) {
662-
Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos);
663-
}
664-
return normalized;
657+
/** Note: output node may be mutated input node. */
658+
function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLineCharacter: string): { text: string, node: Node } {
659+
const writer = new Writer(newLineCharacter);
660+
const newLine = newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed;
661+
createPrinter({ newLine }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer);
662+
return { text: writer.getText(), node: assignPositionsToNode(node) };
665663
}
666664
}
667665

668-
export interface NonFormattedText {
669-
readonly text: string;
670-
readonly node: Node;
671-
}
672-
673-
function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLine: string): NonFormattedText {
674-
const writer = new Writer(newLine);
675-
const printer = createPrinter({ newLine: newLine === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed }, writer);
676-
printer.writeNode(EmitHint.Unspecified, node, sourceFile, writer);
677-
return { text: writer.getText(), node: assignPositionsToNode(node) };
678-
}
679-
680-
function applyFormatting(nonFormattedText: NonFormattedText, sourceFile: SourceFile, initialIndentation: number, delta: number, formatContext: ts.formatting.FormatContext) {
681-
const lineMap = computeLineStarts(nonFormattedText.text);
682-
const file: SourceFileLike = {
683-
text: nonFormattedText.text,
684-
lineMap,
685-
getLineAndCharacterOfPosition: pos => computeLineAndCharacterOfPosition(lineMap, pos)
686-
};
687-
const changes = formatting.formatNodeGivenIndentation(nonFormattedText.node, file, sourceFile.languageVariant, initialIndentation, delta, formatContext);
688-
return applyChanges(nonFormattedText.text, changes);
689-
}
690-
691666
export function applyChanges(text: string, changes: TextChange[]): string {
692667
for (let i = changes.length - 1; i >= 0; i--) {
693668
const change = changes[i];

tests/baselines/reference/esModuleInterop.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ fs;
2222
"use strict";
2323
var __importDefault = (this && this.__importDefault) || function (mod) {
2424
return (mod && mod.__esModule) ? mod : { "default": mod };
25-
}
25+
};
2626
var __importStar = (this && this.__importStar) || function (mod) {
2727
if (mod && mod.__esModule) return mod;
2828
var result = {};
2929
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
3030
result["default"] = mod;
3131
return result;
32-
}
32+
};
3333
exports.__esModule = true;
3434
var hybrid_1 = require("./hybrid");
3535
var path_1 = __importDefault(require("./path"));

tests/baselines/reference/esModuleInteropImportCall.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
1717
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
1818
result["default"] = mod;
1919
return result;
20-
}
20+
};
2121
Promise.resolve().then(function () { return __importStar(require("./foo")); }).then(function (f) {
2222
f["default"];
2323
});

tests/baselines/reference/esModuleInteropImportNamespace.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
1818
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
1919
result["default"] = mod;
2020
return result;
21-
}
21+
};
2222
exports.__esModule = true;
2323
var foo = __importStar(require("./foo"));
2424
foo["default"];

0 commit comments

Comments
 (0)