Skip to content

Commit 6b05ad7

Browse files
committed
Merge pull request #7107 from Microsoft/ScriptBlockSupport
Salsa: adding ScriptKind to ensure script blocks are processed as JS.
2 parents ae8b943 + 2da73b3 commit 6b05ad7

File tree

6 files changed

+100
-35
lines changed

6 files changed

+100
-35
lines changed

src/compiler/parser.ts

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -399,14 +399,31 @@ namespace ts {
399399
}
400400
}
401401

402-
export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false): SourceFile {
402+
export function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
403403
const start = new Date().getTime();
404-
const result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes);
404+
const result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind);
405405

406406
parseTime += new Date().getTime() - start;
407407
return result;
408408
}
409409

410+
/* @internal */
411+
export function getScriptKindFromFileName(fileName: string): ScriptKind {
412+
const ext = fileName.substr(fileName.lastIndexOf("."));
413+
switch (ext.toLowerCase()) {
414+
case ".js":
415+
return ScriptKind.JS;
416+
case ".jsx":
417+
return ScriptKind.JSX;
418+
case ".ts":
419+
return ScriptKind.TS;
420+
case ".tsx":
421+
return ScriptKind.TSX;
422+
default:
423+
return ScriptKind.TS;
424+
}
425+
}
426+
410427
// Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter
411428
// indicates what changed between the 'text' that this SourceFile has and the 'newText'.
412429
// The SourceFile will be created with the compiler attempting to reuse as many nodes from
@@ -533,23 +550,29 @@ namespace ts {
533550
// attached to the EOF token.
534551
let parseErrorBeforeNextFinishedNode = false;
535552

536-
export function parseSourceFile(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, setParentNodes?: boolean): SourceFile {
537-
const isJavaScriptFile = hasJavaScriptFileExtension(fileName) || _sourceText.lastIndexOf("// @language=javascript", 0) === 0;
538-
initializeState(fileName, _sourceText, languageVersion, isJavaScriptFile, _syntaxCursor);
553+
export function parseSourceFile(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, setParentNodes?: boolean, scriptKind?: ScriptKind): SourceFile {
554+
// Using scriptKind as a condition handles both:
555+
// - 'scriptKind' is unspecified and thus it is `undefined`
556+
// - 'scriptKind' is set and it is `Unknown` (0)
557+
// If the 'scriptKind' is 'undefined' or 'Unknown' then attempt
558+
// to get the ScriptKind from the file name.
559+
scriptKind = scriptKind ? scriptKind : getScriptKindFromFileName(fileName);
560+
561+
initializeState(fileName, _sourceText, languageVersion, _syntaxCursor, scriptKind);
539562

540-
const result = parseSourceFileWorker(fileName, languageVersion, setParentNodes);
563+
const result = parseSourceFileWorker(fileName, languageVersion, setParentNodes, scriptKind);
541564

542565
clearState();
543566

544567
return result;
545568
}
546569

547-
function getLanguageVariant(fileName: string) {
570+
function getLanguageVariant(scriptKind: ScriptKind) {
548571
// .tsx and .jsx files are treated as jsx language variant.
549-
return fileExtensionIs(fileName, ".tsx") || fileExtensionIs(fileName, ".jsx") || fileExtensionIs(fileName, ".js") ? LanguageVariant.JSX : LanguageVariant.Standard;
572+
return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS ? LanguageVariant.JSX : LanguageVariant.Standard;
550573
}
551574

552-
function initializeState(fileName: string, _sourceText: string, languageVersion: ScriptTarget, isJavaScriptFile: boolean, _syntaxCursor: IncrementalParser.SyntaxCursor) {
575+
function initializeState(fileName: string, _sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, scriptKind: ScriptKind) {
553576
NodeConstructor = objectAllocator.getNodeConstructor();
554577
SourceFileConstructor = objectAllocator.getSourceFileConstructor();
555578

@@ -562,14 +585,14 @@ namespace ts {
562585
identifierCount = 0;
563586
nodeCount = 0;
564587

565-
contextFlags = isJavaScriptFile ? NodeFlags.JavaScriptFile : NodeFlags.None;
588+
contextFlags = scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX ? NodeFlags.JavaScriptFile : NodeFlags.None;
566589
parseErrorBeforeNextFinishedNode = false;
567590

568591
// Initialize and prime the scanner before parsing the source elements.
569592
scanner.setText(sourceText);
570593
scanner.setOnError(scanError);
571594
scanner.setScriptTarget(languageVersion);
572-
scanner.setLanguageVariant(getLanguageVariant(fileName));
595+
scanner.setLanguageVariant(getLanguageVariant(scriptKind));
573596
}
574597

575598
function clearState() {
@@ -585,8 +608,8 @@ namespace ts {
585608
sourceText = undefined;
586609
}
587610

588-
function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean): SourceFile {
589-
sourceFile = createSourceFile(fileName, languageVersion);
611+
function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind): SourceFile {
612+
sourceFile = createSourceFile(fileName, languageVersion, scriptKind);
590613
sourceFile.flags = contextFlags;
591614

592615
// Prime the scanner.
@@ -653,7 +676,7 @@ namespace ts {
653676
}
654677
}
655678

656-
function createSourceFile(fileName: string, languageVersion: ScriptTarget): SourceFile {
679+
function createSourceFile(fileName: string, languageVersion: ScriptTarget, scriptKind: ScriptKind): SourceFile {
657680
// code from createNode is inlined here so createNode won't have to deal with special case of creating source files
658681
// this is quite rare comparing to other nodes and createNode should be as fast as possible
659682
const sourceFile = <SourceFile>new SourceFileConstructor(SyntaxKind.SourceFile, /*pos*/ 0, /* end */ sourceText.length);
@@ -663,8 +686,9 @@ namespace ts {
663686
sourceFile.bindDiagnostics = [];
664687
sourceFile.languageVersion = languageVersion;
665688
sourceFile.fileName = normalizePath(fileName);
666-
sourceFile.languageVariant = getLanguageVariant(sourceFile.fileName);
689+
sourceFile.languageVariant = getLanguageVariant(scriptKind);
667690
sourceFile.isDeclarationFile = fileExtensionIs(sourceFile.fileName, ".d.ts");
691+
sourceFile.scriptKind = scriptKind;
668692

669693
return sourceFile;
670694
}
@@ -5589,7 +5613,7 @@ namespace ts {
55895613
}
55905614

55915615
export function parseJSDocTypeExpressionForTests(content: string, start: number, length: number) {
5592-
initializeState("file.js", content, ScriptTarget.Latest, /*isJavaScriptFile*/ true, /*_syntaxCursor:*/ undefined);
5616+
initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
55935617
scanner.setText(content, start, length);
55945618
token = scanner.scan();
55955619
const jsDocTypeExpression = parseJSDocTypeExpression();
@@ -5908,7 +5932,7 @@ namespace ts {
59085932
}
59095933

59105934
export function parseIsolatedJSDocComment(content: string, start: number, length: number) {
5911-
initializeState("file.js", content, ScriptTarget.Latest, /*isJavaScriptFile*/ true, /*_syntaxCursor:*/ undefined);
5935+
initializeState("file.js", content, ScriptTarget.Latest, /*_syntaxCursor:*/ undefined, ScriptKind.JS);
59125936
sourceFile = <SourceFile>{ languageVariant: LanguageVariant.Standard, text: content };
59135937
const jsDocComment = parseJSDocCommentWorker(start, length);
59145938
const diagnostics = parseDiagnostics;
@@ -6234,7 +6258,7 @@ namespace ts {
62346258
if (sourceFile.statements.length === 0) {
62356259
// If we don't have any statements in the current source file, then there's no real
62366260
// way to incrementally parse. So just do a full parse instead.
6237-
return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true);
6261+
return Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setParentNodes*/ true, sourceFile.scriptKind);
62386262
}
62396263

62406264
// Make sure we're not trying to incrementally update a source file more than once. Once
@@ -6298,7 +6322,7 @@ namespace ts {
62986322
// inconsistent tree. Setting the parents on the new tree should be very fast. We
62996323
// will immediately bail out of walking any subtrees when we can see that their parents
63006324
// are already correct.
6301-
const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true);
6325+
const result = Parser.parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, syntaxCursor, /*setParentNodes*/ true, sourceFile.scriptKind);
63026326

63036327
return result;
63046328
}

src/compiler/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
namespace ts {
23
export interface Map<T> {
34
[index: string]: T;
@@ -1530,6 +1531,7 @@ namespace ts {
15301531
hasNoDefaultLib: boolean;
15311532

15321533
languageVersion: ScriptTarget;
1534+
/* @internal */ scriptKind: ScriptKind;
15331535

15341536
// The first node that causes this file to be an external module
15351537
/* @internal */ externalModuleIndicator: Node;
@@ -2459,6 +2461,14 @@ namespace ts {
24592461
character: number;
24602462
}
24612463

2464+
export const enum ScriptKind {
2465+
Unknown = 0,
2466+
JS = 1,
2467+
JSX = 2,
2468+
TS = 3,
2469+
TSX = 4
2470+
}
2471+
24622472
export const enum ScriptTarget {
24632473
ES3 = 0,
24642474
ES5 = 1,

src/harness/harnessLanguageService.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ namespace Harness.LanguageService {
183183
const script = this.getScriptInfo(fileName);
184184
return script ? new ScriptSnapshot(script) : undefined;
185185
}
186+
getScriptKind(fileName: string): ts.ScriptKind { return ts.ScriptKind.Unknown; }
186187
getScriptVersion(fileName: string): string {
187188
const script = this.getScriptInfo(fileName);
188189
return script ? script.version.toString() : undefined;
@@ -253,6 +254,7 @@ namespace Harness.LanguageService {
253254
const nativeScriptSnapshot = this.nativeHost.getScriptSnapshot(fileName);
254255
return nativeScriptSnapshot && new ScriptSnapshotProxy(nativeScriptSnapshot);
255256
}
257+
getScriptKind(fileName: string): ts.ScriptKind { return this.nativeHost.getScriptKind(fileName); }
256258
getScriptVersion(fileName: string): string { return this.nativeHost.getScriptVersion(fileName); }
257259
getLocalizedDiagnosticMessages(): string { return JSON.stringify({}); }
258260

src/server/editorServices.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ namespace ts.server {
192192
return this.roots.map(root => root.fileName);
193193
}
194194

195+
getScriptKind() {
196+
return ScriptKind.Unknown;
197+
}
198+
195199
getScriptVersion(filename: string) {
196200
return this.getScriptInfo(filename).svc.latestVersion().toString();
197201
}

0 commit comments

Comments
 (0)