Skip to content

Commit 366518f

Browse files
authored
fix(typescript-estree): fix filename handling for vue JSX + markdown (typescript-eslint#1127)
* fix(typescript-estree): fix filename handling for vue JSX + markdown * fix: correct integration tests * fix: remove erroneous vue file * docs: add a readme for the integration tests * chore: respect known filenames, ignore unknown ones * fix: add explicit tests for filename/jsx handling * docs: explicitly state the expected behaviour for JSX * docs: correct wording * docs: correct wording * chore: new commit to force codecov
1 parent 17c956e commit 366518f

25 files changed

+4623
-17
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,6 @@
8080
"url": "https://opencollective.com/typescript-eslint"
8181
},
8282
"resolutions": {
83-
"typescript": "^3.7.0-dev.20191018"
83+
"typescript": "^3.7.0-dev.20191021"
8484
}
8585
}

packages/parser/README.md

+10-3
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,16 @@ The following additional configuration options are available by specifying them
4242

4343
- **`ecmaFeatures.jsx`** - default `false`. Enable parsing JSX when `true`. More details can be found [here](https://www.typescriptlang.org/docs/handbook/jsx.html).
4444

45-
- It's `false` on `*.ts` files regardless of this option.
46-
- It's `true` on `*.tsx` files regardless of this option.
47-
- Otherwise, it respects this option.
45+
NOTE: this setting does not effect known file types (.js, .jsx, .ts, .tsx, .json) because the typescript compiler has its own internal handling for known file extensions. The exact behaviour is as follows:
46+
47+
- if `parserOptions.project` is _not_ provided:
48+
- `.js`, `.jsx`, `.tsx` files are parsed as if this is true.
49+
- `.ts` files are parsed as if this is false.
50+
- unknown extensions (`.md`, `.vue`) will respect this setting.
51+
- if `parserOptions.project` is provided (i.e. you are using rules with type information):
52+
- `.js`, `.jsx`, `.tsx` files are parsed as if this is true.
53+
- `.ts` files are parsed as if this is false.
54+
- "unknown" extensions (`.md`, `.vue`) **are parsed as if this is false**.
4855

4956
- **`useJSXTextNode`** - default `true`. Please set `false` if you use this parser on ESLint v4. If this is `false`, the parser creates the AST of JSX texts as the legacy style.
5057

packages/typescript-estree/README.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,17 @@ Parses the given string of code with the options provided and returns an ESTree-
4747
// create a top-level comments array containing all comments
4848
comment: false,
4949

50-
// enable parsing JSX. For more details, see https://www.typescriptlang.org/docs/handbook/jsx.html
50+
/*
51+
* enable parsing JSX. For more details, see https://www.typescriptlang.org/docs/handbook/jsx.html
52+
*
53+
* NOTE: this setting does not effect known file types (.js, .jsx, .ts, .tsx, .json) because the
54+
* typescript compiler has its own internal handling for known file extensions.
55+
*
56+
* Exact behaviour:
57+
* - .js, .jsx, .tsx files are parsed as if this is true
58+
* - .ts files are parsed as if this is false
59+
* - unknown extensions (.md, .vue) will respect this setting
60+
*/
5161
jsx: false,
5262

5363
/*

packages/typescript-estree/src/create-program/createIsolatedProgram.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import debug from 'debug';
22
import * as ts from 'typescript'; // leave this as * as ts so people using util package don't need syntheticDefaultImports
33
import { Extra } from '../parser-options';
4-
import { ASTAndProgram, DEFAULT_COMPILER_OPTIONS } from './shared';
4+
import {
5+
ASTAndProgram,
6+
DEFAULT_COMPILER_OPTIONS,
7+
getScriptKind,
8+
} from './shared';
59

610
const log = debug('typescript-eslint:typescript-estree:createIsolatedProgram');
711

@@ -10,7 +14,11 @@ const log = debug('typescript-eslint:typescript-estree:createIsolatedProgram');
1014
* @returns Returns a new source file and program corresponding to the linted code
1115
*/
1216
function createIsolatedProgram(code: string, extra: Extra): ASTAndProgram {
13-
log('Getting isolated program for: %s', extra.filePath);
17+
log(
18+
'Getting isolated program in %s mode for: %s',
19+
extra.jsx ? 'TSX' : 'TS',
20+
extra.filePath,
21+
);
1422

1523
const compilerHost: ts.CompilerHost = {
1624
fileExists() {
@@ -34,7 +42,13 @@ function createIsolatedProgram(code: string, extra: Extra): ASTAndProgram {
3442
return '\n';
3543
},
3644
getSourceFile(filename: string) {
37-
return ts.createSourceFile(filename, code, ts.ScriptTarget.Latest, true);
45+
return ts.createSourceFile(
46+
filename,
47+
code,
48+
ts.ScriptTarget.Latest,
49+
true,
50+
getScriptKind(extra, filename),
51+
);
3852
},
3953
readFile() {
4054
return undefined;

packages/typescript-estree/src/create-program/createSourceFile.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
import debug from 'debug';
22
import * as ts from 'typescript'; // leave this as * as ts so people using util package don't need syntheticDefaultImports
33
import { Extra } from '../parser-options';
4+
import { getScriptKind } from './shared';
45

5-
const log = debug('typescript-eslint:typescript-estree:createIsolatedProgram');
6+
const log = debug('typescript-eslint:typescript-estree:createSourceFile');
67

78
function createSourceFile(code: string, extra: Extra): ts.SourceFile {
8-
log('Getting AST without type information for: %s', extra.filePath);
9+
log(
10+
'Getting AST without type information in %s mode for: %s',
11+
extra.jsx ? 'TSX' : 'TS',
12+
extra.filePath,
13+
);
914

1015
return ts.createSourceFile(
1116
extra.filePath,
1217
code,
1318
ts.ScriptTarget.Latest,
1419
/* setParentNodes */ true,
20+
getScriptKind(extra),
1521
);
1622
}
1723

packages/typescript-estree/src/create-program/shared.ts

+30
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,41 @@ function canonicalDirname(p: CanonicalPath): CanonicalPath {
4141
return path.dirname(p) as CanonicalPath;
4242
}
4343

44+
function getScriptKind(
45+
extra: Extra,
46+
filePath: string = extra.filePath,
47+
): ts.ScriptKind {
48+
const extension = path.extname(filePath).toLowerCase();
49+
// note - we respect the user's extension when it is known we could override it and force it to match their
50+
// jsx setting, but that could create weird situations where we throw parse errors when TSC doesn't
51+
switch (extension) {
52+
case '.ts':
53+
return ts.ScriptKind.TS;
54+
55+
case '.tsx':
56+
return ts.ScriptKind.TSX;
57+
58+
case '.js':
59+
return ts.ScriptKind.JS;
60+
61+
case '.jsx':
62+
return ts.ScriptKind.JSX;
63+
64+
case '.json':
65+
return ts.ScriptKind.JSON;
66+
67+
default:
68+
// unknown extension, force typescript to ignore the file extension, and respect the user's setting
69+
return extra.jsx ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
70+
}
71+
}
72+
4473
export {
4574
ASTAndProgram,
4675
canonicalDirname,
4776
CanonicalPath,
4877
DEFAULT_COMPILER_OPTIONS,
4978
getCanonicalFileName,
79+
getScriptKind,
5080
getTsconfigPath,
5181
};

0 commit comments

Comments
 (0)