Skip to content

Commit b728bf4

Browse files
committed
Merge branch 'master' of https://github.com/Microsoft/TypeScript into feature/eslint
2 parents 466ee10 + 602966b commit b728bf4

84 files changed

Lines changed: 2879 additions & 290 deletions

File tree

Some content is hidden

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

src/compiler/checker.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23157,8 +23157,8 @@ namespace ts {
2315723157
}
2315823158

2315923159
function checkImportMetaProperty(node: MetaProperty) {
23160-
if (languageVersion < ScriptTarget.ESNext || moduleKind < ModuleKind.ESNext) {
23161-
error(node, Diagnostics.The_import_meta_meta_property_is_only_allowed_using_ESNext_for_the_target_and_module_compiler_options);
23160+
if (moduleKind !== ModuleKind.ESNext && moduleKind !== ModuleKind.System) {
23161+
error(node, Diagnostics.The_import_meta_meta_property_is_only_allowed_when_the_module_option_is_esnext_or_system);
2316223162
}
2316323163
const file = getSourceFileOfNode(node);
2316423164
Debug.assert(!!(file.flags & NodeFlags.PossiblyContainsImportMeta), "Containing file is missing import meta node flag.");
@@ -25268,7 +25268,18 @@ namespace ts {
2526825268
}
2526925269

2527025270
function checkExpressionWorker(node: Expression | QualifiedName, checkMode: CheckMode | undefined, forceTuple?: boolean): Type {
25271-
switch (node.kind) {
25271+
const kind = node.kind;
25272+
if (cancellationToken) {
25273+
// Only bother checking on a few construct kinds. We don't want to be excessively
25274+
// hitting the cancellation token on every node we check.
25275+
switch (kind) {
25276+
case SyntaxKind.ClassExpression:
25277+
case SyntaxKind.FunctionExpression:
25278+
case SyntaxKind.ArrowFunction:
25279+
cancellationToken.throwIfCancellationRequested();
25280+
}
25281+
}
25282+
switch (kind) {
2527225283
case SyntaxKind.Identifier:
2527325284
return checkIdentifier(<Identifier>node);
2527425285
case SyntaxKind.ThisKeyword:

src/compiler/diagnosticMessages.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,10 @@
851851
"category": "Error",
852852
"code": 1259
853853
},
854+
"Keywords cannot contain escape characters.": {
855+
"category": "Error",
856+
"code": 1260
857+
},
854858
"'with' statements are not allowed in an async function block.": {
855859
"category": "Error",
856860
"code": 1300
@@ -979,7 +983,7 @@
979983
"category": "Error",
980984
"code": 1342
981985
},
982-
"The 'import.meta' meta-property is only allowed using 'ESNext' for the 'target' and 'module' compiler options.": {
986+
"The 'import.meta' meta-property is only allowed when the '--module' option is 'esnext' or 'system'.": {
983987
"category": "Error",
984988
"code": 1343
985989
},

src/compiler/emitter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,7 @@ namespace ts {
752752
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
753753
getProgramBuildInfo: returnUndefined,
754754
getSourceFileFromReference: returnUndefined,
755+
redirectTargetsMap: createMultiMap()
755756
};
756757
emitFiles(
757758
notImplementedResolver,

src/compiler/factory.ts

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,30 +1330,100 @@ namespace ts {
13301330
: node;
13311331
}
13321332

1333-
export function createTemplateHead(text: string) {
1334-
const node = <TemplateHead>createSynthesizedNode(SyntaxKind.TemplateHead);
1333+
let rawTextScanner: Scanner | undefined;
1334+
const invalidValueSentinel: object = {};
1335+
1336+
function getCookedText(kind: TemplateLiteralToken["kind"], rawText: string) {
1337+
if (!rawTextScanner) {
1338+
rawTextScanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false, LanguageVariant.Standard);
1339+
}
1340+
switch (kind) {
1341+
case SyntaxKind.NoSubstitutionTemplateLiteral:
1342+
rawTextScanner.setText("`" + rawText + "`");
1343+
break;
1344+
case SyntaxKind.TemplateHead:
1345+
// tslint:disable-next-line no-invalid-template-strings
1346+
rawTextScanner.setText("`" + rawText + "${");
1347+
break;
1348+
case SyntaxKind.TemplateMiddle:
1349+
// tslint:disable-next-line no-invalid-template-strings
1350+
rawTextScanner.setText("}" + rawText + "${");
1351+
break;
1352+
case SyntaxKind.TemplateTail:
1353+
rawTextScanner.setText("}" + rawText + "`");
1354+
break;
1355+
}
1356+
1357+
let token = rawTextScanner.scan();
1358+
if (token === SyntaxKind.CloseBracketToken) {
1359+
token = rawTextScanner.reScanTemplateToken();
1360+
}
1361+
1362+
if (rawTextScanner.isUnterminated()) {
1363+
rawTextScanner.setText(undefined);
1364+
return invalidValueSentinel;
1365+
}
1366+
1367+
let tokenValue: string | undefined;
1368+
switch (token) {
1369+
case SyntaxKind.NoSubstitutionTemplateLiteral:
1370+
case SyntaxKind.TemplateHead:
1371+
case SyntaxKind.TemplateMiddle:
1372+
case SyntaxKind.TemplateTail:
1373+
tokenValue = rawTextScanner.getTokenValue();
1374+
break;
1375+
}
1376+
1377+
if (rawTextScanner.scan() !== SyntaxKind.EndOfFileToken) {
1378+
rawTextScanner.setText(undefined);
1379+
return invalidValueSentinel;
1380+
}
1381+
1382+
rawTextScanner.setText(undefined);
1383+
return tokenValue;
1384+
}
1385+
1386+
function createTemplateLiteralLikeNode(kind: TemplateLiteralToken["kind"], text: string, rawText: string | undefined) {
1387+
const node = <TemplateLiteralLikeNode>createSynthesizedNode(kind);
13351388
node.text = text;
1389+
if (rawText === undefined || text === rawText) {
1390+
node.rawText = rawText;
1391+
}
1392+
else {
1393+
const cooked = getCookedText(kind, rawText);
1394+
if (typeof cooked === "object") {
1395+
return Debug.fail("Invalid raw text");
1396+
}
1397+
1398+
Debug.assert(text === cooked, "Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'.");
1399+
node.rawText = rawText;
1400+
}
13361401
return node;
13371402
}
13381403

1339-
export function createTemplateMiddle(text: string) {
1340-
const node = <TemplateMiddle>createSynthesizedNode(SyntaxKind.TemplateMiddle);
1404+
export function createTemplateHead(text: string, rawText?: string) {
1405+
const node = <TemplateHead>createTemplateLiteralLikeNode(SyntaxKind.TemplateHead, text, rawText);
13411406
node.text = text;
13421407
return node;
13431408
}
13441409

1345-
export function createTemplateTail(text: string) {
1346-
const node = <TemplateTail>createSynthesizedNode(SyntaxKind.TemplateTail);
1410+
export function createTemplateMiddle(text: string, rawText?: string) {
1411+
const node = <TemplateMiddle>createTemplateLiteralLikeNode(SyntaxKind.TemplateMiddle, text, rawText);
13471412
node.text = text;
13481413
return node;
13491414
}
13501415

1351-
export function createNoSubstitutionTemplateLiteral(text: string) {
1352-
const node = <NoSubstitutionTemplateLiteral>createSynthesizedNode(SyntaxKind.NoSubstitutionTemplateLiteral);
1416+
export function createTemplateTail(text: string, rawText?: string) {
1417+
const node = <TemplateTail>createTemplateLiteralLikeNode(SyntaxKind.TemplateTail, text, rawText);
13531418
node.text = text;
13541419
return node;
13551420
}
13561421

1422+
export function createNoSubstitutionTemplateLiteral(text: string, rawText?: string) {
1423+
const node = <NoSubstitutionTemplateLiteral>createTemplateLiteralLikeNode(SyntaxKind.NoSubstitutionTemplateLiteral, text, rawText);
1424+
return node;
1425+
}
1426+
13571427
export function createYield(expression?: Expression): YieldExpression;
13581428
export function createYield(asteriskToken: AsteriskToken | undefined, expression: Expression): YieldExpression;
13591429
export function createYield(asteriskTokenOrExpression?: AsteriskToken | undefined | Expression, expression?: Expression) {

src/compiler/moduleSpecifiers.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ namespace ts.moduleSpecifiers {
115115
function getLocalModuleSpecifier(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, compilerOptions: CompilerOptions, { ending, relativePreference }: Preferences): string {
116116
const { baseUrl, paths, rootDirs } = compilerOptions;
117117

118-
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName) ||
118+
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName, ending, compilerOptions) ||
119119
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), ending, compilerOptions);
120120
if (!baseUrl || relativePreference === RelativePreference.Relative) {
121121
return relativePath;
@@ -249,15 +249,17 @@ namespace ts.moduleSpecifiers {
249249
}
250250
}
251251

252-
function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string): string | undefined {
252+
function tryGetModuleNameFromRootDirs(rootDirs: readonly string[], moduleFileName: string, sourceDirectory: string, getCanonicalFileName: (file: string) => string, ending: Ending, compilerOptions: CompilerOptions): string | undefined {
253253
const normalizedTargetPath = getPathRelativeToRootDirs(moduleFileName, rootDirs, getCanonicalFileName);
254254
if (normalizedTargetPath === undefined) {
255255
return undefined;
256256
}
257257

258258
const normalizedSourcePath = getPathRelativeToRootDirs(sourceDirectory, rootDirs, getCanonicalFileName);
259259
const relativePath = normalizedSourcePath !== undefined ? ensurePathIsNonModuleName(getRelativePathFromDirectory(normalizedSourcePath, normalizedTargetPath, getCanonicalFileName)) : normalizedTargetPath;
260-
return removeFileExtension(relativePath);
260+
return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs
261+
? removeExtensionAndIndexPostFix(relativePath, ending, compilerOptions)
262+
: removeFileExtension(relativePath);
261263
}
262264

263265
function tryGetModuleNameAsNodeModule(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, host: ModuleSpecifierResolutionHost, options: CompilerOptions): string | undefined {

src/compiler/parser.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,10 +1082,19 @@ namespace ts {
10821082
return currentToken;
10831083
}
10841084

1085-
function nextToken(): SyntaxKind {
1085+
function nextTokenWithoutCheck() {
10861086
return currentToken = scanner.scan();
10871087
}
10881088

1089+
function nextToken(): SyntaxKind {
1090+
// if the keyword had an escape
1091+
if (isKeyword(currentToken) && (scanner.hasUnicodeEscape() || scanner.hasExtendedUnicodeEscape())) {
1092+
// issue a parse error for the escape
1093+
parseErrorAt(scanner.getTokenPos(), scanner.getTextPos(), Diagnostics.Keywords_cannot_contain_escape_characters);
1094+
}
1095+
return nextTokenWithoutCheck();
1096+
}
1097+
10891098
function nextTokenJSDoc(): JSDocSyntaxKind {
10901099
return currentToken = scanner.scanJsDocToken();
10911100
}
@@ -1376,7 +1385,7 @@ namespace ts {
13761385
node.originalKeywordKind = token();
13771386
}
13781387
node.escapedText = escapeLeadingUnderscores(internIdentifier(scanner.getTokenValue()));
1379-
nextToken();
1388+
nextTokenWithoutCheck();
13801389
return finishNode(node);
13811390
}
13821391

@@ -2287,9 +2296,19 @@ namespace ts {
22872296
return <TemplateMiddle | TemplateTail>fragment;
22882297
}
22892298

2290-
function parseLiteralLikeNode(kind: SyntaxKind): LiteralExpression | LiteralLikeNode {
2291-
const node = <LiteralExpression>createNode(kind);
2299+
function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode {
2300+
const node = <LiteralLikeNode>createNode(kind);
22922301
node.text = scanner.getTokenValue();
2302+
switch (kind) {
2303+
case SyntaxKind.NoSubstitutionTemplateLiteral:
2304+
case SyntaxKind.TemplateHead:
2305+
case SyntaxKind.TemplateMiddle:
2306+
case SyntaxKind.TemplateTail:
2307+
const isLast = kind === SyntaxKind.NoSubstitutionTemplateLiteral || kind === SyntaxKind.TemplateTail;
2308+
const tokenText = scanner.getTokenText();
2309+
(<TemplateLiteralLikeNode>node).rawText = tokenText.substring(1, tokenText.length - (scanner.isUnterminated() ? 0 : isLast ? 1 : 2));
2310+
break;
2311+
}
22932312

22942313
if (scanner.hasExtendedUnicodeEscape()) {
22952314
node.hasExtendedUnicodeEscape = true;

src/compiler/program.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,7 @@ namespace ts {
14431443
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
14441444
getProgramBuildInfo: () => program.getProgramBuildInfo && program.getProgramBuildInfo(),
14451445
getSourceFileFromReference: (file, ref) => program.getSourceFileFromReference(file, ref),
1446+
redirectTargetsMap,
14461447
};
14471448
}
14481449

src/compiler/scanner.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace ts {
1818
getTokenPos(): number;
1919
getTokenText(): string;
2020
getTokenValue(): string;
21+
hasUnicodeEscape(): boolean;
2122
hasExtendedUnicodeEscape(): boolean;
2223
hasPrecedingLineBreak(): boolean;
2324
isIdentifier(): boolean;
@@ -885,6 +886,7 @@ namespace ts {
885886
getTokenPos: () => tokenPos,
886887
getTokenText: () => text.substring(tokenPos, pos),
887888
getTokenValue: () => tokenValue,
889+
hasUnicodeEscape: () => (tokenFlags & TokenFlags.UnicodeEscape) !== 0,
888890
hasExtendedUnicodeEscape: () => (tokenFlags & TokenFlags.ExtendedUnicodeEscape) !== 0,
889891
hasPrecedingLineBreak: () => (tokenFlags & TokenFlags.PrecedingLineBreak) !== 0,
890892
isIdentifier: () => token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord,
@@ -1246,6 +1248,7 @@ namespace ts {
12461248
return scanExtendedUnicodeEscape();
12471249
}
12481250

1251+
tokenFlags |= TokenFlags.UnicodeEscape;
12491252
// '\uDDDD'
12501253
return scanHexadecimalEscape(/*numDigits*/ 4);
12511254

@@ -1377,6 +1380,7 @@ namespace ts {
13771380
if (!(ch >= 0 && isIdentifierPart(ch, languageVersion))) {
13781381
break;
13791382
}
1383+
tokenFlags |= TokenFlags.UnicodeEscape;
13801384
result += text.substring(start, pos);
13811385
result += utf16EncodeAsString(ch);
13821386
// Valid Unicode escape is always six characters
@@ -1869,6 +1873,7 @@ namespace ts {
18691873
const cookedChar = peekUnicodeEscape();
18701874
if (cookedChar >= 0 && isIdentifierStart(cookedChar, languageVersion)) {
18711875
pos += 6;
1876+
tokenFlags |= TokenFlags.UnicodeEscape;
18721877
tokenValue = String.fromCharCode(cookedChar) + scanIdentifierParts();
18731878
return token = getIdentifierToken();
18741879
}
@@ -2157,6 +2162,7 @@ namespace ts {
21572162
const cookedChar = peekUnicodeEscape();
21582163
if (cookedChar >= 0 && isIdentifierStart(cookedChar, languageVersion)) {
21592164
pos += 6;
2165+
tokenFlags |= TokenFlags.UnicodeEscape;
21602166
tokenValue = String.fromCharCode(cookedChar) + scanIdentifierParts();
21612167
return token = getIdentifierToken();
21622168
}

src/compiler/transformers/declarations.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,26 @@ namespace ts {
327327
}
328328

329329
if (declFileName) {
330+
const specifier = moduleSpecifiers.getModuleSpecifier(
331+
// We pathify the baseUrl since we pathify the other paths here, so we can still easily check if the other paths are within the baseUrl
332+
// TODO: Should we _always_ be pathifying the baseUrl as we read it in?
333+
{ ...options, baseUrl: options.baseUrl && toPath(options.baseUrl, host.getCurrentDirectory(), host.getCanonicalFileName) },
334+
currentSourceFile,
335+
toPath(outputFilePath, host.getCurrentDirectory(), host.getCanonicalFileName),
336+
toPath(declFileName, host.getCurrentDirectory(), host.getCanonicalFileName),
337+
host,
338+
host.getSourceFiles(),
339+
/*preferences*/ undefined,
340+
host.redirectTargetsMap
341+
);
342+
if (!pathIsRelative(specifier)) {
343+
// If some compiler option/symlink/whatever allows access to the file containing the ambient module declaration
344+
// via a non-relative name, emit a type reference directive to that non-relative name, rather than
345+
// a relative path to the declaration file
346+
recordTypeReferenceDirectivesIfNecessary([specifier]);
347+
return;
348+
}
349+
330350
let fileName = getRelativePathToDirectoryOrUrl(
331351
outputFilePath,
332352
declFileName,

src/compiler/transformers/es2015.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3993,18 +3993,21 @@ namespace ts {
39933993
*
39943994
* @param node The ES6 template literal.
39953995
*/
3996-
function getRawLiteral(node: LiteralLikeNode) {
3996+
function getRawLiteral(node: TemplateLiteralLikeNode) {
39973997
// Find original source text, since we need to emit the raw strings of the tagged template.
39983998
// The raw strings contain the (escaped) strings of what the user wrote.
39993999
// Examples: `\n` is converted to "\\n", a template string with a newline to "\n".
4000-
let text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node);
4001-
4002-
// text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"),
4003-
// thus we need to remove those characters.
4004-
// First template piece starts with "`", others with "}"
4005-
// Last template piece ends with "`", others with "${"
4006-
const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail;
4007-
text = text.substring(1, text.length - (isLast ? 1 : 2));
4000+
let text = node.rawText;
4001+
if (text === undefined) {
4002+
text = getSourceTextOfNodeFromSourceFile(currentSourceFile, node);
4003+
4004+
// text contains the original source, it will also contain quotes ("`"), dolar signs and braces ("${" and "}"),
4005+
// thus we need to remove those characters.
4006+
// First template piece starts with "`", others with "}"
4007+
// Last template piece ends with "`", others with "${"
4008+
const isLast = node.kind === SyntaxKind.NoSubstitutionTemplateLiteral || node.kind === SyntaxKind.TemplateTail;
4009+
text = text.substring(1, text.length - (isLast ? 1 : 2));
4010+
}
40084011

40094012
// Newline normalization:
40104013
// ES6 Spec 11.8.6.1 - Static Semantics of TV's and TRV's

0 commit comments

Comments
 (0)