From 456a6bf658b25d559d3eadc9e9ea04aaa5faf7f4 Mon Sep 17 00:00:00 2001 From: Klaus Meinhardt Date: Sat, 3 Jun 2017 00:10:41 +0200 Subject: [PATCH 001/256] program.getSourceFile[ByPath] can return undefined --- src/compiler/program.ts | 4 ++-- src/compiler/types.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 834122b3584..d481e72b689 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -969,11 +969,11 @@ namespace ts { return emitResult; } - function getSourceFile(fileName: string): SourceFile { + function getSourceFile(fileName: string): SourceFile | undefined { return getSourceFileByPath(toPath(fileName, currentDirectory, getCanonicalFileName)); } - function getSourceFileByPath(path: Path): SourceFile { + function getSourceFileByPath(path: Path): SourceFile | undefined { return filesByName.get(path); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ed1d5dcbe23..da438809d92 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2352,8 +2352,8 @@ namespace ts { export interface ScriptReferenceHost { getCompilerOptions(): CompilerOptions; - getSourceFile(fileName: string): SourceFile; - getSourceFileByPath(path: Path): SourceFile; + getSourceFile(fileName: string): SourceFile | undefined; + getSourceFileByPath(path: Path): SourceFile | undefined; getCurrentDirectory(): string; } From 1f77317b6459641212efcf3fd6b9b6aa005ba968 Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Sun, 13 Aug 2017 15:12:11 +0800 Subject: [PATCH 002/256] add strictTuples flag giving tuples known length --- src/compiler/checker.ts | 7 +++ src/compiler/commandLineParser.ts | 7 +++ src/compiler/diagnosticMessages.json | 4 ++ src/compiler/types.ts | 1 + .../unittests/configurationExtension.ts | 6 +++ src/harness/unittests/transpile.ts | 4 ++ src/server/protocol.ts | 1 + .../baselines/reference/genericTypeAliases.js | 4 +- .../reference/genericTypeAliases.symbols | 32 ++++++------- .../reference/genericTypeAliases.types | 12 ++--- .../nominalSubtypeCheckOfTypeParameter.js | 10 ++-- ...nominalSubtypeCheckOfTypeParameter.symbols | 46 +++++++++---------- .../nominalSubtypeCheckOfTypeParameter.types | 20 ++++---- .../Supports setting strictTuples.js | 2 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../reference/tupleLength.errors.txt | 26 +++++++++++ tests/baselines/reference/tupleLength.js | 32 +++++++++++++ tests/cases/compiler/tupleLength.ts | 18 ++++++++ .../types/typeAliases/genericTypeAliases.ts | 4 +- .../nominalSubtypeCheckOfTypeParameter.ts | 10 ++-- 27 files changed, 185 insertions(+), 69 deletions(-) create mode 100644 tests/baselines/reference/transpile/Supports setting strictTuples.js create mode 100644 tests/baselines/reference/tupleLength.errors.txt create mode 100644 tests/baselines/reference/tupleLength.js create mode 100644 tests/cases/compiler/tupleLength.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 90328770750..d533f5f82fb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -64,6 +64,7 @@ namespace ts { const noUnusedIdentifiers = !!compilerOptions.noUnusedLocals || !!compilerOptions.noUnusedParameters; const allowSyntheticDefaultImports = typeof compilerOptions.allowSyntheticDefaultImports !== "undefined" ? compilerOptions.allowSyntheticDefaultImports : modulekind === ModuleKind.System; const strictNullChecks = compilerOptions.strictNullChecks === undefined ? compilerOptions.strict : compilerOptions.strictNullChecks; + const strictTuples = compilerOptions.strictTuples === undefined ? compilerOptions.strict : compilerOptions.strictTuples; const noImplicitAny = compilerOptions.noImplicitAny === undefined ? compilerOptions.strict : compilerOptions.noImplicitAny; const noImplicitThis = compilerOptions.noImplicitThis === undefined ? compilerOptions.strict : compilerOptions.noImplicitThis; @@ -7161,6 +7162,12 @@ namespace ts { property.type = typeParameter; properties.push(property); } + if (strictTuples) { + const lengthSymbol = createSymbol(SymbolFlags.Property, "length" as __String); + lengthSymbol.type = getLiteralType(arity); + lengthSymbol.checkFlags = CheckFlags.Readonly; + properties.push(lengthSymbol); + } const type = createObjectType(ObjectFlags.Tuple | ObjectFlags.Reference); type.typeParameters = typeParameters; type.outerTypeParameters = undefined; diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index c92d147f9a9..f6baca68647 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -269,6 +269,13 @@ namespace ts { category: Diagnostics.Strict_Type_Checking_Options, description: Diagnostics.Enable_strict_null_checks }, + { + name: "strictTuples", + type: "boolean", + showInSimplifiedHelpView: true, + category: Diagnostics.Strict_Type_Checking_Options, + description: Diagnostics.Enable_strict_tuple_checks + }, { name: "noImplicitThis", type: "boolean", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 77e7f7e7b62..bda14f2c9ce 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3302,6 +3302,10 @@ "category": "Message", "code": 6185 }, + "Enable strict tuple checks.": { + "category": "Message", + "code": 6187 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 0a09bb5b6ec..bc06d247f2c 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3622,6 +3622,7 @@ namespace ts { sourceRoot?: string; strict?: boolean; strictNullChecks?: boolean; // Always combine with strict property + strictTuples?: boolean; /* @internal */ stripInternal?: boolean; suppressExcessPropertyErrors?: boolean; suppressImplicitAnyIndexErrors?: boolean; diff --git a/src/harness/unittests/configurationExtension.ts b/src/harness/unittests/configurationExtension.ts index 2d50d2cb2af..776feb535c5 100644 --- a/src/harness/unittests/configurationExtension.ts +++ b/src/harness/unittests/configurationExtension.ts @@ -16,6 +16,12 @@ namespace ts { strictNullChecks: false } }, + "/dev/tsconfig.strictTuples.json": { + extends: "./tsconfig", + compilerOptions: { + strictTuples: false + } + }, "/dev/configs/base.json": { compilerOptions: { allowJs: true, diff --git a/src/harness/unittests/transpile.ts b/src/harness/unittests/transpile.ts index e0c96797827..f727fff5594 100644 --- a/src/harness/unittests/transpile.ts +++ b/src/harness/unittests/transpile.ts @@ -413,6 +413,10 @@ var x = 0;`, { options: { compilerOptions: { strictNullChecks: true }, fileName: "input.js", reportDiagnostics: true } }); + transpilesCorrectly("Supports setting 'strictTuples'", "x;", { + options: { compilerOptions: { strictTuples: true }, fileName: "input.js", reportDiagnostics: true } + }); + transpilesCorrectly("Supports setting 'stripInternal'", "x;", { options: { compilerOptions: { stripInternal: true }, fileName: "input.js", reportDiagnostics: true } }); diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 0b7405c7b69..b5c959b484f 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -2448,6 +2448,7 @@ namespace ts.server.protocol { sourceRoot?: string; strict?: boolean; strictNullChecks?: boolean; + strictTuples?: boolean; suppressExcessPropertyErrors?: boolean; suppressImplicitAnyIndexErrors?: boolean; target?: ScriptTarget | ts.ScriptTarget; diff --git a/tests/baselines/reference/genericTypeAliases.js b/tests/baselines/reference/genericTypeAliases.js index 8218f5c886c..282fd9868a9 100644 --- a/tests/baselines/reference/genericTypeAliases.js +++ b/tests/baselines/reference/genericTypeAliases.js @@ -40,12 +40,12 @@ type Strange = string; // Type parameter not used var s: Strange; s = "hello"; -interface Tuple { +interface AB { a: A; b: B; } -type Pair = Tuple; +type Pair = AB; interface TaggedPair extends Pair { tag: string; diff --git a/tests/baselines/reference/genericTypeAliases.symbols b/tests/baselines/reference/genericTypeAliases.symbols index d5f68ec0615..521afe800b3 100644 --- a/tests/baselines/reference/genericTypeAliases.symbols +++ b/tests/baselines/reference/genericTypeAliases.symbols @@ -124,29 +124,29 @@ var s: Strange; s = "hello"; >s : Symbol(s, Decl(genericTypeAliases.ts, 38, 3)) -interface Tuple { ->Tuple : Symbol(Tuple, Decl(genericTypeAliases.ts, 39, 12)) ->A : Symbol(A, Decl(genericTypeAliases.ts, 41, 16)) ->B : Symbol(B, Decl(genericTypeAliases.ts, 41, 18)) +interface AB { +>AB : Symbol(AB, Decl(genericTypeAliases.ts, 39, 12)) +>A : Symbol(A, Decl(genericTypeAliases.ts, 41, 13)) +>B : Symbol(B, Decl(genericTypeAliases.ts, 41, 15)) a: A; ->a : Symbol(Tuple.a, Decl(genericTypeAliases.ts, 41, 23)) ->A : Symbol(A, Decl(genericTypeAliases.ts, 41, 16)) +>a : Symbol(AB.a, Decl(genericTypeAliases.ts, 41, 20)) +>A : Symbol(A, Decl(genericTypeAliases.ts, 41, 13)) b: B; ->b : Symbol(Tuple.b, Decl(genericTypeAliases.ts, 42, 9)) ->B : Symbol(B, Decl(genericTypeAliases.ts, 41, 18)) +>b : Symbol(AB.b, Decl(genericTypeAliases.ts, 42, 9)) +>B : Symbol(B, Decl(genericTypeAliases.ts, 41, 15)) } -type Pair = Tuple; +type Pair = AB; >Pair : Symbol(Pair, Decl(genericTypeAliases.ts, 44, 1)) >T : Symbol(T, Decl(genericTypeAliases.ts, 46, 10)) ->Tuple : Symbol(Tuple, Decl(genericTypeAliases.ts, 39, 12)) +>AB : Symbol(AB, Decl(genericTypeAliases.ts, 39, 12)) >T : Symbol(T, Decl(genericTypeAliases.ts, 46, 10)) >T : Symbol(T, Decl(genericTypeAliases.ts, 46, 10)) interface TaggedPair extends Pair { ->TaggedPair : Symbol(TaggedPair, Decl(genericTypeAliases.ts, 46, 27)) +>TaggedPair : Symbol(TaggedPair, Decl(genericTypeAliases.ts, 46, 24)) >T : Symbol(T, Decl(genericTypeAliases.ts, 48, 21)) >Pair : Symbol(Pair, Decl(genericTypeAliases.ts, 44, 1)) >T : Symbol(T, Decl(genericTypeAliases.ts, 48, 21)) @@ -157,17 +157,17 @@ interface TaggedPair extends Pair { var p: TaggedPair; >p : Symbol(p, Decl(genericTypeAliases.ts, 52, 3)) ->TaggedPair : Symbol(TaggedPair, Decl(genericTypeAliases.ts, 46, 27)) +>TaggedPair : Symbol(TaggedPair, Decl(genericTypeAliases.ts, 46, 24)) p.a = 1; ->p.a : Symbol(Tuple.a, Decl(genericTypeAliases.ts, 41, 23)) +>p.a : Symbol(AB.a, Decl(genericTypeAliases.ts, 41, 20)) >p : Symbol(p, Decl(genericTypeAliases.ts, 52, 3)) ->a : Symbol(Tuple.a, Decl(genericTypeAliases.ts, 41, 23)) +>a : Symbol(AB.a, Decl(genericTypeAliases.ts, 41, 20)) p.b = 2; ->p.b : Symbol(Tuple.b, Decl(genericTypeAliases.ts, 42, 9)) +>p.b : Symbol(AB.b, Decl(genericTypeAliases.ts, 42, 9)) >p : Symbol(p, Decl(genericTypeAliases.ts, 52, 3)) ->b : Symbol(Tuple.b, Decl(genericTypeAliases.ts, 42, 9)) +>b : Symbol(AB.b, Decl(genericTypeAliases.ts, 42, 9)) p.tag = "test"; >p.tag : Symbol(TaggedPair.tag, Decl(genericTypeAliases.ts, 48, 41)) diff --git a/tests/baselines/reference/genericTypeAliases.types b/tests/baselines/reference/genericTypeAliases.types index b4c75841245..722347b0f72 100644 --- a/tests/baselines/reference/genericTypeAliases.types +++ b/tests/baselines/reference/genericTypeAliases.types @@ -158,8 +158,8 @@ s = "hello"; >s : string >"hello" : "hello" -interface Tuple { ->Tuple : Tuple +interface AB { +>AB : AB >A : A >B : B @@ -172,17 +172,17 @@ interface Tuple { >B : B } -type Pair = Tuple; ->Pair : Tuple +type Pair = AB; +>Pair : AB >T : T ->Tuple : Tuple +>AB : AB >T : T >T : T interface TaggedPair extends Pair { >TaggedPair : TaggedPair >T : T ->Pair : Tuple +>Pair : AB >T : T tag: string; diff --git a/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.js b/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.js index 3259b3287fa..5712fb7c244 100644 --- a/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.js +++ b/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.js @@ -1,20 +1,20 @@ //// [nominalSubtypeCheckOfTypeParameter.ts] -interface Tuple { +interface BinaryTuple { first: T - second: S + second: S } interface Sequence { hasNext(): boolean - pop(): T - zip(seq: Sequence): Sequence> + pop(): T + zip(seq: Sequence): Sequence> } // error, despite the fact that the code explicitly says List extends Sequence, the current rules for infinitely expanding type references // perform nominal subtyping checks that allow variance for type arguments, but not nominal subtyping for the generic type itself interface List extends Sequence { getLength(): number - zip(seq: Sequence): List> + zip(seq: Sequence): List> } diff --git a/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.symbols b/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.symbols index c7d9a1b50f4..3d24b82aa8f 100644 --- a/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.symbols +++ b/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.symbols @@ -1,16 +1,16 @@ === tests/cases/conformance/types/typeRelationships/recursiveTypes/nominalSubtypeCheckOfTypeParameter.ts === -interface Tuple { ->Tuple : Symbol(Tuple, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 0)) ->T : Symbol(T, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 16)) ->S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 18)) +interface BinaryTuple { +>BinaryTuple : Symbol(BinaryTuple, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 0)) +>T : Symbol(T, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 22)) +>S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 24)) first: T ->first : Symbol(Tuple.first, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 23)) ->T : Symbol(T, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 16)) +>first : Symbol(BinaryTuple.first, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 29)) +>T : Symbol(T, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 22)) - second: S ->second : Symbol(Tuple.second, Decl(nominalSubtypeCheckOfTypeParameter.ts, 1, 12)) ->S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 18)) + second: S +>second : Symbol(BinaryTuple.second, Decl(nominalSubtypeCheckOfTypeParameter.ts, 1, 12)) +>S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 24)) } interface Sequence { @@ -20,20 +20,20 @@ interface Sequence { hasNext(): boolean >hasNext : Symbol(Sequence.hasNext, Decl(nominalSubtypeCheckOfTypeParameter.ts, 5, 23)) - pop(): T + pop(): T >pop : Symbol(Sequence.pop, Decl(nominalSubtypeCheckOfTypeParameter.ts, 6, 22)) >T : Symbol(T, Decl(nominalSubtypeCheckOfTypeParameter.ts, 5, 19)) - zip(seq: Sequence): Sequence> ->zip : Symbol(Sequence.zip, Decl(nominalSubtypeCheckOfTypeParameter.ts, 7, 14)) ->S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 8, 10)) ->seq : Symbol(seq, Decl(nominalSubtypeCheckOfTypeParameter.ts, 8, 13)) + zip(seq: Sequence): Sequence> +>zip : Symbol(Sequence.zip, Decl(nominalSubtypeCheckOfTypeParameter.ts, 7, 12)) +>S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 8, 8)) +>seq : Symbol(seq, Decl(nominalSubtypeCheckOfTypeParameter.ts, 8, 11)) >Sequence : Symbol(Sequence, Decl(nominalSubtypeCheckOfTypeParameter.ts, 3, 1)) ->S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 8, 10)) +>S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 8, 8)) >Sequence : Symbol(Sequence, Decl(nominalSubtypeCheckOfTypeParameter.ts, 3, 1)) ->Tuple : Symbol(Tuple, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 0)) +>BinaryTuple : Symbol(BinaryTuple, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 0)) >T : Symbol(T, Decl(nominalSubtypeCheckOfTypeParameter.ts, 5, 19)) ->S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 8, 10)) +>S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 8, 8)) } // error, despite the fact that the code explicitly says List extends Sequence, the current rules for infinitely expanding type references @@ -47,15 +47,15 @@ interface List extends Sequence { getLength(): number >getLength : Symbol(List.getLength, Decl(nominalSubtypeCheckOfTypeParameter.ts, 13, 39)) - zip(seq: Sequence): List> + zip(seq: Sequence): List> >zip : Symbol(List.zip, Decl(nominalSubtypeCheckOfTypeParameter.ts, 14, 23)) ->S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 15, 10)) ->seq : Symbol(seq, Decl(nominalSubtypeCheckOfTypeParameter.ts, 15, 13)) +>S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 15, 8)) +>seq : Symbol(seq, Decl(nominalSubtypeCheckOfTypeParameter.ts, 15, 11)) >Sequence : Symbol(Sequence, Decl(nominalSubtypeCheckOfTypeParameter.ts, 3, 1)) ->S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 15, 10)) +>S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 15, 8)) >List : Symbol(List, Decl(nominalSubtypeCheckOfTypeParameter.ts, 9, 1)) ->Tuple : Symbol(Tuple, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 0)) +>BinaryTuple : Symbol(BinaryTuple, Decl(nominalSubtypeCheckOfTypeParameter.ts, 0, 0)) >T : Symbol(T, Decl(nominalSubtypeCheckOfTypeParameter.ts, 13, 15)) ->S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 15, 10)) +>S : Symbol(S, Decl(nominalSubtypeCheckOfTypeParameter.ts, 15, 8)) } diff --git a/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.types b/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.types index 79b2ac77d78..5da84d0c8a4 100644 --- a/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.types +++ b/tests/baselines/reference/nominalSubtypeCheckOfTypeParameter.types @@ -1,6 +1,6 @@ === tests/cases/conformance/types/typeRelationships/recursiveTypes/nominalSubtypeCheckOfTypeParameter.ts === -interface Tuple { ->Tuple : Tuple +interface BinaryTuple { +>BinaryTuple : BinaryTuple >T : T >S : S @@ -8,7 +8,7 @@ interface Tuple { >first : T >T : T - second: S + second: S >second : S >S : S } @@ -20,18 +20,18 @@ interface Sequence { hasNext(): boolean >hasNext : () => boolean - pop(): T + pop(): T >pop : () => T >T : T - zip(seq: Sequence): Sequence> ->zip : (seq: Sequence) => Sequence> + zip(seq: Sequence): Sequence> +>zip : (seq: Sequence) => Sequence> >S : S >seq : Sequence >Sequence : Sequence >S : S >Sequence : Sequence ->Tuple : Tuple +>BinaryTuple : BinaryTuple >T : T >S : S } @@ -47,14 +47,14 @@ interface List extends Sequence { getLength(): number >getLength : () => number - zip(seq: Sequence): List> ->zip : (seq: Sequence) => List> + zip(seq: Sequence): List> +>zip : (seq: Sequence) => List> >S : S >seq : Sequence >Sequence : Sequence >S : S >List : List ->Tuple : Tuple +>BinaryTuple : BinaryTuple >T : T >S : S } diff --git a/tests/baselines/reference/transpile/Supports setting strictTuples.js b/tests/baselines/reference/transpile/Supports setting strictTuples.js new file mode 100644 index 00000000000..8394371f908 --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting strictTuples.js @@ -0,0 +1,2 @@ +x; +//# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json index 0f5b2378468..5218d687724 100644 --- a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictTuples": true, /* Enable strict tuple checks. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json index a545124a723..4fc67f07f0e 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json @@ -22,6 +22,7 @@ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictTuples": true, /* Enable strict tuple checks. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json index b53ac2d8552..cd190298fd8 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictTuples": true, /* Enable strict tuple checks. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json index 4e06e06d159..278322852f8 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictTuples": true, /* Enable strict tuple checks. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json index 94808d89ed0..c81634bccea 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictTuples": true, /* Enable strict tuple checks. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json index 0f5b2378468..5218d687724 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictTuples": true, /* Enable strict tuple checks. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json index d165b0f2775..0b34f4724f8 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json @@ -22,6 +22,7 @@ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictTuples": true, /* Enable strict tuple checks. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json index 2a169b3aaaf..9a63db2069b 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json @@ -22,6 +22,7 @@ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictTuples": true, /* Enable strict tuple checks. */ // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ diff --git a/tests/baselines/reference/tupleLength.errors.txt b/tests/baselines/reference/tupleLength.errors.txt new file mode 100644 index 00000000000..c68bd652c85 --- /dev/null +++ b/tests/baselines/reference/tupleLength.errors.txt @@ -0,0 +1,26 @@ +tests/cases/compiler/tupleLength.ts(11,5): error TS2403: Subsequent variable declarations must have the same type. Variable 't1' must be of type '[number]', but here has type '[number, number]'. +tests/cases/compiler/tupleLength.ts(12,5): error TS2403: Subsequent variable declarations must have the same type. Variable 't2' must be of type '[number, number]', but here has type '[number]'. + + +==== tests/cases/compiler/tupleLength.ts (2 errors) ==== + // var t0: []; + var t1: [number]; + var t2: [number, number]; + var arr: number[]; + + // var len0: 0 = t0.length; + var len1: 1 = t1.length; + var len2: 2 = t2.length; + var lena: number = arr.length; + + var t1 = t2; // error + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 't1' must be of type '[number]', but here has type '[number, number]'. + var t2 = t1; // error + ~~ +!!! error TS2403: Subsequent variable declarations must have the same type. Variable 't2' must be of type '[number, number]', but here has type '[number]'. + + type A = T['length']; + var b: A<[boolean]>; + var c: 1 = b; + \ No newline at end of file diff --git a/tests/baselines/reference/tupleLength.js b/tests/baselines/reference/tupleLength.js new file mode 100644 index 00000000000..3893305421b --- /dev/null +++ b/tests/baselines/reference/tupleLength.js @@ -0,0 +1,32 @@ +//// [tupleLength.ts] +// var t0: []; +var t1: [number]; +var t2: [number, number]; +var arr: number[]; + +// var len0: 0 = t0.length; +var len1: 1 = t1.length; +var len2: 2 = t2.length; +var lena: number = arr.length; + +var t1 = t2; // error +var t2 = t1; // error + +type A = T['length']; +var b: A<[boolean]>; +var c: 1 = b; + + +//// [tupleLength.js] +// var t0: []; +var t1; +var t2; +var arr; +// var len0: 0 = t0.length; +var len1 = t1.length; +var len2 = t2.length; +var lena = arr.length; +var t1 = t2; // error +var t2 = t1; // error +var b; +var c = b; diff --git a/tests/cases/compiler/tupleLength.ts b/tests/cases/compiler/tupleLength.ts new file mode 100644 index 00000000000..3c6db1a034a --- /dev/null +++ b/tests/cases/compiler/tupleLength.ts @@ -0,0 +1,18 @@ +// @strictTuples: true + +// var t0: []; +var t1: [number]; +var t2: [number, number]; +var arr: number[]; + +// var len0: 0 = t0.length; +var len1: 1 = t1.length; +var len2: 2 = t2.length; +var lena: number = arr.length; + +var t1 = t2; // error +var t2 = t1; // error + +type A = T['length']; +var b: A<[boolean]>; +var c: 1 = b; diff --git a/tests/cases/conformance/types/typeAliases/genericTypeAliases.ts b/tests/cases/conformance/types/typeAliases/genericTypeAliases.ts index e26279a8a41..8c8ab3291fa 100644 --- a/tests/cases/conformance/types/typeAliases/genericTypeAliases.ts +++ b/tests/cases/conformance/types/typeAliases/genericTypeAliases.ts @@ -39,12 +39,12 @@ type Strange = string; // Type parameter not used var s: Strange; s = "hello"; -interface Tuple { +interface AB { a: A; b: B; } -type Pair = Tuple; +type Pair = AB; interface TaggedPair extends Pair { tag: string; diff --git a/tests/cases/conformance/types/typeRelationships/recursiveTypes/nominalSubtypeCheckOfTypeParameter.ts b/tests/cases/conformance/types/typeRelationships/recursiveTypes/nominalSubtypeCheckOfTypeParameter.ts index ed8d724300d..ea16201ae91 100644 --- a/tests/cases/conformance/types/typeRelationships/recursiveTypes/nominalSubtypeCheckOfTypeParameter.ts +++ b/tests/cases/conformance/types/typeRelationships/recursiveTypes/nominalSubtypeCheckOfTypeParameter.ts @@ -1,17 +1,17 @@ -interface Tuple { +interface BinaryTuple { first: T - second: S + second: S } interface Sequence { hasNext(): boolean - pop(): T - zip(seq: Sequence): Sequence> + pop(): T + zip(seq: Sequence): Sequence> } // error, despite the fact that the code explicitly says List extends Sequence, the current rules for infinitely expanding type references // perform nominal subtyping checks that allow variance for type arguments, but not nominal subtyping for the generic type itself interface List extends Sequence { getLength(): number - zip(seq: Sequence): List> + zip(seq: Sequence): List> } From ff0961b85e33f6dd6f876df5c5ed2777ea309bde Mon Sep 17 00:00:00 2001 From: Yuval Greenfield Date: Fri, 8 Sep 2017 15:02:59 -0700 Subject: [PATCH 003/256] Remove trailing space from emitLeadingComment This will prevent emiting an extraneous trailing space on comments to match https://eslint.org/docs/rules/no-trailing-spaces This also removes a space that may have been originally there after a comment but isn't necessary syntactically. --- src/compiler/comments.ts | 3 --- .../baselines/reference/ambientDeclarationsExternal.js | 2 +- tests/baselines/reference/anyAssignableToEveryType.js | 2 +- tests/baselines/reference/augmentedTypesClass3.js | 2 +- tests/baselines/reference/augmentedTypesEnum.js | 2 +- tests/baselines/reference/augmentedTypesEnum2.js | 2 +- tests/baselines/reference/augmentedTypesFunction.js | 2 +- tests/baselines/reference/augmentedTypesInterface.js | 2 +- .../reference/baseIndexSignatureResolution.js | 2 +- tests/baselines/reference/commentEmitAtEndOfFile1.js | 2 +- .../reference/commentEmitWithCommentOnLastLine.js | 2 +- tests/baselines/reference/commentOnArrayElement1.js | 2 +- tests/baselines/reference/commentOnArrayElement3.js | 4 ++-- tests/baselines/reference/commentOnBlock1.js | 2 +- .../reference/commentsArgumentsOfCallExpression1.js | 2 +- .../reference/commentsArgumentsOfCallExpression2.js | 6 +++--- tests/baselines/reference/commentsCommentParsing.js | 10 +++++----- tests/baselines/reference/commentsFunction.js | 4 ++-- .../reference/commentsOnPropertyOfObjectLiteral1.js | 2 +- ...mparisonOperatorWithSubtypeObjectOnCallSignature.js | 2 +- ...nOperatorWithSubtypeObjectOnConstructorSignature.js | 2 +- ...atorWithSubtypeObjectOnInstantiatedCallSignature.js | 2 +- ...hSubtypeObjectOnInstantiatedConstructorSignature.js | 2 +- tests/baselines/reference/concatError.js | 2 +- tests/baselines/reference/errorSupression1.js | 2 +- tests/baselines/reference/everyTypeAssignableToAny.js | 2 +- .../reference/functionConstraintSatisfaction.js | 2 +- .../genericCallWithObjectTypeArgsAndNumericIndexer.js | 2 +- .../genericCallWithObjectTypeArgsAndStringIndexer.js | 2 +- .../baselines/reference/heterogeneousArrayLiterals.js | 2 +- .../reference/innerTypeParameterShadowingOuterOne.js | 2 +- .../reference/innerTypeParameterShadowingOuterOne2.js | 2 +- .../reference/literalsInComputedProperties1.js | 2 +- tests/baselines/reference/moduleIdentifiers.js | 2 +- .../reference/moduleResolutionWithExtensions.js | 4 ++-- tests/baselines/reference/nullAssignableToEveryType.js | 2 +- tests/baselines/reference/parserSkippedTokens10.js | 2 +- .../recursivelySpecializedConstructorDeclaration.js | 2 +- tests/baselines/reference/scannerS7.4_A2_T2.js | 2 +- tests/baselines/reference/sourceMap-Comment1.js | 2 +- .../reference/sourceMap-Comment1.sourcemap.txt | 2 +- .../reference/systemDefaultExportCommentValidity.js | 2 +- .../reference/systemModuleTrailingComments.js | 2 +- .../typeParameterUsedAsTypeParameterConstraint3.js | 2 +- .../reference/undefinedAssignableToEveryType.js | 2 +- 45 files changed, 53 insertions(+), 56 deletions(-) diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts index 025a4f36d26..b936c0655e1 100644 --- a/src/compiler/comments.ts +++ b/src/compiler/comments.ts @@ -274,9 +274,6 @@ namespace ts { if (hasTrailingNewLine) { writer.writeLine(); } - else { - writer.write(" "); - } } function emitLeadingCommentsOfPosition(pos: number) { diff --git a/tests/baselines/reference/ambientDeclarationsExternal.js b/tests/baselines/reference/ambientDeclarationsExternal.js index fb531586467..ed413fb0d8e 100644 --- a/tests/baselines/reference/ambientDeclarationsExternal.js +++ b/tests/baselines/reference/ambientDeclarationsExternal.js @@ -24,7 +24,7 @@ var n: number; //// [decls.js] -// Ambient external import declaration referencing ambient external module using top level module name +// Ambient external import declaration referencing ambient external module using top level module name //// [consumer.js] "use strict"; exports.__esModule = true; diff --git a/tests/baselines/reference/anyAssignableToEveryType.js b/tests/baselines/reference/anyAssignableToEveryType.js index d6b2303de48..eff97905e4f 100644 --- a/tests/baselines/reference/anyAssignableToEveryType.js +++ b/tests/baselines/reference/anyAssignableToEveryType.js @@ -87,4 +87,4 @@ function foo(x, y, z) { // x = a; // y = a; // z = a; -//} +//} diff --git a/tests/baselines/reference/augmentedTypesClass3.js b/tests/baselines/reference/augmentedTypesClass3.js index d2ad63161b5..045109f8587 100644 --- a/tests/baselines/reference/augmentedTypesClass3.js +++ b/tests/baselines/reference/augmentedTypesClass3.js @@ -46,4 +46,4 @@ var c5c = /** @class */ (function () { c5c.prototype.foo = function () { }; return c5c; }()); -//import c5c = require(''); +//import c5c = require(''); diff --git a/tests/baselines/reference/augmentedTypesEnum.js b/tests/baselines/reference/augmentedTypesEnum.js index ff0ad93f817..edd4a92d767 100644 --- a/tests/baselines/reference/augmentedTypesEnum.js +++ b/tests/baselines/reference/augmentedTypesEnum.js @@ -100,4 +100,4 @@ var e6b; })(e6b || (e6b = {})); // should be error // enum then import, messes with error reporting //enum e7 { One } -//import e7 = require(''); // should be error +//import e7 = require(''); // should be error diff --git a/tests/baselines/reference/augmentedTypesEnum2.js b/tests/baselines/reference/augmentedTypesEnum2.js index 66fc96b62a0..0e6e70df263 100644 --- a/tests/baselines/reference/augmentedTypesEnum2.js +++ b/tests/baselines/reference/augmentedTypesEnum2.js @@ -41,4 +41,4 @@ var e2 = /** @class */ (function () { return e2; }()); //enum then enum - covered -//enum then import - covered +//enum then import - covered diff --git a/tests/baselines/reference/augmentedTypesFunction.js b/tests/baselines/reference/augmentedTypesFunction.js index 3c6066e5bb4..a2dd4a664a3 100644 --- a/tests/baselines/reference/augmentedTypesFunction.js +++ b/tests/baselines/reference/augmentedTypesFunction.js @@ -79,4 +79,4 @@ function y5b() { } function y5c() { } // function then import, messes with other errors //function y6() { } -//import y6 = require(''); +//import y6 = require(''); diff --git a/tests/baselines/reference/augmentedTypesInterface.js b/tests/baselines/reference/augmentedTypesInterface.js index b74da5bbfee..0409e157584 100644 --- a/tests/baselines/reference/augmentedTypesInterface.js +++ b/tests/baselines/reference/augmentedTypesInterface.js @@ -48,4 +48,4 @@ var i3; i3[i3["One"] = 0] = "One"; })(i3 || (i3 = {})); ; // error -//import i4 = require(''); // error +//import i4 = require(''); // error diff --git a/tests/baselines/reference/baseIndexSignatureResolution.js b/tests/baselines/reference/baseIndexSignatureResolution.js index 4053e588e44..3fdeecf78f6 100644 --- a/tests/baselines/reference/baseIndexSignatureResolution.js +++ b/tests/baselines/reference/baseIndexSignatureResolution.js @@ -59,4 +59,4 @@ interface B extends A { } var b: B = null; var z: Derived = b.foo(); -*/ +*/ diff --git a/tests/baselines/reference/commentEmitAtEndOfFile1.js b/tests/baselines/reference/commentEmitAtEndOfFile1.js index 1be031fa84a..d6ba7b158d6 100644 --- a/tests/baselines/reference/commentEmitAtEndOfFile1.js +++ b/tests/baselines/reference/commentEmitAtEndOfFile1.js @@ -18,4 +18,4 @@ var foo; (function (foo) { function bar() { } })(foo || (foo = {})); -// test #4 +// test #4 diff --git a/tests/baselines/reference/commentEmitWithCommentOnLastLine.js b/tests/baselines/reference/commentEmitWithCommentOnLastLine.js index ffd4addb264..077286a7364 100644 --- a/tests/baselines/reference/commentEmitWithCommentOnLastLine.js +++ b/tests/baselines/reference/commentEmitWithCommentOnLastLine.js @@ -8,4 +8,4 @@ var bar; var x; /* var bar; -*/ +*/ diff --git a/tests/baselines/reference/commentOnArrayElement1.js b/tests/baselines/reference/commentOnArrayElement1.js index 960df336dbb..c93cf634096 100644 --- a/tests/baselines/reference/commentOnArrayElement1.js +++ b/tests/baselines/reference/commentOnArrayElement1.js @@ -11,7 +11,7 @@ var array = [ var array = [ /* element 1*/ 1 - /* end of element 1 */ , + /* end of element 1 */, 2 /* end of element 2 */ ]; diff --git a/tests/baselines/reference/commentOnArrayElement3.js b/tests/baselines/reference/commentOnArrayElement3.js index e31f8adf26a..f19ef5d6050 100644 --- a/tests/baselines/reference/commentOnArrayElement3.js +++ b/tests/baselines/reference/commentOnArrayElement3.js @@ -12,8 +12,8 @@ var array = [ var array = [ /* element 1*/ 1 - /* end of element 1 */ , + /* end of element 1 */, 2 - /* end of element 2 */ , + /* end of element 2 */, , ]; diff --git a/tests/baselines/reference/commentOnBlock1.js b/tests/baselines/reference/commentOnBlock1.js index ed5437c1f66..20df3764b77 100644 --- a/tests/baselines/reference/commentOnBlock1.js +++ b/tests/baselines/reference/commentOnBlock1.js @@ -7,5 +7,5 @@ function f() { //// [commentOnBlock1.js] // asdf function f() { - /*asdf*/ { } + /*asdf*/{ } } diff --git a/tests/baselines/reference/commentsArgumentsOfCallExpression1.js b/tests/baselines/reference/commentsArgumentsOfCallExpression1.js index 4e6d693c5c2..f32e0bb8098 100644 --- a/tests/baselines/reference/commentsArgumentsOfCallExpression1.js +++ b/tests/baselines/reference/commentsArgumentsOfCallExpression1.js @@ -29,4 +29,4 @@ function () { }); foo(/*c7*/ function () { }); foo( /*c7*/ -/*c8*/ function () { }); +/*c8*/function () { }); diff --git a/tests/baselines/reference/commentsArgumentsOfCallExpression2.js b/tests/baselines/reference/commentsArgumentsOfCallExpression2.js index f89e67ef3d8..1e1079a4d22 100644 --- a/tests/baselines/reference/commentsArgumentsOfCallExpression2.js +++ b/tests/baselines/reference/commentsArgumentsOfCallExpression2.js @@ -17,7 +17,7 @@ foo(/*c2*/ 1, /*d2*/ 1 + 2, /*e1*/ a + b); foo(/*c3*/ function () { }, /*d2*/ function () { }, /*e2*/ a + /*e3*/ b); foo(/*c3*/ function () { }, /*d3*/ function () { }, /*e3*/ (a + b)); foo( -/*c4*/ function () { }, -/*d4*/ function () { }, +/*c4*/function () { }, +/*d4*/function () { }, /*e4*/ -/*e5*/ "hello"); +/*e5*/"hello"); diff --git a/tests/baselines/reference/commentsCommentParsing.js b/tests/baselines/reference/commentsCommentParsing.js index 889067a3c05..c39bf05e556 100644 --- a/tests/baselines/reference/commentsCommentParsing.js +++ b/tests/baselines/reference/commentsCommentParsing.js @@ -178,7 +178,7 @@ jsDocMultiLine(); *New line1 *New Line2*/ /** Shoul mege this line as well -* and this too*/ /** Another this one too*/ +* and this too*//** Another this one too*/ function jsDocMultiLineMerge() { } jsDocMultiLineMerge(); @@ -188,23 +188,23 @@ function jsDocMixedComments1() { } jsDocMixedComments1(); /// Triple slash comment -/** jsdoc comment */ /*** another jsDocComment*/ +/** jsdoc comment *//*** another jsDocComment*/ function jsDocMixedComments2() { } jsDocMixedComments2(); -/** jsdoc comment */ /*** another jsDocComment*/ +/** jsdoc comment *//*** another jsDocComment*/ /// Triple slash comment function jsDocMixedComments3() { } jsDocMixedComments3(); -/** jsdoc comment */ /*** another jsDocComment*/ +/** jsdoc comment *//*** another jsDocComment*/ /// Triple slash comment /// Triple slash comment 2 function jsDocMixedComments4() { } jsDocMixedComments4(); /// Triple slash comment 1 -/** jsdoc comment */ /*** another jsDocComment*/ +/** jsdoc comment *//*** another jsDocComment*/ /// Triple slash comment /// Triple slash comment 2 function jsDocMixedComments5() { diff --git a/tests/baselines/reference/commentsFunction.js b/tests/baselines/reference/commentsFunction.js index ad31aa47b91..a02ffb3b364 100644 --- a/tests/baselines/reference/commentsFunction.js +++ b/tests/baselines/reference/commentsFunction.js @@ -86,8 +86,8 @@ function blah3(a // trailing commen single line ) { } lambdaFoo = function (a, b) { return a * b; }; // This is trailing comment -/*leading comment*/ (function () { return 0; }); // Needs to be wrapped in parens to be a valid expression (not declaration) -/*leading comment*/ (function () { return 0; }); //trailing comment +/*leading comment*/(function () { return 0; }); // Needs to be wrapped in parens to be a valid expression (not declaration) +/*leading comment*/(function () { return 0; }); //trailing comment function blah4(/*1*/ a /*2*/, /*3*/ b /*4*/) { } function foo1() { diff --git a/tests/baselines/reference/commentsOnPropertyOfObjectLiteral1.js b/tests/baselines/reference/commentsOnPropertyOfObjectLiteral1.js index fa7790443ac..39190d9173a 100644 --- a/tests/baselines/reference/commentsOnPropertyOfObjectLiteral1.js +++ b/tests/baselines/reference/commentsOnPropertyOfObjectLiteral1.js @@ -18,7 +18,7 @@ var resolve = { id: /*! @ngInject */ function (details) { return details.id; }, id1: /* c1 */ "hello", id2: - /*! @ngInject */ function (details) { return details.id; }, + /*! @ngInject */function (details) { return details.id; }, id3: /*! @ngInject */ function (details) { return details.id; }, diff --git a/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnCallSignature.js b/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnCallSignature.js index 079a1e276fb..bcd87998f83 100644 --- a/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnCallSignature.js +++ b/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnCallSignature.js @@ -505,4 +505,4 @@ var r8b8 = b8 !== a8; var r8b9 = b9 !== a9; var r8b10 = b10 !== a10; var r8b11 = b11 !== a11; -//var r8b12 = b12 !== a12; +//var r8b12 = b12 !== a12; diff --git a/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnConstructorSignature.js b/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnConstructorSignature.js index 38097a936e3..1721f564865 100644 --- a/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnConstructorSignature.js +++ b/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnConstructorSignature.js @@ -431,4 +431,4 @@ var r8b6 = b6 !== a6; var r8b7 = b7 !== a7; var r8b8 = b8 !== a8; var r8b9 = b9 !== a9; -//var r8b10 = b10 !== a10; +//var r8b10 = b10 !== a10; diff --git a/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnInstantiatedCallSignature.js b/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnInstantiatedCallSignature.js index 87359ea0074..72dd4be0afc 100644 --- a/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnInstantiatedCallSignature.js +++ b/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnInstantiatedCallSignature.js @@ -320,4 +320,4 @@ var r8b3 = b3 !== a3; var r8b4 = b4 !== a4; var r8b5 = b5 !== a5; var r8b6 = b6 !== a6; -//var r8b7 = b7 !== a7; +//var r8b7 = b7 !== a7; diff --git a/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnInstantiatedConstructorSignature.js b/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnInstantiatedConstructorSignature.js index fcfbfa4bfbc..19183773406 100644 --- a/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnInstantiatedConstructorSignature.js +++ b/tests/baselines/reference/comparisonOperatorWithSubtypeObjectOnInstantiatedConstructorSignature.js @@ -320,4 +320,4 @@ var r8b3 = b3 !== a3; var r8b4 = b4 !== a4; var r8b5 = b5 !== a5; var r8b6 = b6 !== a6; -//var r8b7 = b7 !== a7; +//var r8b7 = b7 !== a7; diff --git a/tests/baselines/reference/concatError.js b/tests/baselines/reference/concatError.js index 67361719702..d2b30218e50 100644 --- a/tests/baselines/reference/concatError.js +++ b/tests/baselines/reference/concatError.js @@ -56,4 +56,4 @@ var c: C; var cc: C>; c = c.m(cc); -*/ +*/ diff --git a/tests/baselines/reference/errorSupression1.js b/tests/baselines/reference/errorSupression1.js index 2f467871434..4b635a0d660 100644 --- a/tests/baselines/reference/errorSupression1.js +++ b/tests/baselines/reference/errorSupression1.js @@ -17,4 +17,4 @@ var Foo = /** @class */ (function () { var baz = Foo.b; // Foo.b won't bind. baz.concat("y"); -// So we don't want an error on 'concat'. +// So we don't want an error on 'concat'. diff --git a/tests/baselines/reference/everyTypeAssignableToAny.js b/tests/baselines/reference/everyTypeAssignableToAny.js index 7f02badca00..fd71ec624be 100644 --- a/tests/baselines/reference/everyTypeAssignableToAny.js +++ b/tests/baselines/reference/everyTypeAssignableToAny.js @@ -117,4 +117,4 @@ function foo(x, y, z) { // a = x; // a = y; // a = z; -//} +//} diff --git a/tests/baselines/reference/functionConstraintSatisfaction.js b/tests/baselines/reference/functionConstraintSatisfaction.js index fc8a2be88a7..f24fd32aff6 100644 --- a/tests/baselines/reference/functionConstraintSatisfaction.js +++ b/tests/baselines/reference/functionConstraintSatisfaction.js @@ -108,4 +108,4 @@ function foo2(x, y) { //function foo2(x: T, y: U) { // foo(x); // foo(y); -//} +//} diff --git a/tests/baselines/reference/genericCallWithObjectTypeArgsAndNumericIndexer.js b/tests/baselines/reference/genericCallWithObjectTypeArgsAndNumericIndexer.js index f300e3a8093..27e4093d9c7 100644 --- a/tests/baselines/reference/genericCallWithObjectTypeArgsAndNumericIndexer.js +++ b/tests/baselines/reference/genericCallWithObjectTypeArgsAndNumericIndexer.js @@ -63,4 +63,4 @@ function other3(arg) { // var d = r2[1]; // // BUG 821629 // //var u: U = r2[1]; // ok -//} +//} diff --git a/tests/baselines/reference/genericCallWithObjectTypeArgsAndStringIndexer.js b/tests/baselines/reference/genericCallWithObjectTypeArgsAndStringIndexer.js index eee87caf3de..ee33746b152 100644 --- a/tests/baselines/reference/genericCallWithObjectTypeArgsAndStringIndexer.js +++ b/tests/baselines/reference/genericCallWithObjectTypeArgsAndStringIndexer.js @@ -64,4 +64,4 @@ function other3(arg) { // var d: Date = r2['hm']; // ok // // BUG 821629 // //var u: U = r2['hm']; // ok -//} +//} diff --git a/tests/baselines/reference/heterogeneousArrayLiterals.js b/tests/baselines/reference/heterogeneousArrayLiterals.js index 499aa7e7818..46dee284ae9 100644 --- a/tests/baselines/reference/heterogeneousArrayLiterals.js +++ b/tests/baselines/reference/heterogeneousArrayLiterals.js @@ -268,4 +268,4 @@ function foo4(t, u) { // var i = [u, base]; // Base[] // var j = [u, derived]; // Derived[] // var k: Base[] = [t, u]; -//} +//} diff --git a/tests/baselines/reference/innerTypeParameterShadowingOuterOne.js b/tests/baselines/reference/innerTypeParameterShadowingOuterOne.js index 74354468e32..f566bbdd878 100644 --- a/tests/baselines/reference/innerTypeParameterShadowingOuterOne.js +++ b/tests/baselines/reference/innerTypeParameterShadowingOuterOne.js @@ -54,4 +54,4 @@ function f2() { // } // var x: U; // x.getDate(); -//} +//} diff --git a/tests/baselines/reference/innerTypeParameterShadowingOuterOne2.js b/tests/baselines/reference/innerTypeParameterShadowingOuterOne2.js index 984584389f6..824061fce1f 100644 --- a/tests/baselines/reference/innerTypeParameterShadowingOuterOne2.js +++ b/tests/baselines/reference/innerTypeParameterShadowingOuterOne2.js @@ -75,4 +75,4 @@ var C2 = /** @class */ (function () { // var x: U; // x.getDate(); // } -//} +//} diff --git a/tests/baselines/reference/literalsInComputedProperties1.js b/tests/baselines/reference/literalsInComputedProperties1.js index c5b0060f626..4611925f2d4 100644 --- a/tests/baselines/reference/literalsInComputedProperties1.js +++ b/tests/baselines/reference/literalsInComputedProperties1.js @@ -89,4 +89,4 @@ var X; var a = X["foo"]; var a0 = X["bar"]; var _a; -// TODO: make sure that enum still disallow template literals as member names +// TODO: make sure that enum still disallow template literals as member names diff --git a/tests/baselines/reference/moduleIdentifiers.js b/tests/baselines/reference/moduleIdentifiers.js index 04d39019482..d3a654b8670 100644 --- a/tests/baselines/reference/moduleIdentifiers.js +++ b/tests/baselines/reference/moduleIdentifiers.js @@ -19,4 +19,4 @@ var M; //var m: M = M; var x1 = M.a; //var x2 = m.a; -//var q: m.P; +//var q: m.P; diff --git a/tests/baselines/reference/moduleResolutionWithExtensions.js b/tests/baselines/reference/moduleResolutionWithExtensions.js index c1e0310e995..3406bb0adae 100644 --- a/tests/baselines/reference/moduleResolutionWithExtensions.js +++ b/tests/baselines/reference/moduleResolutionWithExtensions.js @@ -28,11 +28,11 @@ import j from "./jquery.js" "use strict"; exports.__esModule = true; exports["default"] = 0; -// No extension: '.ts' added +// No extension: '.ts' added //// [b.js] "use strict"; exports.__esModule = true; -// '.js' extension: stripped and replaced with '.ts' +// '.js' extension: stripped and replaced with '.ts' //// [d.js] "use strict"; exports.__esModule = true; diff --git a/tests/baselines/reference/nullAssignableToEveryType.js b/tests/baselines/reference/nullAssignableToEveryType.js index f04ae865692..50914b366f8 100644 --- a/tests/baselines/reference/nullAssignableToEveryType.js +++ b/tests/baselines/reference/nullAssignableToEveryType.js @@ -84,4 +84,4 @@ function foo(x, y, z) { // x = null; // y = null; // z = null; -//} +//} diff --git a/tests/baselines/reference/parserSkippedTokens10.js b/tests/baselines/reference/parserSkippedTokens10.js index cfacb2e21bd..3af628a2e1e 100644 --- a/tests/baselines/reference/parserSkippedTokens10.js +++ b/tests/baselines/reference/parserSkippedTokens10.js @@ -5,4 +5,4 @@ //// [parserSkippedTokens10.js] -/*existing trivia*/ ; +/*existing trivia*/; diff --git a/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js b/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js index beff303c540..dbf4b6b27d1 100644 --- a/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js +++ b/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js @@ -78,4 +78,4 @@ declare module MsPortal.Controls.Base.ItemList { class ViewModel extends ItemValue { } } -*/ +*/ diff --git a/tests/baselines/reference/scannerS7.4_A2_T2.js b/tests/baselines/reference/scannerS7.4_A2_T2.js index 9cfc0b03bd8..4a446b520ad 100644 --- a/tests/baselines/reference/scannerS7.4_A2_T2.js +++ b/tests/baselines/reference/scannerS7.4_A2_T2.js @@ -26,4 +26,4 @@ */ /*CHECK#1/ - + diff --git a/tests/baselines/reference/sourceMap-Comment1.js b/tests/baselines/reference/sourceMap-Comment1.js index 071e54b5716..6f1f43cd8e2 100644 --- a/tests/baselines/reference/sourceMap-Comment1.js +++ b/tests/baselines/reference/sourceMap-Comment1.js @@ -2,5 +2,5 @@ // Comment //// [sourceMap-Comment1.js] -// Comment +// Comment //# sourceMappingURL=sourceMap-Comment1.js.map \ No newline at end of file diff --git a/tests/baselines/reference/sourceMap-Comment1.sourcemap.txt b/tests/baselines/reference/sourceMap-Comment1.sourcemap.txt index 4d427d1de89..e2f9174a45f 100644 --- a/tests/baselines/reference/sourceMap-Comment1.sourcemap.txt +++ b/tests/baselines/reference/sourceMap-Comment1.sourcemap.txt @@ -8,7 +8,7 @@ sources: sourceMap-Comment1.ts emittedFile:tests/cases/compiler/sourceMap-Comment1.js sourceFile:sourceMap-Comment1.ts ------------------------------------------------------------------- ->>>// Comment +>>>// Comment 1 > 2 >^^^^^^^^^^ 3 > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-> diff --git a/tests/baselines/reference/systemDefaultExportCommentValidity.js b/tests/baselines/reference/systemDefaultExportCommentValidity.js index a56110b0de9..45fe1df3ccd 100644 --- a/tests/baselines/reference/systemDefaultExportCommentValidity.js +++ b/tests/baselines/reference/systemDefaultExportCommentValidity.js @@ -14,7 +14,7 @@ System.register([], function (exports_1, context_1) { execute: function () { Home = {}; exports_1("default", Home); - // There is intentionally no semicolon on the prior line, this comment should not break emit + // There is intentionally no semicolon on the prior line, this comment should not break emit } }; }); diff --git a/tests/baselines/reference/systemModuleTrailingComments.js b/tests/baselines/reference/systemModuleTrailingComments.js index 41b0bd299a0..01f17d1facf 100644 --- a/tests/baselines/reference/systemModuleTrailingComments.js +++ b/tests/baselines/reference/systemModuleTrailingComments.js @@ -12,7 +12,7 @@ System.register([], function (exports_1, context_1) { setters: [], execute: function () { exports_1("test", test = "TEST"); - //some comment + //some comment } }; }); diff --git a/tests/baselines/reference/typeParameterUsedAsTypeParameterConstraint3.js b/tests/baselines/reference/typeParameterUsedAsTypeParameterConstraint3.js index 95c65d5f3a9..0655ad17138 100644 --- a/tests/baselines/reference/typeParameterUsedAsTypeParameterConstraint3.js +++ b/tests/baselines/reference/typeParameterUsedAsTypeParameterConstraint3.js @@ -64,4 +64,4 @@ interface I2 { // y: U; // z: V; // foo(x: W): T; -//} +//} diff --git a/tests/baselines/reference/undefinedAssignableToEveryType.js b/tests/baselines/reference/undefinedAssignableToEveryType.js index 507f647763a..de64f97f70b 100644 --- a/tests/baselines/reference/undefinedAssignableToEveryType.js +++ b/tests/baselines/reference/undefinedAssignableToEveryType.js @@ -83,4 +83,4 @@ function foo(x, y, z) { // x = undefined; // y = undefined; // z = undefined; -//} +//} From dcd2ddd0b71f6682c3d020ada0e9ac482b9b3d33 Mon Sep 17 00:00:00 2001 From: Yuval Greenfield Date: Tue, 26 Sep 2017 12:09:58 -0700 Subject: [PATCH 004/256] Yes space after multiline comments --- src/compiler/comments.ts | 3 +++ .../reference/baseIndexSignatureResolution.js | 2 +- .../reference/commentEmitWithCommentOnLastLine.js | 2 +- tests/baselines/reference/commentOnArrayElement1.js | 2 +- tests/baselines/reference/commentOnArrayElement3.js | 4 ++-- tests/baselines/reference/commentOnBlock1.js | 2 +- .../reference/commentsArgumentsOfCallExpression1.js | 2 +- .../reference/commentsArgumentsOfCallExpression2.js | 6 +++--- tests/baselines/reference/commentsCommentParsing.js | 10 +++++----- tests/baselines/reference/commentsFunction.js | 4 ++-- .../reference/commentsOnPropertyOfObjectLiteral1.js | 2 +- tests/baselines/reference/concatError.js | 2 +- tests/baselines/reference/parserSkippedTokens10.js | 2 +- .../recursivelySpecializedConstructorDeclaration.js | 2 +- tests/baselines/reference/scannerS7.4_A2_T2.js | 2 +- 15 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts index b936c0655e1..bb8ec9bf3e7 100644 --- a/src/compiler/comments.ts +++ b/src/compiler/comments.ts @@ -274,6 +274,9 @@ namespace ts { if (hasTrailingNewLine) { writer.writeLine(); } + else if (_kind === SyntaxKind.MultiLineCommentTrivia) { + writer.write(" "); + } } function emitLeadingCommentsOfPosition(pos: number) { diff --git a/tests/baselines/reference/baseIndexSignatureResolution.js b/tests/baselines/reference/baseIndexSignatureResolution.js index 3fdeecf78f6..4053e588e44 100644 --- a/tests/baselines/reference/baseIndexSignatureResolution.js +++ b/tests/baselines/reference/baseIndexSignatureResolution.js @@ -59,4 +59,4 @@ interface B extends A { } var b: B = null; var z: Derived = b.foo(); -*/ +*/ diff --git a/tests/baselines/reference/commentEmitWithCommentOnLastLine.js b/tests/baselines/reference/commentEmitWithCommentOnLastLine.js index 077286a7364..ffd4addb264 100644 --- a/tests/baselines/reference/commentEmitWithCommentOnLastLine.js +++ b/tests/baselines/reference/commentEmitWithCommentOnLastLine.js @@ -8,4 +8,4 @@ var bar; var x; /* var bar; -*/ +*/ diff --git a/tests/baselines/reference/commentOnArrayElement1.js b/tests/baselines/reference/commentOnArrayElement1.js index c93cf634096..960df336dbb 100644 --- a/tests/baselines/reference/commentOnArrayElement1.js +++ b/tests/baselines/reference/commentOnArrayElement1.js @@ -11,7 +11,7 @@ var array = [ var array = [ /* element 1*/ 1 - /* end of element 1 */, + /* end of element 1 */ , 2 /* end of element 2 */ ]; diff --git a/tests/baselines/reference/commentOnArrayElement3.js b/tests/baselines/reference/commentOnArrayElement3.js index f19ef5d6050..e31f8adf26a 100644 --- a/tests/baselines/reference/commentOnArrayElement3.js +++ b/tests/baselines/reference/commentOnArrayElement3.js @@ -12,8 +12,8 @@ var array = [ var array = [ /* element 1*/ 1 - /* end of element 1 */, + /* end of element 1 */ , 2 - /* end of element 2 */, + /* end of element 2 */ , , ]; diff --git a/tests/baselines/reference/commentOnBlock1.js b/tests/baselines/reference/commentOnBlock1.js index 20df3764b77..ed5437c1f66 100644 --- a/tests/baselines/reference/commentOnBlock1.js +++ b/tests/baselines/reference/commentOnBlock1.js @@ -7,5 +7,5 @@ function f() { //// [commentOnBlock1.js] // asdf function f() { - /*asdf*/{ } + /*asdf*/ { } } diff --git a/tests/baselines/reference/commentsArgumentsOfCallExpression1.js b/tests/baselines/reference/commentsArgumentsOfCallExpression1.js index f32e0bb8098..4e6d693c5c2 100644 --- a/tests/baselines/reference/commentsArgumentsOfCallExpression1.js +++ b/tests/baselines/reference/commentsArgumentsOfCallExpression1.js @@ -29,4 +29,4 @@ function () { }); foo(/*c7*/ function () { }); foo( /*c7*/ -/*c8*/function () { }); +/*c8*/ function () { }); diff --git a/tests/baselines/reference/commentsArgumentsOfCallExpression2.js b/tests/baselines/reference/commentsArgumentsOfCallExpression2.js index 1e1079a4d22..f89e67ef3d8 100644 --- a/tests/baselines/reference/commentsArgumentsOfCallExpression2.js +++ b/tests/baselines/reference/commentsArgumentsOfCallExpression2.js @@ -17,7 +17,7 @@ foo(/*c2*/ 1, /*d2*/ 1 + 2, /*e1*/ a + b); foo(/*c3*/ function () { }, /*d2*/ function () { }, /*e2*/ a + /*e3*/ b); foo(/*c3*/ function () { }, /*d3*/ function () { }, /*e3*/ (a + b)); foo( -/*c4*/function () { }, -/*d4*/function () { }, +/*c4*/ function () { }, +/*d4*/ function () { }, /*e4*/ -/*e5*/"hello"); +/*e5*/ "hello"); diff --git a/tests/baselines/reference/commentsCommentParsing.js b/tests/baselines/reference/commentsCommentParsing.js index c39bf05e556..889067a3c05 100644 --- a/tests/baselines/reference/commentsCommentParsing.js +++ b/tests/baselines/reference/commentsCommentParsing.js @@ -178,7 +178,7 @@ jsDocMultiLine(); *New line1 *New Line2*/ /** Shoul mege this line as well -* and this too*//** Another this one too*/ +* and this too*/ /** Another this one too*/ function jsDocMultiLineMerge() { } jsDocMultiLineMerge(); @@ -188,23 +188,23 @@ function jsDocMixedComments1() { } jsDocMixedComments1(); /// Triple slash comment -/** jsdoc comment *//*** another jsDocComment*/ +/** jsdoc comment */ /*** another jsDocComment*/ function jsDocMixedComments2() { } jsDocMixedComments2(); -/** jsdoc comment *//*** another jsDocComment*/ +/** jsdoc comment */ /*** another jsDocComment*/ /// Triple slash comment function jsDocMixedComments3() { } jsDocMixedComments3(); -/** jsdoc comment *//*** another jsDocComment*/ +/** jsdoc comment */ /*** another jsDocComment*/ /// Triple slash comment /// Triple slash comment 2 function jsDocMixedComments4() { } jsDocMixedComments4(); /// Triple slash comment 1 -/** jsdoc comment *//*** another jsDocComment*/ +/** jsdoc comment */ /*** another jsDocComment*/ /// Triple slash comment /// Triple slash comment 2 function jsDocMixedComments5() { diff --git a/tests/baselines/reference/commentsFunction.js b/tests/baselines/reference/commentsFunction.js index a02ffb3b364..ad31aa47b91 100644 --- a/tests/baselines/reference/commentsFunction.js +++ b/tests/baselines/reference/commentsFunction.js @@ -86,8 +86,8 @@ function blah3(a // trailing commen single line ) { } lambdaFoo = function (a, b) { return a * b; }; // This is trailing comment -/*leading comment*/(function () { return 0; }); // Needs to be wrapped in parens to be a valid expression (not declaration) -/*leading comment*/(function () { return 0; }); //trailing comment +/*leading comment*/ (function () { return 0; }); // Needs to be wrapped in parens to be a valid expression (not declaration) +/*leading comment*/ (function () { return 0; }); //trailing comment function blah4(/*1*/ a /*2*/, /*3*/ b /*4*/) { } function foo1() { diff --git a/tests/baselines/reference/commentsOnPropertyOfObjectLiteral1.js b/tests/baselines/reference/commentsOnPropertyOfObjectLiteral1.js index 39190d9173a..fa7790443ac 100644 --- a/tests/baselines/reference/commentsOnPropertyOfObjectLiteral1.js +++ b/tests/baselines/reference/commentsOnPropertyOfObjectLiteral1.js @@ -18,7 +18,7 @@ var resolve = { id: /*! @ngInject */ function (details) { return details.id; }, id1: /* c1 */ "hello", id2: - /*! @ngInject */function (details) { return details.id; }, + /*! @ngInject */ function (details) { return details.id; }, id3: /*! @ngInject */ function (details) { return details.id; }, diff --git a/tests/baselines/reference/concatError.js b/tests/baselines/reference/concatError.js index d2b30218e50..67361719702 100644 --- a/tests/baselines/reference/concatError.js +++ b/tests/baselines/reference/concatError.js @@ -56,4 +56,4 @@ var c: C; var cc: C>; c = c.m(cc); -*/ +*/ diff --git a/tests/baselines/reference/parserSkippedTokens10.js b/tests/baselines/reference/parserSkippedTokens10.js index 3af628a2e1e..cfacb2e21bd 100644 --- a/tests/baselines/reference/parserSkippedTokens10.js +++ b/tests/baselines/reference/parserSkippedTokens10.js @@ -5,4 +5,4 @@ //// [parserSkippedTokens10.js] -/*existing trivia*/; +/*existing trivia*/ ; diff --git a/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js b/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js index dbf4b6b27d1..beff303c540 100644 --- a/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js +++ b/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js @@ -78,4 +78,4 @@ declare module MsPortal.Controls.Base.ItemList { class ViewModel extends ItemValue { } } -*/ +*/ diff --git a/tests/baselines/reference/scannerS7.4_A2_T2.js b/tests/baselines/reference/scannerS7.4_A2_T2.js index 4a446b520ad..9cfc0b03bd8 100644 --- a/tests/baselines/reference/scannerS7.4_A2_T2.js +++ b/tests/baselines/reference/scannerS7.4_A2_T2.js @@ -26,4 +26,4 @@ */ /*CHECK#1/ - + From 405d8cf8ebd3f6c9c2a5f7e19c2a687235ec0a18 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 9 Oct 2017 10:45:50 -0700 Subject: [PATCH 005/256] In getSuggestionForNonexistentSymbol, guard name against undefined --- src/compiler/checker.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a8e18c432a6..738a484d254 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15064,7 +15064,10 @@ namespace ts { function getSuggestionForNonexistentSymbol(location: Node, name: __String, meaning: SymbolFlags): string { const result = resolveNameHelper(location, name, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ false, (symbols, name, meaning) => { - // `name` from the callback === the outer `name` + // NOTE: `name` from the callback is supposed to === the outer `name`, but is undefined in some cases + if (name === undefined) { + return undefined; + } const symbol = getSymbol(symbols, name, meaning); // Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function // So the table *contains* `x` but `x` isn't actually in scope. From 1cb2d24c5d218a8119655d584bd61d749b18dec2 Mon Sep 17 00:00:00 2001 From: Armando Aguirre Date: Thu, 12 Oct 2017 17:18:38 -0700 Subject: [PATCH 006/256] Added DefinitionAndBoundSpan command --- src/harness/harnessLanguageService.ts | 3 +++ src/harness/unittests/session.ts | 5 +++-- src/server/client.ts | 6 +++++- src/server/protocol.ts | 2 ++ src/server/session.ts | 20 +++++++++++++++++-- src/services/services.ts | 14 +++++++++++-- src/services/types.ts | 1 + .../reference/api/tsserverlibrary.d.ts | 18 +++++++++-------- tests/baselines/reference/api/typescript.d.ts | 7 ++++--- 9 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index ad79c96d833..34043195429 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -490,6 +490,9 @@ namespace Harness.LanguageService { getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan { return unwrapJSONCallResult(this.shim.getSpanOfEnclosingComment(fileName, position, onlyMultiLine)); } + getSpanForPosition(): ts.TextSpan { + throw new Error("Not supportred on the shim."); + } getCodeFixesAtPosition(): ts.CodeAction[] { throw new Error("Not supported on the shim."); } diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index 3b5efc2d6de..2ce5ef530e4 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -117,7 +117,7 @@ namespace ts.server { body: undefined }); }); - it ("should handle literal types in request", () => { + it("should handle literal types in request", () => { const configureRequest: protocol.ConfigureRequest = { command: CommandNames.Configure, seq: 0, @@ -175,6 +175,7 @@ namespace ts.server { CommandNames.Configure, CommandNames.Definition, CommandNames.DefinitionFull, + CommandNames.DefinitionAndBoundSpan, CommandNames.Implementation, CommandNames.ImplementationFull, CommandNames.Exit, @@ -341,7 +342,7 @@ namespace ts.server { session.addProtocolHandler(command, () => resp); expect(() => session.addProtocolHandler(command, () => resp)) - .to.throw(`Protocol handler already exists for command "${command}"`); + .to.throw(`Protocol handler already exists for command "${command}"`); }); }); diff --git a/src/server/client.ts b/src/server/client.ts index d08d1e13d2e..f467f7f9224 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -322,7 +322,7 @@ namespace ts.server { } getSyntacticDiagnostics(file: string): Diagnostic[] { - const args: protocol.SyntacticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true }; + const args: protocol.SyntacticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true }; const request = this.processRequest(CommandNames.SyntacticDiagnosticsSync, args); const response = this.processResponse(request); @@ -531,6 +531,10 @@ namespace ts.server { return notImplemented(); } + getSpanForPosition(_fileName: string, _position: number): TextSpan { + return notImplemented(); + } + getCodeFixesAtPosition(file: string, start: number, end: number, errorCodes: number[]): CodeAction[] { const args: protocol.CodeFixRequestArgs = { ...this.createFileRangeRequestArgs(file, start, end), errorCodes }; diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 3d07392bbe6..0685728c3b0 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -21,6 +21,8 @@ namespace ts.server.protocol { Definition = "definition", /* @internal */ DefinitionFull = "definition-full", + /* @internal */ + DefinitionAndBoundSpan = "definitionAndBoundSpan", Implementation = "implementation", /* @internal */ ImplementationFull = "implementation-full", diff --git a/src/server/session.ts b/src/server/session.ts index 800d09ff6c2..5a8426f23b3 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -167,7 +167,7 @@ namespace ts.server { private timerHandle: any; private immediateId: number | undefined; - constructor(private readonly operationHost: MultistepOperationHost) {} + constructor(private readonly operationHost: MultistepOperationHost) { } public startNew(action: (next: NextStep) => void) { this.complete(); @@ -579,7 +579,7 @@ namespace ts.server { private getDiagnosticsWorker( args: protocol.FileRequestArgs, isSemantic: boolean, selector: (project: Project, file: string) => ReadonlyArray, includeLinePosition: boolean - ): ReadonlyArray | ReadonlyArray { + ): ReadonlyArray | ReadonlyArray { const { project, file } = this.getFileAndProject(args); if (isSemantic && isDeclarationFileInJSOnlyNonConfiguredProject(project, file)) { return emptyArray; @@ -1081,6 +1081,13 @@ namespace ts.server { } } + private getSpanForLocation(args: protocol.FileLocationRequestArgs): TextSpan { + const { file, project } = this.getFileAndProject(args); + const scriptInfo = project.getScriptInfoForNormalizedPath(file); + + return project.getLanguageService().getSpanForPosition(file, this.getPosition(args, scriptInfo)); + } + private getFormattingEditsForRange(args: protocol.FormatRequestArgs): protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file); @@ -1707,6 +1714,15 @@ namespace ts.server { [CommandNames.DefinitionFull]: (request: protocol.DefinitionRequest) => { return this.requiredResponse(this.getDefinition(request.arguments, /*simplifiedResult*/ false)); }, + [CommandNames.DefinitionAndBoundSpan]: (request: protocol.DefinitionRequest) => { + const definitions = this.getDefinition(request.arguments, /*simplifiedResult*/ false); + const textSpan = definitions.length !== 0 ? this.getSpanForLocation(request.arguments) : {}; + + return this.requiredResponse({ + definitions, + textSpan + }); + }, [CommandNames.TypeDefinition]: (request: protocol.FileLocationRequest) => { return this.requiredResponse(this.getTypeDefinition(request.arguments)); }, diff --git a/src/services/services.ts b/src/services/services.ts index 6bdc96d8b4d..5b24fa1947e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -724,9 +724,9 @@ namespace ts { case SyntaxKind.BinaryExpression: if (getSpecialPropertyAssignmentKind(node as BinaryExpression) !== SpecialPropertyAssignmentKind.None) { - addDeclaration(node as BinaryExpression); + addDeclaration(node as BinaryExpression); } - // falls through + // falls through default: forEachChild(node, visit); @@ -1807,6 +1807,15 @@ namespace ts { return range && createTextSpanFromRange(range); } + function getSpanForPosition(fileName: string, position: number): TextSpan { + synchronizeHostData(); + + const sourceFile = getValidSourceFile(fileName); + const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocCcomment*/ false); + + return createTextSpan(node.getStart(), node.getWidth()); + } + function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] { // Note: while getting todo comments seems like a syntactic operation, we actually // treat it as a semantic operation here. This is because we expect our host to call @@ -2032,6 +2041,7 @@ namespace ts { getDocCommentTemplateAtPosition, isValidBraceCompletionAtPosition, getSpanOfEnclosingComment, + getSpanForPosition, getCodeFixesAtPosition, getEmitOutput, getNonBoundSourceFile, diff --git a/src/services/types.ts b/src/services/types.ts index e853eb7b96c..034b45100e0 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -273,6 +273,7 @@ namespace ts { isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan; + getSpanForPosition(fileName: string, position: number): TextSpan; getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 151c948602d..1cf429546de 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -44,9 +44,9 @@ declare namespace ts { value: T; done: false; } | { - value: never; - done: true; - }; + value: never; + done: true; + }; } /** Array that is only intended to be pushed to, never read. */ interface Push { @@ -3942,6 +3942,7 @@ declare namespace ts { getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion; isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan; + getSpanForPosition(fileName: string, position: number): TextSpan; getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined; @@ -4609,12 +4610,12 @@ declare namespace ts.server { module: {}; error: undefined; } | { - module: undefined; - error: { - stack?: string; - message?: string; + module: undefined; + error: { + stack?: string; + message?: string; + }; }; - }; interface ServerHost extends System { setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any; clearTimeout(timeoutId: any): void; @@ -6887,6 +6888,7 @@ declare namespace ts.server { private getNameOrDottedNameSpan(args); private isValidBraceCompletion(args); private getQuickInfoWorker(args, simplifiedResult); + private getSpanForLocation(args); private getFormattingEditsForRange(args); private getFormattingEditsForRangeFull(args); private getFormattingEditsForDocumentFull(args); diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 14fae7d0d77..8350b2d7a9d 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -44,9 +44,9 @@ declare namespace ts { value: T; done: false; } | { - value: never; - done: true; - }; + value: never; + done: true; + }; } /** Array that is only intended to be pushed to, never read. */ interface Push { @@ -3942,6 +3942,7 @@ declare namespace ts { getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion; isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan; + getSpanForPosition(fileName: string, position: number): TextSpan; getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined; From c6a8a32b710a3c8c3581c1792e7858c97e22318a Mon Sep 17 00:00:00 2001 From: Armando Aguirre Date: Fri, 13 Oct 2017 16:36:25 -0700 Subject: [PATCH 007/256] Fixed api reference tests --- .../baselines/reference/api/tsserverlibrary.d.ts | 16 ++++++++-------- tests/baselines/reference/api/typescript.d.ts | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 1cf429546de..8beb5ff60e4 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -44,9 +44,9 @@ declare namespace ts { value: T; done: false; } | { - value: never; - done: true; - }; + value: never; + done: true; + }; } /** Array that is only intended to be pushed to, never read. */ interface Push { @@ -4610,12 +4610,12 @@ declare namespace ts.server { module: {}; error: undefined; } | { - module: undefined; - error: { - stack?: string; - message?: string; - }; + module: undefined; + error: { + stack?: string; + message?: string; }; + }; interface ServerHost extends System { setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any; clearTimeout(timeoutId: any): void; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 8350b2d7a9d..2733bb20e56 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -44,9 +44,9 @@ declare namespace ts { value: T; done: false; } | { - value: never; - done: true; - }; + value: never; + done: true; + }; } /** Array that is only intended to be pushed to, never read. */ interface Push { From 5e7bfad2a7c8e44c66b4599c187a738834d7dc4d Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 16 Oct 2017 09:19:46 -0700 Subject: [PATCH 008/256] Check own-constructor in abstract prop access error --- src/compiler/checker.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 32086157552..549b759b225 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14906,12 +14906,11 @@ namespace ts { } } - // Referencing Abstract Properties within Constructors is not allowed + // Referencing abstract properties within their own constructors is not allowed if ((flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop)) { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)); - - if (declaringClassDeclaration && isNodeWithinConstructor(node, declaringClassDeclaration)) { - error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), typeToString(getDeclaringClass(prop))); + if (declaringClassDeclaration && isNodeWithinConstructorOfClass(node, declaringClassDeclaration)) { + error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name)); return false; } } @@ -23227,9 +23226,9 @@ namespace ts { return result; } - function isNodeWithinConstructor(node: Node, classDeclaration: ClassLikeDeclaration) { + function isNodeWithinConstructorOfClass(node: Node, classDeclaration: ClassLikeDeclaration) { return findAncestor(node, element => { - if (isConstructorDeclaration(element) && nodeIsPresent(element.body)) { + if (isConstructorDeclaration(element) && nodeIsPresent(element.body) && element.parent === classDeclaration) { return true; } else if (element === classDeclaration || isFunctionLikeDeclaration(element)) { From fb45b49afcbc1182f4524703221f8bfe573a5de9 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 16 Oct 2017 09:20:28 -0700 Subject: [PATCH 009/256] Test:abstract prop access in non-declaring ctor --- .../abstractPropertyInConstructor.errors.txt | 9 +++++ .../abstractPropertyInConstructor.js | 18 ++++++++++ .../abstractPropertyInConstructor.symbols | 29 ++++++++++++++++ .../abstractPropertyInConstructor.types | 34 +++++++++++++++++++ .../compiler/abstractPropertyInConstructor.ts | 9 +++++ 5 files changed, 99 insertions(+) diff --git a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt index 461dd713d3b..63636b35725 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt +++ b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt @@ -34,4 +34,13 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr this.prop = this.prop + "!"; } } + + class User { + constructor(a: AbstractClass) { + a.prop; + a.cb("hi"); + a.method(12); + a.method2(); + } + } \ No newline at end of file diff --git a/tests/baselines/reference/abstractPropertyInConstructor.js b/tests/baselines/reference/abstractPropertyInConstructor.js index 18a2937a191..5bf9726b283 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.js +++ b/tests/baselines/reference/abstractPropertyInConstructor.js @@ -23,6 +23,15 @@ abstract class AbstractClass { this.prop = this.prop + "!"; } } + +class User { + constructor(a: AbstractClass) { + a.prop; + a.cb("hi"); + a.method(12); + a.method2(); + } +} //// [abstractPropertyInConstructor.js] @@ -44,3 +53,12 @@ var AbstractClass = /** @class */ (function () { }; return AbstractClass; }()); +var User = /** @class */ (function () { + function User(a) { + a.prop; + a.cb("hi"); + a.method(12); + a.method2(); + } + return User; +}()); diff --git a/tests/baselines/reference/abstractPropertyInConstructor.symbols b/tests/baselines/reference/abstractPropertyInConstructor.symbols index 0d542ffb0a8..f6e29a58487 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.symbols +++ b/tests/baselines/reference/abstractPropertyInConstructor.symbols @@ -68,3 +68,32 @@ abstract class AbstractClass { } } +class User { +>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 23, 1)) + + constructor(a: AbstractClass) { +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) +>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) + + a.prop; +>a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) + + a.cb("hi"); +>a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) +>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) + + a.method(12); +>a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) + + a.method2(); +>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) +>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39)) + } +} + diff --git a/tests/baselines/reference/abstractPropertyInConstructor.types b/tests/baselines/reference/abstractPropertyInConstructor.types index 0ffb5f1bdfd..a44403c1091 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.types +++ b/tests/baselines/reference/abstractPropertyInConstructor.types @@ -79,3 +79,37 @@ abstract class AbstractClass { } } +class User { +>User : User + + constructor(a: AbstractClass) { +>a : AbstractClass +>AbstractClass : AbstractClass + + a.prop; +>a.prop : string +>a : AbstractClass +>prop : string + + a.cb("hi"); +>a.cb("hi") : void +>a.cb : (s: string) => void +>a : AbstractClass +>cb : (s: string) => void +>"hi" : "hi" + + a.method(12); +>a.method(12) : void +>a.method : (num: number) => void +>a : AbstractClass +>method : (num: number) => void +>12 : 12 + + a.method2(); +>a.method2() : void +>a.method2 : () => void +>a : AbstractClass +>method2 : () => void + } +} + diff --git a/tests/cases/compiler/abstractPropertyInConstructor.ts b/tests/cases/compiler/abstractPropertyInConstructor.ts index 457fdb473b1..e58e052f8db 100644 --- a/tests/cases/compiler/abstractPropertyInConstructor.ts +++ b/tests/cases/compiler/abstractPropertyInConstructor.ts @@ -22,3 +22,12 @@ abstract class AbstractClass { this.prop = this.prop + "!"; } } + +class User { + constructor(a: AbstractClass) { + a.prop; + a.cb("hi"); + a.method(12); + a.method2(); + } +} From 49beac919cdaa6167653722e454e5acd2c041a87 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 16 Oct 2017 09:43:49 -0700 Subject: [PATCH 010/256] Abstract property access error only on this access --- src/compiler/checker.ts | 2 +- src/compiler/utilities.ts | 13 ++- .../abstractPropertyInConstructor.errors.txt | 6 +- .../abstractPropertyInConstructor.js | 11 ++- .../abstractPropertyInConstructor.symbols | 84 +++++++++++-------- .../abstractPropertyInConstructor.types | 15 +++- .../compiler/abstractPropertyInConstructor.ts | 6 +- 7 files changed, 93 insertions(+), 44 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 549b759b225..3c36a85e5d2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -14907,7 +14907,7 @@ namespace ts { } // Referencing abstract properties within their own constructors is not allowed - if ((flags & ModifierFlags.Abstract) && symbolHasNonMethodDeclaration(prop)) { + if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) { const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)); if (declaringClassDeclaration && isNodeWithinConstructorOfClass(node, declaringClassDeclaration)) { error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name)); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c4d3de453ba..c29c6c45c89 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1121,7 +1121,7 @@ namespace ts { } /** - * Determines whether a node is a property or element access expression for super. + * Determines whether a node is a property or element access expression for `super`. */ export function isSuperProperty(node: Node): node is SuperProperty { const kind = node.kind; @@ -1129,7 +1129,16 @@ namespace ts { && (node).expression.kind === SyntaxKind.SuperKeyword; } - export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression { + /** + * Determines whether a node is a property or element access expression for `this`. + */ + export function isThisProperty(node: Node): boolean { + const kind = node.kind; + return (kind === SyntaxKind.PropertyAccessExpression || kind === SyntaxKind.ElementAccessExpression) + && (node).expression.kind === SyntaxKind.ThisKeyword; + } + + export function getEntityNameFromTypeNode(node: TypeNode): EntityNameOrEntityNameExpression { switch (node.kind) { case SyntaxKind.TypeReference: return (node).typeName; diff --git a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt index 63636b35725..0798d91ce78 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.errors.txt +++ b/tests/baselines/reference/abstractPropertyInConstructor.errors.txt @@ -5,7 +5,7 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr ==== tests/cases/compiler/abstractPropertyInConstructor.ts (3 errors) ==== abstract class AbstractClass { - constructor(str: string) { + constructor(str: string, other: AbstractClass) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); ~~~~ @@ -20,9 +20,13 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstr ~~ !!! error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor. + // OK, reference is inside function const innerFunction = () => { return this.prop; } + + // OK, references are to another instance + other.cb(other.prop); } abstract prop: string; diff --git a/tests/baselines/reference/abstractPropertyInConstructor.js b/tests/baselines/reference/abstractPropertyInConstructor.js index 5bf9726b283..5a4feda110f 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.js +++ b/tests/baselines/reference/abstractPropertyInConstructor.js @@ -1,6 +1,6 @@ //// [abstractPropertyInConstructor.ts] abstract class AbstractClass { - constructor(str: string) { + constructor(str: string, other: AbstractClass) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); @@ -9,9 +9,13 @@ abstract class AbstractClass { } this.cb(str); + // OK, reference is inside function const innerFunction = () => { return this.prop; } + + // OK, references are to another instance + other.cb(other.prop); } abstract prop: string; @@ -36,7 +40,7 @@ class User { //// [abstractPropertyInConstructor.js] var AbstractClass = /** @class */ (function () { - function AbstractClass(str) { + function AbstractClass(str, other) { var _this = this; this.method(parseInt(str)); var val = this.prop.toLowerCase(); @@ -44,9 +48,12 @@ var AbstractClass = /** @class */ (function () { this.prop = "Hello World"; } this.cb(str); + // OK, reference is inside function var innerFunction = function () { return _this.prop; }; + // OK, references are to another instance + other.cb(other.prop); } AbstractClass.prototype.method2 = function () { this.prop = this.prop + "!"; diff --git a/tests/baselines/reference/abstractPropertyInConstructor.symbols b/tests/baselines/reference/abstractPropertyInConstructor.symbols index f6e29a58487..42cd3bb6827 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.symbols +++ b/tests/baselines/reference/abstractPropertyInConstructor.symbols @@ -2,98 +2,110 @@ abstract class AbstractClass { >AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) - constructor(str: string) { + constructor(str: string, other: AbstractClass) { >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) +>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 1, 28)) +>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) this.method(parseInt(str)); ->this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) +>this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) >parseInt : Symbol(parseInt, Decl(lib.d.ts, --, --)) >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) let val = this.prop.toLowerCase(); >val : Symbol(val, Decl(abstractPropertyInConstructor.ts, 3, 11)) >this.prop.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) if (!str) { >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) this.prop = "Hello World"; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) } this.cb(str); ->this.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) +>this.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) +>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) >str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 1, 16)) + // OK, reference is inside function const innerFunction = () => { ->innerFunction : Symbol(innerFunction, Decl(abstractPropertyInConstructor.ts, 10, 13)) +>innerFunction : Symbol(innerFunction, Decl(abstractPropertyInConstructor.ts, 11, 13)) return this.prop; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) } + + // OK, references are to another instance + other.cb(other.prop); +>other.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) +>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 1, 28)) +>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) +>other.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) +>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 1, 28)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) } abstract prop: string; ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) abstract cb: (s: string) => void; ->cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) ->s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 16, 18)) +>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) +>s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 20, 18)) abstract method(num: number): void; ->method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) ->num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 18, 20)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) +>num : Symbol(num, Decl(abstractPropertyInConstructor.ts, 22, 20)) method2() { ->method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39)) +>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39)) this.prop = this.prop + "!"; ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) ->this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) +>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) >this : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) } } class User { ->User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 23, 1)) +>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 27, 1)) constructor(a: AbstractClass) { ->a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) >AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0)) a.prop; ->a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) ->a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) ->prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 13, 5)) +>a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) +>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5)) a.cb("hi"); ->a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) ->a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) ->cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 15, 26)) +>a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) +>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26)) a.method(12); ->a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) ->a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) ->method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 16, 37)) +>a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) +>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37)) a.method2(); ->a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39)) ->a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 26, 16)) ->method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 18, 39)) +>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39)) +>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 30, 16)) +>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 22, 39)) } } diff --git a/tests/baselines/reference/abstractPropertyInConstructor.types b/tests/baselines/reference/abstractPropertyInConstructor.types index a44403c1091..6f8970a7702 100644 --- a/tests/baselines/reference/abstractPropertyInConstructor.types +++ b/tests/baselines/reference/abstractPropertyInConstructor.types @@ -2,8 +2,10 @@ abstract class AbstractClass { >AbstractClass : AbstractClass - constructor(str: string) { + constructor(str: string, other: AbstractClass) { >str : string +>other : AbstractClass +>AbstractClass : AbstractClass this.method(parseInt(str)); >this.method(parseInt(str)) : void @@ -41,6 +43,7 @@ abstract class AbstractClass { >cb : (s: string) => void >str : string + // OK, reference is inside function const innerFunction = () => { >innerFunction : () => string >() => { return this.prop; } : () => string @@ -50,6 +53,16 @@ abstract class AbstractClass { >this : this >prop : string } + + // OK, references are to another instance + other.cb(other.prop); +>other.cb(other.prop) : void +>other.cb : (s: string) => void +>other : AbstractClass +>cb : (s: string) => void +>other.prop : string +>other : AbstractClass +>prop : string } abstract prop: string; diff --git a/tests/cases/compiler/abstractPropertyInConstructor.ts b/tests/cases/compiler/abstractPropertyInConstructor.ts index e58e052f8db..b8386f56e1e 100644 --- a/tests/cases/compiler/abstractPropertyInConstructor.ts +++ b/tests/cases/compiler/abstractPropertyInConstructor.ts @@ -1,5 +1,5 @@ abstract class AbstractClass { - constructor(str: string) { + constructor(str: string, other: AbstractClass) { this.method(parseInt(str)); let val = this.prop.toLowerCase(); @@ -8,9 +8,13 @@ abstract class AbstractClass { } this.cb(str); + // OK, reference is inside function const innerFunction = () => { return this.prop; } + + // OK, references are to another instance + other.cb(other.prop); } abstract prop: string; From b86153da8806a0b9ee7aaa76cc549ee37b2dc3bc Mon Sep 17 00:00:00 2001 From: Armando Aguirre Date: Mon, 16 Oct 2017 17:50:35 -0700 Subject: [PATCH 011/256] Changed command designed based on review input --- src/harness/harnessLanguageService.ts | 6 +- src/harness/unittests/session.ts | 1 + src/server/client.ts | 8 +-- src/server/protocol.ts | 8 ++- src/server/session.ts | 71 +++++++++++++------ src/services/services.ts | 25 ++++--- src/services/types.ts | 7 +- .../reference/api/tsserverlibrary.d.ts | 15 +++- tests/baselines/reference/api/typescript.d.ts | 6 +- 9 files changed, 103 insertions(+), 44 deletions(-) diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 34043195429..2ec40a8981d 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -432,6 +432,9 @@ namespace Harness.LanguageService { getDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] { return unwrapJSONCallResult(this.shim.getDefinitionAtPosition(fileName, position)); } + getDefinitionAndBoundSpan(): ts.DefinitionInfoAndBoundSpan { + throw new Error("Not supported on the shim."); + } getTypeDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] { return unwrapJSONCallResult(this.shim.getTypeDefinitionAtPosition(fileName, position)); } @@ -490,9 +493,6 @@ namespace Harness.LanguageService { getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): ts.TextSpan { return unwrapJSONCallResult(this.shim.getSpanOfEnclosingComment(fileName, position, onlyMultiLine)); } - getSpanForPosition(): ts.TextSpan { - throw new Error("Not supportred on the shim."); - } getCodeFixesAtPosition(): ts.CodeAction[] { throw new Error("Not supported on the shim."); } diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index 2ce5ef530e4..fd278dc3c3a 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -176,6 +176,7 @@ namespace ts.server { CommandNames.Definition, CommandNames.DefinitionFull, CommandNames.DefinitionAndBoundSpan, + CommandNames.DefinitionAndBoundSpanFull, CommandNames.Implementation, CommandNames.ImplementationFull, CommandNames.Exit, diff --git a/src/server/client.ts b/src/server/client.ts index f467f7f9224..0fe5f48ed31 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -268,6 +268,10 @@ namespace ts.server { })); } + getDefinitionAndBoundSpan(_fileName: string, _position: number): DefinitionInfoAndBoundSpan { + return notImplemented(); + } + getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { const args: protocol.FileLocationRequestArgs = this.createFileLocationRequestArgs(fileName, position); @@ -531,10 +535,6 @@ namespace ts.server { return notImplemented(); } - getSpanForPosition(_fileName: string, _position: number): TextSpan { - return notImplemented(); - } - getCodeFixesAtPosition(file: string, start: number, end: number, errorCodes: number[]): CodeAction[] { const args: protocol.CodeFixRequestArgs = { ...this.createFileRangeRequestArgs(file, start, end), errorCodes }; diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 0685728c3b0..327c351ba6f 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -21,8 +21,9 @@ namespace ts.server.protocol { Definition = "definition", /* @internal */ DefinitionFull = "definition-full", - /* @internal */ DefinitionAndBoundSpan = "definitionAndBoundSpan", + /* @internal */ + DefinitionAndBoundSpanFull = "definitionAndBoundSpan-full", Implementation = "implementation", /* @internal */ ImplementationFull = "implementation-full", @@ -690,6 +691,11 @@ namespace ts.server.protocol { file: string; } + export interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } + /** * Definition response message. Gives text range for definition. */ diff --git a/src/server/session.ts b/src/server/session.ts index 5a8426f23b3..54ac3082c18 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -601,20 +601,57 @@ namespace ts.server { } if (simplifiedResult) { - return definitions.map(def => { - const defScriptInfo = project.getScriptInfo(def.fileName); - return { - file: def.fileName, - start: defScriptInfo.positionToLineOffset(def.textSpan.start), - end: defScriptInfo.positionToLineOffset(textSpanEnd(def.textSpan)) - }; - }); + return this.getSimplifiedDefinition(definitions, project); } else { return definitions; } } + private getDefinitionAndBoundSpan(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.DefinitionInfoAndBoundSpan | DefinitionInfoAndBoundSpan { + const { file, project } = this.getFileAndProject(args); + const position = this.getPositionInFile(args, file); + const scriptInfo = project.getScriptInfo(file); + + const definitionAndBoundSpan = project.getLanguageService().getDefinitionAndBoundSpan(file, position); + + if (!definitionAndBoundSpan || !definitionAndBoundSpan.definitions) { + return { + definitions: emptyArray, + textSpan: undefined + }; + } + + if (simplifiedResult) { + return { + definitions: this.getSimplifiedDefinition(definitionAndBoundSpan.definitions, project), + textSpan: this.getSimplifiedTextSpan(definitionAndBoundSpan.textSpan, scriptInfo) + }; + } + + return definitionAndBoundSpan; + } + + private getSimplifiedDefinition(definitions: ReadonlyArray, project: Project): ReadonlyArray { + return definitions.map(def => { + const defScriptInfo = project.getScriptInfo(def.fileName); + const simplifiedTextSpan = this.getSimplifiedTextSpan(def.textSpan, defScriptInfo); + + return { + file: def.fileName, + start: simplifiedTextSpan.start, + end: simplifiedTextSpan.end + }; + }); + } + + private getSimplifiedTextSpan(textSpan: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan { + return { + start: scriptInfo.positionToLineOffset(textSpan.start), + end: scriptInfo.positionToLineOffset(textSpanEnd(textSpan)) + }; + } + private getTypeDefinition(args: protocol.FileLocationRequestArgs): ReadonlyArray { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); @@ -1081,13 +1118,6 @@ namespace ts.server { } } - private getSpanForLocation(args: protocol.FileLocationRequestArgs): TextSpan { - const { file, project } = this.getFileAndProject(args); - const scriptInfo = project.getScriptInfoForNormalizedPath(file); - - return project.getLanguageService().getSpanForPosition(file, this.getPosition(args, scriptInfo)); - } - private getFormattingEditsForRange(args: protocol.FormatRequestArgs): protocol.CodeEdit[] { const { file, languageService } = this.getFileAndLanguageServiceForSyntacticOperation(args); const scriptInfo = this.projectService.getScriptInfoForNormalizedPath(file); @@ -1715,13 +1745,10 @@ namespace ts.server { return this.requiredResponse(this.getDefinition(request.arguments, /*simplifiedResult*/ false)); }, [CommandNames.DefinitionAndBoundSpan]: (request: protocol.DefinitionRequest) => { - const definitions = this.getDefinition(request.arguments, /*simplifiedResult*/ false); - const textSpan = definitions.length !== 0 ? this.getSpanForLocation(request.arguments) : {}; - - return this.requiredResponse({ - definitions, - textSpan - }); + return this.requiredResponse(this.getDefinitionAndBoundSpan(request.arguments, /*simplifiedResult*/ true)); + }, + [CommandNames.DefinitionAndBoundSpanFull]: (request: protocol.DefinitionRequest) => { + return this.requiredResponse(this.getDefinitionAndBoundSpan(request.arguments, /*simplifiedResult*/ false)); }, [CommandNames.TypeDefinition]: (request: protocol.FileLocationRequest) => { return this.requiredResponse(this.getTypeDefinition(request.arguments)); diff --git a/src/services/services.ts b/src/services/services.ts index 5b24fa1947e..f2702082470 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1411,6 +1411,20 @@ namespace ts { return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position); } + function getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan { + const definitions = getDefinitionAtPosition(fileName, position); + + if (!definitions) { + return undefined; + } + + const sourceFile = getValidSourceFile(fileName); + const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true); + const textSpan = createTextSpan(node.getStart(), node.getWidth()); + + return { definitions, textSpan }; + } + function getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[] { synchronizeHostData(); return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position); @@ -1807,15 +1821,6 @@ namespace ts { return range && createTextSpanFromRange(range); } - function getSpanForPosition(fileName: string, position: number): TextSpan { - synchronizeHostData(); - - const sourceFile = getValidSourceFile(fileName); - const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocCcomment*/ false); - - return createTextSpan(node.getStart(), node.getWidth()); - } - function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] { // Note: while getting todo comments seems like a syntactic operation, we actually // treat it as a semantic operation here. This is because we expect our host to call @@ -2018,6 +2023,7 @@ namespace ts { getSignatureHelpItems, getQuickInfoAtPosition, getDefinitionAtPosition, + getDefinitionAndBoundSpan, getImplementationAtPosition, getTypeDefinitionAtPosition, getReferencesAtPosition, @@ -2041,7 +2047,6 @@ namespace ts { getDocCommentTemplateAtPosition, isValidBraceCompletionAtPosition, getSpanOfEnclosingComment, - getSpanForPosition, getCodeFixesAtPosition, getEmitOutput, getNonBoundSourceFile, diff --git a/src/services/types.ts b/src/services/types.ts index 034b45100e0..c6ab8c876f0 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -245,6 +245,7 @@ namespace ts { findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan; getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[]; @@ -273,7 +274,6 @@ namespace ts { isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan; - getSpanForPosition(fileName: string, position: number): TextSpan; getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; @@ -549,6 +549,11 @@ namespace ts { containerName: string; } + export interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } + export interface ReferencedSymbolDefinitionInfo extends DefinitionInfo { displayParts: SymbolDisplayPart[]; } diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 8beb5ff60e4..b69b44e98a0 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3922,6 +3922,7 @@ declare namespace ts { getRenameInfo(fileName: string, position: number): RenameInfo; findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan; getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; @@ -3942,7 +3943,6 @@ declare namespace ts { getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion; isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan; - getSpanForPosition(fileName: string, position: number): TextSpan; getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined; @@ -4174,6 +4174,10 @@ declare namespace ts { containerKind: ScriptElementKind; containerName: string; } + interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } interface ReferencedSymbolDefinitionInfo extends DefinitionInfo { displayParts: SymbolDisplayPart[]; } @@ -4793,6 +4797,7 @@ declare namespace ts.server.protocol { CompileOnSaveEmitFile = "compileOnSaveEmitFile", Configure = "configure", Definition = "definition", + DefinitionAndBoundSpan = "definitionAndBoundSpan", Implementation = "implementation", Exit = "exit", Format = "format", @@ -5298,6 +5303,10 @@ declare namespace ts.server.protocol { */ file: string; } + interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } /** * Definition response message. Gives text range for definition. */ @@ -6855,6 +6864,9 @@ declare namespace ts.server { private convertToDiagnosticsWithLinePosition(diagnostics, scriptInfo); private getDiagnosticsWorker(args, isSemantic, selector, includeLinePosition); private getDefinition(args, simplifiedResult); + private getDefinitionAndBoundSpan(args, simplifiedResult); + private getSimplifiedDefinition(definitions, project); + private getSimplifiedTextSpan(textSpan, scriptInfo); private getTypeDefinition(args); private getImplementation(args, simplifiedResult); private getOccurrences(args); @@ -6888,7 +6900,6 @@ declare namespace ts.server { private getNameOrDottedNameSpan(args); private isValidBraceCompletion(args); private getQuickInfoWorker(args, simplifiedResult); - private getSpanForLocation(args); private getFormattingEditsForRange(args); private getFormattingEditsForRangeFull(args); private getFormattingEditsForDocumentFull(args); diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 2733bb20e56..9f9319fd7fa 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3922,6 +3922,7 @@ declare namespace ts { getRenameInfo(fileName: string, position: number): RenameInfo; findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[]; getDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; + getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan; getTypeDefinitionAtPosition(fileName: string, position: number): DefinitionInfo[]; getImplementationAtPosition(fileName: string, position: number): ImplementationLocation[]; getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[]; @@ -3942,7 +3943,6 @@ declare namespace ts { getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion; isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan; - getSpanForPosition(fileName: string, position: number): TextSpan; getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined; @@ -4174,6 +4174,10 @@ declare namespace ts { containerKind: ScriptElementKind; containerName: string; } + interface DefinitionInfoAndBoundSpan { + definitions: ReadonlyArray; + textSpan: TextSpan; + } interface ReferencedSymbolDefinitionInfo extends DefinitionInfo { displayParts: SymbolDisplayPart[]; } From abb3f58db29e4b9889f4fcc784f5ebf9d35f5263 Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Fri, 13 Oct 2017 17:14:56 -0700 Subject: [PATCH 012/256] Add support for JSX fragment syntax --- src/compiler/binder.ts | 3 ++ src/compiler/checker.ts | 73 ++++++++++++++++++---------- src/compiler/diagnosticMessages.json | 8 +++ src/compiler/emitter.ts | 40 ++++++++++----- src/compiler/factory.ts | 53 ++++++++++++++++++-- src/compiler/parser.ts | 69 +++++++++++++++++++++----- src/compiler/scanner.ts | 5 ++ src/compiler/transformers/jsx.ts | 26 ++++++++++ src/compiler/types.ts | 27 +++++++++- src/compiler/utilities.ts | 18 ++++++- src/compiler/visitor.ts | 12 +++++ tests/cases/compiler/jsxFragment.tsx | 4 ++ 12 files changed, 282 insertions(+), 56 deletions(-) create mode 100644 tests/cases/compiler/jsxFragment.tsx diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 35a62a644d8..ce02d461ed5 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3296,6 +3296,9 @@ namespace ts { case SyntaxKind.JsxOpeningElement: case SyntaxKind.JsxText: case SyntaxKind.JsxClosingElement: + case SyntaxKind.JsxFragment: + case SyntaxKind.JsxOpeningFragment: + case SyntaxKind.JsxClosingFragment: case SyntaxKind.JsxAttribute: case SyntaxKind.JsxAttributes: case SyntaxKind.JsxSpreadAttribute: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 69a46ed6cb2..8a0e369789d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13467,32 +13467,37 @@ namespace ts { function getContextualTypeForJsxExpression(node: JsxExpression): Type { // JSX expression can appear in two position : JSX Element's children or JSX attribute - const jsxAttributes = isJsxAttributeLike(node.parent) ? + const jsxAttributes: JsxAttributes = isJsxAttributeLike(node.parent) ? node.parent.parent : - node.parent.openingElement.attributes; // node.parent is JsxElement + isJsxElement(node.parent) ? + node.parent.openingElement.attributes : + undefined; // node.parent is JsxFragment with no attributes - // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type - // which is a type of the parameter of the signature we are trying out. - // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName - const attributesType = getContextualType(jsxAttributes); + if (jsxAttributes) { + // When we trying to resolve JsxOpeningLikeElement as a stateless function element, we will already give its attributes a contextual type + // which is a type of the parameter of the signature we are trying out. + // If there is no contextual type (e.g. we are trying to resolve stateful component), get attributes type from resolving element's tagName + const attributesType = getContextualType(jsxAttributes); - if (!attributesType || isTypeAny(attributesType)) { - return undefined; - } + if (!attributesType || isTypeAny(attributesType)) { + return undefined; + } - if (isJsxAttribute(node.parent)) { - // JSX expression is in JSX attribute - return getTypeOfPropertyOfContextualType(attributesType, node.parent.name.escapedText); - } - else if (node.parent.kind === SyntaxKind.JsxElement) { - // JSX expression is in children of JSX Element, we will look for an "children" atttribute (we get the name from JSX.ElementAttributesProperty) - const jsxChildrenPropertyName = getJsxElementChildrenPropertyname(); - return jsxChildrenPropertyName && jsxChildrenPropertyName !== "" ? getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName) : anyType; - } - else { - // JSX expression is in JSX spread attribute - return attributesType; + if (isJsxAttribute(node.parent)) { + // JSX expression is in JSX attribute + return getTypeOfPropertyOfContextualType(attributesType, node.parent.name.escapedText); + } + else if (node.parent.kind === SyntaxKind.JsxElement) { + // JSX expression is in children of JSX Element, we will look for an "children" atttribute (we get the name from JSX.ElementAttributesProperty) + const jsxChildrenPropertyName = getJsxElementChildrenPropertyname(); + return jsxChildrenPropertyName && jsxChildrenPropertyName !== "" ? getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName) : anyType; + } + else { + // JSX expression is in JSX spread attribute + return attributesType; + } } + return anyType; // don't check children of a fragment } function getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute) { @@ -14049,13 +14054,13 @@ namespace ts { } function checkJsxSelfClosingElement(node: JsxSelfClosingElement): Type { - checkJsxOpeningLikeElement(node); + checkJsxOpeningLikeElementOrOpeningFragment(node); return getJsxGlobalElementType() || anyType; } function checkJsxElement(node: JsxElement): Type { // Check attributes - checkJsxOpeningLikeElement(node.openingElement); + checkJsxOpeningLikeElementOrOpeningFragment(node.openingElement); // Perform resolution on the closing tag so that rename/go to definition/etc work if (isJsxIntrinsicIdentifier(node.closingElement.tagName)) { @@ -14068,6 +14073,11 @@ namespace ts { return getJsxGlobalElementType() || anyType; } + function checkJsxFragment(node: JsxFragment): Type { + checkJsxOpeningLikeElementOrOpeningFragment(node.openingFragment); + return getJsxGlobalElementType() || anyType; + } + /** * Returns true iff the JSX element name would be a valid JS identifier, ignoring restrictions about keywords not being identifiers */ @@ -14731,14 +14741,19 @@ namespace ts { } } - function checkJsxOpeningLikeElement(node: JsxOpeningLikeElement) { - checkGrammarJsxElement(node); + function checkJsxOpeningLikeElementOrOpeningFragment(node: JsxOpeningLikeElement | JsxOpeningFragment) { + const isNodeOpeningLikeElement = isJsxOpeningLikeElement(node); + + if (isNodeOpeningLikeElement) { + checkGrammarJsxElement(node); + } checkJsxPreconditions(node); // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; const reactNamespace = getJsxNamespace(); - const reactSym = resolveName(node.tagName, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true); + const reactLocation = isNodeOpeningLikeElement ? (node).tagName : node; + const reactSym = resolveName(reactLocation, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true); if (reactSym) { // Mark local symbol as referenced here because it might not have been marked // if jsx emit was not react as there wont be error being emitted @@ -14750,7 +14765,9 @@ namespace ts { } } - checkJsxAttributesAssignableToTagNameAttributes(node); + if (isNodeOpeningLikeElement) { + checkJsxAttributesAssignableToTagNameAttributes(node); + } } /** @@ -18518,6 +18535,8 @@ namespace ts { return checkJsxElement(node); case SyntaxKind.JsxSelfClosingElement: return checkJsxSelfClosingElement(node); + case SyntaxKind.JsxFragment: + return checkJsxFragment(node); case SyntaxKind.JsxAttributes: return checkJsxAttributes(node, checkMode); case SyntaxKind.JsxOpeningElement: diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 8cd5088049c..68cc5a7309e 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3607,6 +3607,14 @@ "category": "Error", "code": 17013 }, + "JSX fragment has no corresponding closing tag.": { + "category": "Error", + "code": 17014 + }, + "Expected corresponding JSX fragment closing tag.": { + "category": "Error", + "code": 17015 + }, "Circularity detected while resolving configuration: {0}": { "category": "Error", diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 9ce220e723f..ced57157b26 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -699,9 +699,11 @@ namespace ts { case SyntaxKind.JsxText: return emitJsxText(node); case SyntaxKind.JsxOpeningElement: - return emitJsxOpeningElement(node); + case SyntaxKind.JsxOpeningFragment: + return emitJsxOpeningElementOrFragment(node); case SyntaxKind.JsxClosingElement: - return emitJsxClosingElement(node); + case SyntaxKind.JsxClosingFragment: + return emitJsxClosingElementOrFragment(node); case SyntaxKind.JsxAttribute: return emitJsxAttribute(node); case SyntaxKind.JsxAttributes: @@ -836,6 +838,8 @@ namespace ts { return emitJsxElement(node); case SyntaxKind.JsxSelfClosingElement: return emitJsxSelfClosingElement(node); + case SyntaxKind.JsxFragment: + return emitJsxFragment(node); // Transformation nodes case SyntaxKind.PartiallyEmittedExpression: @@ -2060,7 +2064,7 @@ namespace ts { function emitJsxElement(node: JsxElement) { emit(node.openingElement); - emitList(node, node.children, ListFormat.JsxElementChildren); + emitList(node, node.children, ListFormat.JsxElementOrFragmentChildren); emit(node.closingElement); } @@ -2075,14 +2079,24 @@ namespace ts { write("/>"); } - function emitJsxOpeningElement(node: JsxOpeningElement) { + function emitJsxFragment(node: JsxFragment) { + emit(node.openingFragment); + emitList(node, node.children, ListFormat.JsxElementOrFragmentChildren); + emit(node.closingFragment); + } + + function emitJsxOpeningElementOrFragment(node: JsxOpeningElement | JsxOpeningFragment) { write("<"); - emitJsxTagName(node.tagName); - writeIfAny(node.attributes.properties, " "); - // We are checking here so we won't re-enter the emitting pipeline and emit extra sourcemap - if (node.attributes.properties && node.attributes.properties.length > 0) { - emit(node.attributes); + + if (isJsxOpeningElement(node)) { + emitJsxTagName(node.tagName); + writeIfAny(node.attributes.properties, " "); + // We are checking here so we won't re-enter the emitting pipeline and emit extra sourcemap + if (node.attributes.properties && node.attributes.properties.length > 0) { + emit(node.attributes); + } } + write(">"); } @@ -2090,9 +2104,11 @@ namespace ts { writer.writeLiteral(getTextOfNode(node, /*includeTrivia*/ true)); } - function emitJsxClosingElement(node: JsxClosingElement) { + function emitJsxClosingElementOrFragment(node: JsxClosingElement | JsxClosingFragment) { write(""); } @@ -3176,7 +3192,7 @@ namespace ts { EnumMembers = CommaDelimited | Indented | MultiLine, CaseBlockClauses = Indented | MultiLine, NamedImportsOrExportsElements = CommaDelimited | SpaceBetweenSiblings | AllowTrailingComma | SingleLine | SpaceBetweenBraces, - JsxElementChildren = SingleLine | NoInterveningComments, + JsxElementOrFragmentChildren = SingleLine | NoInterveningComments, JsxElementAttributes = SingleLine | SpaceBetweenSiblings | NoInterveningComments, CaseOrDefaultClauseStatements = Indented | MultiLine | NoTrailingNewLine | OptionalIfEmpty, HeritageClauseTypes = CommaDelimited | SpaceBetweenSiblings | SingleLine, diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 65c1c92f366..8d66608c226 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2115,6 +2115,22 @@ namespace ts { : node; } + export function createJsxFragment(openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment) { + const node = createSynthesizedNode(SyntaxKind.JsxFragment); + node.openingFragment = openingFragment; + node.children = createNodeArray(children); + node.closingFragment = closingFragment; + return node; + } + + export function updateJsxFragment(node: JsxFragment, openingFragment: JsxOpeningFragment, children: ReadonlyArray, closingFragment: JsxClosingFragment) { + return node.openingFragment !== openingFragment + || node.children !== children + || node.closingFragment !== closingFragment + ? updateNode(createJsxFragment(openingFragment, children, closingFragment), node) + : node; + } + export function createJsxAttribute(name: Identifier, initializer: StringLiteral | JsxExpression) { const node = createSynthesizedNode(SyntaxKind.JsxAttribute); node.name = name; @@ -2951,7 +2967,7 @@ namespace ts { ); } - function createReactNamespace(reactNamespace: string, parent: JsxOpeningLikeElement) { + function createReactNamespace(reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment) { // To ensure the emit resolver can properly resolve the namespace, we need to // treat this identifier as if it were a source tree node by clearing the `Synthesized` // flag and setting a parent node. @@ -2963,7 +2979,7 @@ namespace ts { return react; } - function createJsxFactoryExpressionFromEntityName(jsxFactory: EntityName, parent: JsxOpeningLikeElement): Expression { + function createJsxFactoryExpressionFromEntityName(jsxFactory: EntityName, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { if (isQualifiedName(jsxFactory)) { const left = createJsxFactoryExpressionFromEntityName(jsxFactory.left, parent); const right = createIdentifier(idText(jsxFactory.right)); @@ -2975,7 +2991,7 @@ namespace ts { } } - function createJsxFactoryExpression(jsxFactoryEntity: EntityName, reactNamespace: string, parent: JsxOpeningLikeElement): Expression { + function createJsxFactoryExpression(jsxFactoryEntity: EntityName, reactNamespace: string, parent: JsxOpeningLikeElement | JsxOpeningFragment): Expression { return jsxFactoryEntity ? createJsxFactoryExpressionFromEntityName(jsxFactoryEntity, parent) : createPropertyAccess( @@ -3016,6 +3032,37 @@ namespace ts { ); } + export function createExpressionForJsxFragment(jsxFactoryEntity: EntityName, reactNamespace: string, children: Expression[], parentElement: JsxOpeningFragment, location: TextRange): LeftHandSideExpression { + const tagName = createPropertyAccess( + createReactNamespace(reactNamespace, parentElement), + "Fragment" + ); + + const argumentsList = [tagName]; + argumentsList.push(createNull()); + + if (children && children.length > 0) { + if (children.length > 1) { + for (const child of children) { + child.startsOnNewLine = true; + argumentsList.push(child); + } + } + else { + argumentsList.push(children[0]); + } + } + + return setTextRange( + createCall( + createJsxFactoryExpression(jsxFactoryEntity, reactNamespace, parentElement), + /*typeArguments*/ undefined, + argumentsList + ), + location + ); + } + // Helpers export function getHelperName(name: string) { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e2bae71e6bf..28329791045 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -377,6 +377,10 @@ namespace ts { return visitNode(cbNode, (node).openingElement) || visitNodes(cbNode, cbNodes, (node).children) || visitNode(cbNode, (node).closingElement); + case SyntaxKind.JsxFragment: + return visitNode(cbNode, (node).openingFragment) || + visitNodes(cbNode, cbNodes, (node).children) || + visitNode(cbNode, (node).closingFragment); case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxOpeningElement: return visitNode(cbNode, (node).tagName) || @@ -1423,6 +1427,11 @@ namespace ts { return tokenIsIdentifierOrKeyword(token()); } + function nextTokenIsIdentifierOrKeywordOrGreaterThan() { + nextToken(); + return tokenIsIdentifierOrKeywordOrGreaterThan(token()); + } + function isHeritageClauseExtendsOrImplementsKeyword(): boolean { if (token() === SyntaxKind.ImplementsKeyword || token() === SyntaxKind.ExtendsKeyword) { @@ -3802,9 +3811,9 @@ namespace ts { node.operand = parseLeftHandSideExpressionOrHigher(); return finishNode(node); } - else if (sourceFile.languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeyword)) { + else if (sourceFile.languageVariant === LanguageVariant.JSX && token() === SyntaxKind.LessThanToken && lookAhead(nextTokenIsIdentifierOrKeywordOrGreaterThan)) { // JSXElement is part of primaryExpression - return parseJsxElementOrSelfClosingElement(/*inExpressionContext*/ true); + return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true); } const expression = parseLeftHandSideExpressionOrHigher(); @@ -3959,14 +3968,14 @@ namespace ts { } - function parseJsxElementOrSelfClosingElement(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement { - const opening = parseJsxOpeningOrSelfClosingElement(inExpressionContext); - let result: JsxElement | JsxSelfClosingElement; + function parseJsxElementOrSelfClosingElementOrFragment(inExpressionContext: boolean): JsxElement | JsxSelfClosingElement | JsxFragment { + const opening = parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext); + let result: JsxElement | JsxSelfClosingElement | JsxFragment; if (opening.kind === SyntaxKind.JsxOpeningElement) { const node = createNode(SyntaxKind.JsxElement, opening.pos); node.openingElement = opening; - node.children = parseJsxChildren(node.openingElement.tagName); + node.children = parseJsxChildren(node.openingElement); node.closingElement = parseJsxClosingElement(inExpressionContext); if (!tagNamesAreEquivalent(node.openingElement.tagName, node.closingElement.tagName)) { @@ -3975,6 +3984,15 @@ namespace ts { result = finishNode(node); } + else if (opening.kind === SyntaxKind.JsxOpeningFragment) { + const node = createNode(SyntaxKind.JsxFragment, opening.pos); + node.openingFragment = opening; + + node.children = parseJsxChildren(node.openingFragment); + node.closingFragment = parseJsxClosingFragment(inExpressionContext); + + result = finishNode(node); + } else { Debug.assert(opening.kind === SyntaxKind.JsxSelfClosingElement); // Nothing else to do for self-closing elements @@ -3989,7 +4007,7 @@ namespace ts { // Since JSX elements are invalid < operands anyway, this lookahead parse will only occur in error scenarios // of one sort or another. if (inExpressionContext && token() === SyntaxKind.LessThanToken) { - const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElement(/*inExpressionContext*/ true)); + const invalidElement = tryParse(() => parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ true)); if (invalidElement) { parseErrorAtCurrentToken(Diagnostics.JSX_expressions_must_have_one_parent_element); const badNode = createNode(SyntaxKind.BinaryExpression, result.pos); @@ -4020,12 +4038,12 @@ namespace ts { case SyntaxKind.OpenBraceToken: return parseJsxExpression(/*inExpressionContext*/ false); case SyntaxKind.LessThanToken: - return parseJsxElementOrSelfClosingElement(/*inExpressionContext*/ false); + return parseJsxElementOrSelfClosingElementOrFragment(/*inExpressionContext*/ false); } Debug.fail("Unknown JSX child kind " + token()); } - function parseJsxChildren(openingTagName: LeftHandSideExpression): NodeArray { + function parseJsxChildren(openingTag: JsxOpeningElement | JsxOpeningFragment): NodeArray { const list = []; const listPos = getNodePos(); const saveParsingContext = parsingContext; @@ -4040,7 +4058,13 @@ namespace ts { else if (token() === SyntaxKind.EndOfFileToken) { // If we hit EOF, issue the error at the tag that lacks the closing element // rather than at the end of the file (which is useless) - parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName)); + if (isJsxOpeningElement(openingTag)) { + const openingTagName = openingTag.tagName; + parseErrorAtPosition(openingTagName.pos, openingTagName.end - openingTagName.pos, Diagnostics.JSX_element_0_has_no_corresponding_closing_tag, getTextOfNodeFromSourceText(sourceText, openingTagName)); + } + else { + parseErrorAtPosition(openingTag.pos, openingTag.end - openingTag.pos, Diagnostics.JSX_fragment_has_no_corresponding_closing_tag); + } break; } else if (token() === SyntaxKind.ConflictMarkerTrivia) { @@ -4063,11 +4087,17 @@ namespace ts { return finishNode(jsxAttributes); } - function parseJsxOpeningOrSelfClosingElement(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement { + function parseJsxOpeningOrSelfClosingElementOrOpeningFragment(inExpressionContext: boolean): JsxOpeningElement | JsxSelfClosingElement | JsxOpeningFragment { const fullStart = scanner.getStartPos(); parseExpected(SyntaxKind.LessThanToken); + if (token() === SyntaxKind.GreaterThanToken) { + parseExpected(SyntaxKind.GreaterThanToken); + const node: JsxOpeningFragment = createNode(SyntaxKind.JsxOpeningFragment, fullStart); + return finishNode(node); + } + const tagName = parseJsxElementName(); const attributes = parseJsxAttributes(); @@ -4179,6 +4209,23 @@ namespace ts { return finishNode(node); } + function parseJsxClosingFragment(inExpressionContext: boolean): JsxClosingFragment { + const node = createNode(SyntaxKind.JsxClosingFragment); + parseExpected(SyntaxKind.LessThanSlashToken); + if (tokenIsIdentifierOrKeyword(token())) { + const unexpectedTagName = parseJsxElementName(); + parseErrorAtPosition(unexpectedTagName.pos, unexpectedTagName.end - unexpectedTagName.pos, Diagnostics.Expected_corresponding_JSX_fragment_closing_tag); + } + if (inExpressionContext) { + parseExpected(SyntaxKind.GreaterThanToken); + } + else { + parseExpected(SyntaxKind.GreaterThanToken, /*diagnostic*/ undefined, /*shouldAdvance*/ false); + scanJsxText(); + } + return finishNode(node); + } + function parseTypeAssertion(): TypeAssertion { const node = createNode(SyntaxKind.TypeAssertionExpression); parseExpected(SyntaxKind.LessThanToken); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index b19a1466328..67d83f262c8 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -11,6 +11,11 @@ namespace ts { return token >= SyntaxKind.Identifier; } + /* @internal */ + export function tokenIsIdentifierOrKeywordOrGreaterThan(token: SyntaxKind): boolean { + return token === SyntaxKind.GreaterThanToken || token >= SyntaxKind.Identifier; + } + export interface Scanner { getStartPos(): number; getToken(): SyntaxKind; diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index bbe05afe878..2be6cdef0bc 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -41,6 +41,9 @@ namespace ts { case SyntaxKind.JsxSelfClosingElement: return visitJsxSelfClosingElement(node, /*isChild*/ false); + case SyntaxKind.JsxFragment: + return visitJsxFragment(node, /*isChild*/ false); + case SyntaxKind.JsxExpression: return visitJsxExpression(node); @@ -63,6 +66,9 @@ namespace ts { case SyntaxKind.JsxSelfClosingElement: return visitJsxSelfClosingElement(node, /*isChild*/ true); + case SyntaxKind.JsxFragment: + return visitJsxFragment(node, /*isChild*/ true); + default: Debug.failBadSyntaxKind(node); return undefined; @@ -77,6 +83,10 @@ namespace ts { return visitJsxOpeningLikeElement(node, /*children*/ undefined, isChild, /*location*/ node); } + function visitJsxFragment(node: JsxFragment, isChild: boolean) { + return visitJsxOpeningFragment(node.openingFragment, node.children, isChild, /*location*/ node); + } + function visitJsxOpeningLikeElement(node: JsxOpeningLikeElement, children: ReadonlyArray, isChild: boolean, location: TextRange) { const tagName = getTagName(node); let objectProperties: Expression; @@ -126,6 +136,22 @@ namespace ts { return element; } + function visitJsxOpeningFragment(node: JsxOpeningFragment, children: ReadonlyArray, isChild: boolean, location: TextRange) { + const element = createExpressionForJsxFragment( + context.getEmitResolver().getJsxFactoryEntity(), + compilerOptions.reactNamespace, + mapDefined(children, transformJsxChildToExpression), + node, + location + ); + + if (isChild) { + startOnNewLine(element); + } + + return element; + } + function transformJsxSpreadAttributeToExpression(node: JsxSpreadAttribute) { return visitNode(node.expression, visitor, isExpression); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 42e8292b13b..27cba8ef777 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -328,6 +328,9 @@ namespace ts { JsxSelfClosingElement, JsxOpeningElement, JsxClosingElement, + JsxFragment, + JsxOpeningFragment, + JsxClosingFragment, JsxAttribute, JsxAttributes, JsxSpreadAttribute, @@ -1618,7 +1621,7 @@ namespace ts { closingElement: JsxClosingElement; } - /// Either the opening tag in a ... pair, or the lone in a self-closing form + /// Either the opening tag in a ... pair, the opening tag in a <>... pair, or the lone in a self-closing form export type JsxOpeningLikeElement = JsxSelfClosingElement | JsxOpeningElement; export type JsxAttributeLike = JsxAttribute | JsxSpreadAttribute; @@ -1644,6 +1647,26 @@ namespace ts { attributes: JsxAttributes; } + /// A JSX expression of the form <>... + export interface JsxFragment extends PrimaryExpression { + kind: SyntaxKind.JsxFragment; + openingFragment: JsxOpeningFragment; + children: NodeArray; + closingFragment: JsxClosingFragment; + } + + /// The opening element of a <>... JsxFragment + export interface JsxOpeningFragment extends Expression { + kind: SyntaxKind.JsxOpeningFragment; + parent?: JsxFragment; + } + + /// The closing element of a <>... JsxFragment + export interface JsxClosingFragment extends Expression { + kind: SyntaxKind.JsxClosingFragment; + parent?: JsxFragment; + } + export interface JsxAttribute extends ObjectLiteralElement { kind: SyntaxKind.JsxAttribute; parent?: JsxAttributes; @@ -1677,7 +1700,7 @@ namespace ts { parent?: JsxElement; } - export type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement; + export type JsxChild = JsxText | JsxExpression | JsxElement | JsxSelfClosingElement | JsxFragment; export interface Statement extends Node { _statementBrand: any; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c4d3de453ba..bfb9e488c92 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1251,6 +1251,7 @@ namespace ts { case SyntaxKind.OmittedExpression: case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxFragment: case SyntaxKind.YieldExpression: case SyntaxKind.AwaitExpression: case SyntaxKind.MetaProperty: @@ -2136,6 +2137,7 @@ namespace ts { case SyntaxKind.ClassExpression: case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxFragment: case SyntaxKind.RegularExpressionLiteral: case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.TemplateExpression: @@ -4760,6 +4762,18 @@ namespace ts { return node.kind === SyntaxKind.JsxClosingElement; } + export function isJsxFragment(node: Node): node is JsxFragment { + return node.kind === SyntaxKind.JsxFragment; + } + + export function isJsxOpeningFragment(node: Node): node is JsxOpeningFragment { + return node.kind === SyntaxKind.JsxOpeningFragment; + } + + export function isJsxClosingFragment(node: Node): node is JsxClosingFragment { + return node.kind === SyntaxKind.JsxClosingFragment; + } + export function isJsxAttribute(node: Node): node is JsxAttribute { return node.kind === SyntaxKind.JsxAttribute; } @@ -5285,6 +5299,7 @@ namespace ts { case SyntaxKind.CallExpression: case SyntaxKind.JsxElement: case SyntaxKind.JsxSelfClosingElement: + case SyntaxKind.JsxFragment: case SyntaxKind.TaggedTemplateExpression: case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.ParenthesizedExpression: @@ -5606,7 +5621,8 @@ namespace ts { return kind === SyntaxKind.JsxElement || kind === SyntaxKind.JsxExpression || kind === SyntaxKind.JsxSelfClosingElement - || kind === SyntaxKind.JsxText; + || kind === SyntaxKind.JsxText + || kind === SyntaxKind.JsxFragment; } /* @internal */ diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 7d46630e227..0428d2d2d2e 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -819,6 +819,12 @@ namespace ts { return updateJsxClosingElement(node, visitNode((node).tagName, visitor, isJsxTagNameExpression)); + case SyntaxKind.JsxFragment: + return updateJsxFragment(node, + visitNode((node).openingFragment, visitor, isJsxOpeningFragment), + nodesVisitor((node).children, visitor, isJsxChild), + visitNode((node).closingFragment, visitor, isJsxClosingFragment)); + case SyntaxKind.JsxAttribute: return updateJsxAttribute(node, visitNode((node).name, visitor, isIdentifier), @@ -1334,6 +1340,12 @@ namespace ts { result = reduceNode((node).closingElement, cbNode, result); break; + case SyntaxKind.JsxFragment: + result = reduceNode((node).openingFragment, cbNode, result); + result = reduceLeft((node).children, cbNode, result); + result = reduceNode((node).closingFragment, cbNode, result); + break; + case SyntaxKind.JsxSelfClosingElement: case SyntaxKind.JsxOpeningElement: result = reduceNode((node).tagName, cbNode, result); diff --git a/tests/cases/compiler/jsxFragment.tsx b/tests/cases/compiler/jsxFragment.tsx new file mode 100644 index 00000000000..82e093327be --- /dev/null +++ b/tests/cases/compiler/jsxFragment.tsx @@ -0,0 +1,4 @@ +//@jsx: react + +declare var React: any; +
; \ No newline at end of file From 269d37a2e6c1e41a002fa5c0f18e23654b73cbfc Mon Sep 17 00:00:00 2001 From: uniqueiniquity Date: Mon, 16 Oct 2017 16:51:39 -0700 Subject: [PATCH 013/256] Update tests --- tests/cases/compiler/jsxFragment.tsx | 4 -- .../jsx/checkJsxChildrenProperty14.tsx | 48 +++++++++++++++++++ .../conformance/jsx/tsxFragmentErrors.tsx | 14 ++++++ .../jsx/tsxFragmentPreserveEmit.tsx | 17 +++++++ .../conformance/jsx/tsxFragmentReactEmit.tsx | 17 +++++++ 5 files changed, 96 insertions(+), 4 deletions(-) delete mode 100644 tests/cases/compiler/jsxFragment.tsx create mode 100644 tests/cases/conformance/jsx/checkJsxChildrenProperty14.tsx create mode 100644 tests/cases/conformance/jsx/tsxFragmentErrors.tsx create mode 100644 tests/cases/conformance/jsx/tsxFragmentPreserveEmit.tsx create mode 100644 tests/cases/conformance/jsx/tsxFragmentReactEmit.tsx diff --git a/tests/cases/compiler/jsxFragment.tsx b/tests/cases/compiler/jsxFragment.tsx deleted file mode 100644 index 82e093327be..00000000000 --- a/tests/cases/compiler/jsxFragment.tsx +++ /dev/null @@ -1,4 +0,0 @@ -//@jsx: react - -declare var React: any; -
; \ No newline at end of file diff --git a/tests/cases/conformance/jsx/checkJsxChildrenProperty14.tsx b/tests/cases/conformance/jsx/checkJsxChildrenProperty14.tsx new file mode 100644 index 00000000000..65dfc720003 --- /dev/null +++ b/tests/cases/conformance/jsx/checkJsxChildrenProperty14.tsx @@ -0,0 +1,48 @@ +// @filename: file.tsx +// @jsx: preserve +// @noLib: true +// @skipLibCheck: true +// @libFiles: react.d.ts,lib.d.ts + +import React = require('react'); + +interface Prop { + a: number, + b: string, + children: JSX.Element | JSX.Element[]; +} + +class Button extends React.Component { + render() { + return (
My Button
) + } +} + +function AnotherButton(p: any) { + return

Just Another Button

; +} + +function Comp(p: Prop) { + return
{p.b}
; +} + +// OK +let k1 = <>