Skip to content

Commit ea9dbe1

Browse files
committed
Merge branch 'master' into there-can-be-only-one
2 parents 3d7348f + 7cc4a8d commit ea9dbe1

File tree

166 files changed

+2448
-1365
lines changed

Some content is hidden

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

166 files changed

+2448
-1365
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ jobs:
3535
npm install
3636
npm update
3737
npm test
38+
- name: Validate the browser can import TypeScript
39+
run: gulp test-browser-integration
40+

Gulpfile.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ task("runtests").flags = {
456456
" --shardId": "1-based ID of this shard (default: 1)",
457457
};
458458

459-
const runTestsParallel = () => runConsoleTests("built/local/run.js", "min", /*runInParallel*/ true, /*watchMode*/ false);
459+
const runTestsParallel = () => runConsoleTests("built/local/run.js", "min", /*runInParallel*/ cmdLineOptions.workers > 1, /*watchMode*/ false);
460460
task("runtests-parallel", series(preBuild, preTest, runTestsParallel, postTest));
461461
task("runtests-parallel").description = "Runs all the tests in parallel using the built run.js file.";
462462
task("runtests-parallel").flags = {
@@ -472,6 +472,11 @@ task("runtests-parallel").flags = {
472472
" --shardId": "1-based ID of this shard (default: 1)",
473473
};
474474

475+
476+
task("test-browser-integration", () => exec(process.execPath, ["scripts/browserIntegrationTest.js"]));
477+
task("test-browser-integration").description = "Runs scripts/browserIntegrationTest.ts which tests that typescript.js loads in a browser";
478+
479+
475480
task("diff", () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true, waitForExit: false }));
476481
task("diff").description = "Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable";
477482

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"through2": "latest",
9797
"travis-fold": "latest",
9898
"typescript": "next",
99+
"playwright": "latest",
99100
"vinyl": "latest",
100101
"vinyl-sourcemaps-apply": "latest",
101102
"xml2js": "^0.4.19"

scripts/browserIntegrationTest.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
const playwright = require("playwright");
2+
const chalk = require("chalk");
3+
const { join } = require("path");
4+
const { readFileSync } = require("fs");
5+
6+
// Turning this on will leave the Chromium browser open, giving you the
7+
// chance to open up the web inspector.
8+
const debugging = false;
9+
10+
(async () => {
11+
for (const browserType of ["chromium", "firefox", "webkit"]) {
12+
const browser = await playwright[browserType].launch({ headless: !debugging });
13+
const context = await browser.newContext();
14+
const page = await context.newPage();
15+
16+
const errorCaught = err => {
17+
console.error(chalk.red("There was an error running built/typescript.js in " + browserType));
18+
console.log(err.toString());
19+
process.exitCode = 1;
20+
};
21+
22+
page.on("error", errorCaught);
23+
page.on("pageerror", errorCaught);
24+
page.on("console", log => console[log._type](log._text));
25+
26+
await page.setContent(`
27+
<html>
28+
<script>${readFileSync(join("built", "local", "typescript.js"), "utf8")}</script>
29+
</html>
30+
`);
31+
32+
if (!debugging) {
33+
await browser.close();
34+
}
35+
else {
36+
console.log("Not closing the browser, you'll need to exit the process in your terminal manually");
37+
}
38+
}
39+
})();

src/compiler/checker.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9596,7 +9596,7 @@ namespace ts {
95969596
// When creating an optional property in strictNullChecks mode, if 'undefined' isn't assignable to the
95979597
// type, we include 'undefined' in the type. Similarly, when creating a non-optional property in strictNullChecks
95989598
// mode, if the underlying property is optional we remove 'undefined' from the type.
9599-
prop.type = strictNullChecks && isOptional && !isTypeAssignableTo(undefinedType, propType) ? getOptionalType(propType) :
9599+
prop.type = strictNullChecks && isOptional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType) :
96009600
strictNullChecks && !isOptional && modifiersProp && modifiersProp.flags & SymbolFlags.Optional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) :
96019601
propType;
96029602
if (modifiersProp) {
@@ -11343,6 +11343,11 @@ namespace ts {
1134311343
function getTypeFromTypeReference(node: TypeReferenceType): Type {
1134411344
const links = getNodeLinks(node);
1134511345
if (!links.resolvedType) {
11346+
// handle LS queries on the `const` in `x as const` by resolving to the type of `x`
11347+
if (isConstTypeReference(node) && isAssertionExpression(node.parent)) {
11348+
links.resolvedSymbol = unknownSymbol;
11349+
return links.resolvedType = checkExpressionCached(node.parent.expression);
11350+
}
1134611351
let symbol: Symbol | undefined;
1134711352
let type: Type | undefined;
1134811353
const meaning = SymbolFlags.Type;
@@ -13696,7 +13701,7 @@ namespace ts {
1369613701
const templateMapper = combineTypeMappers(mapper, createTypeMapper([getTypeParameterFromMappedType(type)], [key]));
1369713702
const propType = instantiateType(getTemplateTypeFromMappedType(<MappedType>type.target || type), templateMapper);
1369813703
const modifiers = getMappedTypeModifiers(type);
13699-
return strictNullChecks && modifiers & MappedTypeModifiers.IncludeOptional && !isTypeAssignableTo(undefinedType, propType) ? getOptionalType(propType) :
13704+
return strictNullChecks && modifiers & MappedTypeModifiers.IncludeOptional && !maybeTypeOfKind(propType, TypeFlags.Undefined | TypeFlags.Void) ? getOptionalType(propType) :
1370013705
strictNullChecks && modifiers & MappedTypeModifiers.ExcludeOptional && isOptional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) :
1370113706
propType;
1370213707
}
@@ -22608,6 +22613,7 @@ namespace ts {
2260822613

2260922614
function checkJsxSelfClosingElementDeferred(node: JsxSelfClosingElement) {
2261022615
checkJsxOpeningLikeElementOrOpeningFragment(node);
22616+
resolveUntypedCall(node); // ensure type arguments and parameters are typechecked, even if there is an arity error
2261122617
}
2261222618

2261322619
function checkJsxSelfClosingElement(node: JsxSelfClosingElement, _checkMode: CheckMode | undefined): Type {
@@ -24995,14 +25001,14 @@ namespace ts {
2499525001
}
2499625002

2499725003
// No signature was applicable. We have already reported the errors for the invalid signature.
24998-
// If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
2499925004
function getCandidateForOverloadFailure(
2500025005
node: CallLikeExpression,
2500125006
candidates: Signature[],
2500225007
args: readonly Expression[],
2500325008
hasCandidatesOutArray: boolean,
2500425009
): Signature {
2500525010
Debug.assert(candidates.length > 0); // Else should not have called this.
25011+
checkNodeDeferred(node);
2500625012
// Normally we will combine overloads. Skip this if they have type parameters since that's hard to combine.
2500725013
// Don't do this if there is a `candidatesOutArray`,
2500825014
// because then we want the chosen best candidate to be one of the overloads, not a combination.
@@ -29299,7 +29305,7 @@ namespace ts {
2929929305
}
2930029306

2930129307
function isPrivateWithinAmbient(node: Node): boolean {
29302-
return hasModifier(node, ModifierFlags.Private) && !!(node.flags & NodeFlags.Ambient);
29308+
return (hasModifier(node, ModifierFlags.Private) || isPrivateIdentifierPropertyDeclaration(node)) && !!(node.flags & NodeFlags.Ambient);
2930329309
}
2930429310

2930529311
function getEffectiveDeclarationFlags(n: Declaration, flagsToCheck: ModifierFlags): ModifierFlags {
@@ -33971,6 +33977,16 @@ namespace ts {
3397133977
currentNode = node;
3397233978
instantiationCount = 0;
3397333979
switch (node.kind) {
33980+
case SyntaxKind.CallExpression:
33981+
case SyntaxKind.NewExpression:
33982+
case SyntaxKind.TaggedTemplateExpression:
33983+
case SyntaxKind.Decorator:
33984+
case SyntaxKind.JsxOpeningElement:
33985+
// These node kinds are deferred checked when overload resolution fails
33986+
// To save on work, we ensure the arguments are checked just once, in
33987+
// a deferred way
33988+
resolveUntypedCall(node as CallLikeExpression);
33989+
break;
3397433990
case SyntaxKind.FunctionExpression:
3397533991
case SyntaxKind.ArrowFunction:
3397633992
case SyntaxKind.MethodDeclaration:

src/compiler/parser.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6576,18 +6576,19 @@ namespace ts {
65766576
return finishNode(node);
65776577
}
65786578

6579-
function parseNamespaceExport(): NamespaceExport {
6580-
const node = <NamespaceExport>createNode(SyntaxKind.NamespaceExport);
6579+
function parseNamespaceExport(pos: number): NamespaceExport {
6580+
const node = <NamespaceExport>createNode(SyntaxKind.NamespaceExport, pos);
65816581
node.name = parseIdentifier();
65826582
return finishNode(node);
65836583
}
65846584

65856585
function parseExportDeclaration(node: ExportDeclaration): ExportDeclaration {
65866586
node.kind = SyntaxKind.ExportDeclaration;
65876587
node.isTypeOnly = parseOptional(SyntaxKind.TypeKeyword);
6588+
const namespaceExportPos = scanner.getStartPos();
65886589
if (parseOptional(SyntaxKind.AsteriskToken)) {
65896590
if (parseOptional(SyntaxKind.AsKeyword)) {
6590-
node.exportClause = parseNamespaceExport();
6591+
node.exportClause = parseNamespaceExport(namespaceExportPos);
65916592
}
65926593
parseExpected(SyntaxKind.FromKeyword);
65936594
node.moduleSpecifier = parseModuleSpecifier();

src/compiler/transformers/ts.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@ namespace ts {
2323
IsNamedExternalExport = 1 << 4,
2424
IsDefaultExternalExport = 1 << 5,
2525
IsDerivedClass = 1 << 6,
26-
UseImmediatelyInvokedFunctionExpression = 1 << 7,
2726

2827
HasAnyDecorators = HasConstructorDecorators | HasMemberDecorators,
2928
NeedsName = HasStaticInitializedProperties | HasMemberDecorators,
30-
MayNeedImmediatelyInvokedFunctionExpression = HasAnyDecorators | HasStaticInitializedProperties,
29+
UseImmediatelyInvokedFunctionExpression = HasAnyDecorators | HasStaticInitializedProperties,
3130
IsExported = IsExportOfNamespace | IsDefaultExternalExport | IsNamedExternalExport,
3231
}
3332

@@ -590,7 +589,6 @@ namespace ts {
590589
if (isExportOfNamespace(node)) facts |= ClassFacts.IsExportOfNamespace;
591590
else if (isDefaultExternalModuleExport(node)) facts |= ClassFacts.IsDefaultExternalExport;
592591
else if (isNamedExternalModuleExport(node)) facts |= ClassFacts.IsNamedExternalExport;
593-
if (languageVersion <= ScriptTarget.ES5 && (facts & ClassFacts.MayNeedImmediatelyInvokedFunctionExpression)) facts |= ClassFacts.UseImmediatelyInvokedFunctionExpression;
594592
return facts;
595593
}
596594

@@ -661,6 +659,12 @@ namespace ts {
661659
const iife = createImmediatelyInvokedArrowFunction(statements);
662660
setEmitFlags(iife, EmitFlags.TypeScriptClassWrapper);
663661

662+
// Class comment is already added by the ES2015 transform when targeting ES5 or below.
663+
// Only add if targetting ES2015+ to prevent duplicates
664+
if (languageVersion > ScriptTarget.ES5) {
665+
addSyntheticLeadingComment(iife, SyntaxKind.MultiLineCommentTrivia, "* @class ");
666+
}
667+
664668
const varStatement = createVariableStatement(
665669
/*modifiers*/ undefined,
666670
createVariableDeclarationList([
@@ -669,7 +673,7 @@ namespace ts {
669673
/*type*/ undefined,
670674
iife
671675
)
672-
])
676+
], languageVersion > ScriptTarget.ES5 ? NodeFlags.Let : undefined)
673677
);
674678

675679
setOriginalNode(varStatement, node);

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3520,7 +3520,7 @@ namespace ts {
35203520
/* @internal */ createPromiseType(type: Type): Type;
35213521

35223522
/* @internal */ isTypeAssignableTo(source: Type, target: Type): boolean;
3523-
/* @internal */ createAnonymousType(symbol: Symbol, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): Type;
3523+
/* @internal */ createAnonymousType(symbol: Symbol | undefined, members: SymbolTable, callSignatures: Signature[], constructSignatures: Signature[], stringIndexInfo: IndexInfo | undefined, numberIndexInfo: IndexInfo | undefined): Type;
35243524
/* @internal */ createSignature(
35253525
declaration: SignatureDeclaration,
35263526
typeParameters: TypeParameter[] | undefined,

src/compiler/utilities.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4225,6 +4225,9 @@ namespace ts {
42254225
}
42264226

42274227
export function getModifierFlags(node: Node): ModifierFlags {
4228+
if (node.kind >= SyntaxKind.FirstToken && node.kind <= SyntaxKind.LastToken) {
4229+
return ModifierFlags.None;
4230+
}
42284231
if (node.modifierFlagsCache & ModifierFlags.HasComputedFlags) {
42294232
return node.modifierFlagsCache & ~ModifierFlags.HasComputedFlags;
42304233
}
@@ -5072,6 +5075,28 @@ namespace ts {
50725075
this.original = undefined;
50735076
}
50745077

5078+
function Token(this: Node, kind: SyntaxKind, pos: number, end: number) {
5079+
this.pos = pos;
5080+
this.end = end;
5081+
this.kind = kind;
5082+
this.id = 0;
5083+
this.flags = NodeFlags.None;
5084+
this.transformFlags = TransformFlags.None;
5085+
this.parent = undefined!;
5086+
}
5087+
5088+
function Identifier(this: Node, kind: SyntaxKind, pos: number, end: number) {
5089+
this.pos = pos;
5090+
this.end = end;
5091+
this.kind = kind;
5092+
this.id = 0;
5093+
this.flags = NodeFlags.None;
5094+
this.transformFlags = TransformFlags.None;
5095+
this.parent = undefined!;
5096+
this.original = undefined;
5097+
this.flowNode = undefined;
5098+
}
5099+
50755100
function SourceMapSource(this: SourceMapSource, fileName: string, text: string, skipTrivia?: (pos: number) => number) {
50765101
this.fileName = fileName;
50775102
this.text = text;
@@ -5081,8 +5106,8 @@ namespace ts {
50815106
// eslint-disable-next-line prefer-const
50825107
export let objectAllocator: ObjectAllocator = {
50835108
getNodeConstructor: () => <any>Node,
5084-
getTokenConstructor: () => <any>Node,
5085-
getIdentifierConstructor: () => <any>Node,
5109+
getTokenConstructor: () => <any>Token,
5110+
getIdentifierConstructor: () => <any>Identifier,
50865111
getPrivateIdentifierConstructor: () => <any>Node,
50875112
getSourceFileConstructor: () => <any>Node,
50885113
getSymbolConstructor: () => <any>Symbol,

src/harness/fourslashImpl.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,37 @@ namespace FourSlash {
13191319
}
13201320
}
13211321

1322+
public baselineRename(marker: string, options: FourSlashInterface.RenameOptions) {
1323+
const position = this.getMarkerByName(marker).position;
1324+
const locations = this.languageService.findRenameLocations(
1325+
this.activeFile.fileName,
1326+
position,
1327+
options.findInStrings ?? false,
1328+
options.findInComments ?? false,
1329+
options.providePrefixAndSuffixTextForRename);
1330+
1331+
if (!locations) {
1332+
this.raiseError(`baselineRename failed. Could not rename at the provided position.`);
1333+
}
1334+
1335+
const renamesByFile = ts.group(locations, l => l.fileName);
1336+
const baselineContent = renamesByFile.map(renames => {
1337+
const { fileName } = renames[0];
1338+
const sortedRenames = ts.sort(renames, (a, b) => b.textSpan.start - a.textSpan.start);
1339+
let baselineFileContent = this.getFileContent(fileName);
1340+
for (const { textSpan } of sortedRenames) {
1341+
const isOriginalSpan = fileName === this.activeFile.fileName && ts.textSpanIntersectsWithPosition(textSpan, position);
1342+
baselineFileContent =
1343+
baselineFileContent.slice(0, textSpan.start) +
1344+
(isOriginalSpan ? "[|RENAME|]" : "RENAME") +
1345+
baselineFileContent.slice(textSpan.start + textSpan.length);
1346+
}
1347+
return `/*====== ${fileName} ======*/\n\n${baselineFileContent}`;
1348+
}).join("\n\n") + "\n";
1349+
1350+
Harness.Baseline.runBaseline(this.getBaselineFileNameForContainingTestFile(), baselineContent);
1351+
}
1352+
13221353
public verifyQuickInfoExists(negative: boolean) {
13231354
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
13241355
if (negative) {

src/harness/fourslashInterfaceImpl.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,10 @@ namespace FourSlashInterface {
516516
this.state.verifyRenameLocations(startRanges, options);
517517
}
518518

519+
public baselineRename(marker: string, options: RenameOptions) {
520+
this.state.baselineRename(marker, options);
521+
}
522+
519523
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: FourSlash.TextSpan,
520524
displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], tags: ts.JSDocTagInfo[]) {
521525
this.state.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation, tags);
@@ -1623,4 +1627,9 @@ namespace FourSlashInterface {
16231627
template: string
16241628
};
16251629
export type RenameLocationOptions = FourSlash.Range | { readonly range: FourSlash.Range, readonly prefixText?: string, readonly suffixText?: string };
1630+
export interface RenameOptions {
1631+
readonly findInStrings?: boolean;
1632+
readonly findInComments?: boolean;
1633+
readonly providePrefixAndSuffixTextForRename?: boolean;
1634+
};
16261635
}

src/services/codefixes/inferFromUsage.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,7 @@ namespace ts.codefix {
985985
const callSignatures: Signature[] = usage.calls ? [getSignatureFromCalls(usage.calls)] : [];
986986
const constructSignatures: Signature[] = usage.constructs ? [getSignatureFromCalls(usage.constructs)] : [];
987987
const stringIndexInfo = usage.stringIndex && checker.createIndexInfo(combineFromUsage(usage.stringIndex), /*isReadonly*/ false);
988-
return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined); // TODO: GH#18217
988+
return checker.createAnonymousType(/*symbol*/ undefined, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined);
989989
}
990990

991991
function inferNamedTypesFromProperties(usage: Usage): Type[] {
@@ -1089,7 +1089,7 @@ namespace ts.codefix {
10891089
}
10901090

10911091
function getFunctionFromCalls(calls: CallUsage[]) {
1092-
return checker.createAnonymousType(undefined!, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
1092+
return checker.createAnonymousType(/*symbol*/ undefined, createSymbolTable(), [getSignatureFromCalls(calls)], emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
10931093
}
10941094

10951095
function getSignatureFromCalls(calls: CallUsage[]): Signature {

src/services/findAllReferences.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1927,10 +1927,12 @@ namespace ts.FindAllReferences {
19271927
}
19281928

19291929
const exportSpecifier = getDeclarationOfKind<ExportSpecifier>(symbol, SyntaxKind.ExportSpecifier);
1930-
const localSymbol = exportSpecifier && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier);
1931-
if (localSymbol) {
1932-
const res = cbSymbol(localSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.Node);
1933-
if (res) return res;
1930+
if (!isForRenamePopulateSearchSymbolSet || exportSpecifier && !exportSpecifier.propertyName) {
1931+
const localSymbol = exportSpecifier && checker.getExportSpecifierLocalTargetSymbol(exportSpecifier);
1932+
if (localSymbol) {
1933+
const res = cbSymbol(localSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.Node);
1934+
if (res) return res;
1935+
}
19341936
}
19351937

19361938
// symbolAtLocation for a binding element is the local symbol. See if the search symbol is the property.

0 commit comments

Comments
 (0)