Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(typescript-estree): fix filename handling for vue JSX + markdown #1127

Merged
merged 12 commits into from Nov 3, 2019
Merged
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -80,6 +80,6 @@
"url": "https://opencollective.com/typescript-eslint"
},
"resolutions": {
"typescript": "^3.7.0-dev.20191018"
"typescript": "^3.7.0-dev.20191021"
}
}
13 changes: 10 additions & 3 deletions packages/parser/README.md
Expand Up @@ -42,9 +42,16 @@ The following additional configuration options are available by specifying them

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

- It's `false` on `*.ts` files regardless of this option.
- It's `true` on `*.tsx` files regardless of this option.
- Otherwise, it respects this option.
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:

- if `parserOptions.project` is _not_ provided:
- `.js`, `.jsx`, `.tsx` files are parsed as if this is true.
- `.ts` files are parsed as if this is false.
- unknown extensions (`.md`, `.vue`) will respect this setting.
- if `parserOptions.project` is provided (i.e. you are using rules with type information):
- `.js`, `.jsx`, `.tsx` files are parsed as if this is true.
- `.ts` files are parsed as if this is false.
- "unknown" extensions (`.md`, `.vue`) **are parsed as if this is false**.
bradzacher marked this conversation as resolved.
Show resolved Hide resolved

- **`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.

Expand Down
12 changes: 11 additions & 1 deletion packages/typescript-estree/README.md
Expand Up @@ -47,7 +47,17 @@ Parses the given string of code with the options provided and returns an ESTree-
// create a top-level comments array containing all comments
comment: false,

// enable parsing JSX. For more details, see https://www.typescriptlang.org/docs/handbook/jsx.html
/*
* enable parsing JSX. For more details, see https://www.typescriptlang.org/docs/handbook/jsx.html
*
* 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.
*
* Exact behaviour:
* - .js, .jsx, .tsx files are parsed as if this is true
* - .ts files are parsed as if this is false
* - unknown extensions (.md, .vue) will respect this setting
*/
jsx: false,

/*
Expand Down
@@ -1,7 +1,11 @@
import debug from 'debug';
import * as ts from 'typescript'; // leave this as * as ts so people using util package don't need syntheticDefaultImports
import { Extra } from '../parser-options';
import { ASTAndProgram, DEFAULT_COMPILER_OPTIONS } from './shared';
import {
ASTAndProgram,
DEFAULT_COMPILER_OPTIONS,
getScriptKind,
} from './shared';

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

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

const compilerHost: ts.CompilerHost = {
fileExists() {
Expand All @@ -34,7 +42,13 @@ function createIsolatedProgram(code: string, extra: Extra): ASTAndProgram {
return '\n';
},
getSourceFile(filename: string) {
return ts.createSourceFile(filename, code, ts.ScriptTarget.Latest, true);
return ts.createSourceFile(
filename,
code,
ts.ScriptTarget.Latest,
true,
getScriptKind(extra, filename),
);
},
readFile() {
return undefined;
Expand Down
@@ -1,17 +1,23 @@
import debug from 'debug';
import * as ts from 'typescript'; // leave this as * as ts so people using util package don't need syntheticDefaultImports
import { Extra } from '../parser-options';
import { getScriptKind } from './shared';

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

function createSourceFile(code: string, extra: Extra): ts.SourceFile {
log('Getting AST without type information for: %s', extra.filePath);
log(
'Getting AST without type information in %s mode for: %s',
extra.jsx ? 'TSX' : 'TS',
extra.filePath,
);

return ts.createSourceFile(
extra.filePath,
code,
ts.ScriptTarget.Latest,
/* setParentNodes */ true,
getScriptKind(extra),
);
}

Expand Down
30 changes: 30 additions & 0 deletions packages/typescript-estree/src/create-program/shared.ts
Expand Up @@ -41,11 +41,41 @@ function canonicalDirname(p: CanonicalPath): CanonicalPath {
return path.dirname(p) as CanonicalPath;
}

function getScriptKind(
extra: Extra,
filePath: string = extra.filePath,
): ts.ScriptKind {
const extension = path.extname(filePath).toLowerCase();
// note - we respect the user's extension when it is known we could override it and force it to match their
// jsx setting, but that could create weird situations where we throw parse errors when TSC doesn't
switch (extension) {
case '.ts':
return ts.ScriptKind.TS;

case '.tsx':
return ts.ScriptKind.TSX;

case '.js':
return ts.ScriptKind.JS;
bradzacher marked this conversation as resolved.
Show resolved Hide resolved

case '.jsx':
return ts.ScriptKind.JSX;

case '.json':
return ts.ScriptKind.JSON;

default:
// unknown extension, force typescript to ignore the file extension, and respect the user's setting
return extra.jsx ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
}
}

export {
ASTAndProgram,
canonicalDirname,
CanonicalPath,
DEFAULT_COMPILER_OPTIONS,
getCanonicalFileName,
getScriptKind,
getTsconfigPath,
};