Skip to content

Commit

Permalink
feat(parser): add parserOptions.emitDecoratorMetadata (#4646)
Browse files Browse the repository at this point in the history
  • Loading branch information
xboy2012 committed Mar 11, 2022
1 parent 43b9c23 commit e3dd343
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 2 deletions.
271 changes: 271 additions & 0 deletions packages/eslint-plugin/tests/rules/consistent-type-imports.test.ts
Expand Up @@ -14,6 +14,10 @@ const withMetaParserOptions = {
project: './tsconfig-withmeta.json',
};

const withMetaConfigParserOptions = {
emitDecoratorMetadata: true,
};

ruleTester.run('consistent-type-imports', rule, {
valid: [
`
Expand Down Expand Up @@ -346,6 +350,113 @@ ruleTester.run('consistent-type-imports', rule, {
`,
parserOptions: withMetaParserOptions,
},
{
code: `
import Foo from 'foo';
@deco
class A {
constructor(foo: Foo) {}
}
`,
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import Foo from 'foo';
class A {
@deco
foo: Foo;
}
`,
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import Foo from 'foo';
class A {
@deco
foo(foo: Foo) {}
}
`,
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import Foo from 'foo';
class A {
@deco
foo(): Foo {}
}
`,
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import Foo from 'foo';
class A {
foo(@deco foo: Foo) {}
}
`,
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import Foo from 'foo';
class A {
@deco
set foo(value: Foo) {}
}
`,
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import Foo from 'foo';
class A {
@deco
get foo() {}
set foo(value: Foo) {}
}
`,
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import Foo from 'foo';
class A {
@deco
get foo() {}
set ['foo'](value: Foo) {}
}
`,
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import type { Foo } from 'foo';
const key = 'k';
class A {
@deco
get [key]() {}
set [key](value: Foo) {}
}
`,
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import * as foo from 'foo';
@deco
class A {
constructor(foo: foo.Foo) {}
}
`,
parserOptions: withMetaConfigParserOptions,
},

// https://github.com/typescript-eslint/typescript-eslint/issues/2989
`
import type * as constants from './constants';
Expand Down Expand Up @@ -1522,6 +1633,166 @@ const a: Default = '';
],
parserOptions: withMetaParserOptions,
},
{
code: `
import type Foo from 'foo';
@deco
class A {
constructor(foo: Foo) {}
}
`,
output: noFormat`
import Foo from 'foo';
@deco
class A {
constructor(foo: Foo) {}
}
`,
errors: [
{
messageId: 'aImportInDecoMeta',
data: { typeImports: '"Foo"' },
line: 2,
column: 9,
},
],
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import type { Foo } from 'foo';
@deco
class A {
constructor(foo: Foo) {}
}
`,
output: noFormat`
import { Foo } from 'foo';
@deco
class A {
constructor(foo: Foo) {}
}
`,
errors: [
{
messageId: 'aImportInDecoMeta',
data: { typeImports: '"Foo"' },
line: 2,
column: 9,
},
],
parserOptions: withMetaConfigParserOptions,
},
{
code: noFormat`
import type { Type } from 'foo';
import { Foo, Bar } from 'foo';
@deco
class A {
constructor(foo: Foo) {}
}
type T = Bar;
`,
output: noFormat`
import type { Type , Bar } from 'foo';
import { Foo } from 'foo';
@deco
class A {
constructor(foo: Foo) {}
}
type T = Bar;
`,
errors: [
{
messageId: 'aImportIsOnlyTypes',
data: { typeImports: '"Bar"' },
line: 3,
column: 9,
},
],
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import { V } from 'foo';
import type { Foo, Bar, T } from 'foo';
@deco
class A {
constructor(foo: Foo) {}
foo(@deco bar: Bar) {}
}
`,
output: noFormat`
import { V , Foo, Bar} from 'foo';
import type { T } from 'foo';
@deco
class A {
constructor(foo: Foo) {}
foo(@deco bar: Bar) {}
}
`,
errors: [
{
messageId: 'someImportsInDecoMeta',
data: { typeImports: '"Foo" and "Bar"' },
line: 3,
column: 9,
},
],
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import type { Foo, T } from 'foo';
import { V } from 'foo';
@deco
class A {
constructor(foo: Foo) {}
}
`,
output: noFormat`
import type { T } from 'foo';
import { V , Foo} from 'foo';
@deco
class A {
constructor(foo: Foo) {}
}
`,
errors: [
{
messageId: 'aImportInDecoMeta',
data: { typeImports: '"Foo"' },
line: 2,
column: 9,
},
],
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import type * as Type from 'foo';
@deco
class A {
constructor(foo: Type.Foo) {}
}
`,
output: noFormat`
import * as Type from 'foo';
@deco
class A {
constructor(foo: Type.Foo) {}
}
`,
errors: [
{
messageId: 'aImportInDecoMeta',
data: { typeImports: '"Type"' },
line: 2,
column: 9,
},
],
parserOptions: withMetaConfigParserOptions,
},
{
code: `
import { type A, B } from 'foo';
Expand Down
8 changes: 8 additions & 0 deletions packages/parser/README.md
Expand Up @@ -67,6 +67,8 @@ interface ParserOptions {

program?: import('typescript').Program;
moduleResolver?: string;

emitDecoratorMetadata?: boolean;
}
```

Expand Down Expand Up @@ -246,6 +248,12 @@ interface ModuleResolver {

Note that if you pass custom programs via `options.programs` this option will not have any effect over them (you can simply add the custom resolution on them directly).

### `parserOptions.emitDecoratorMetadata`

Default `undefined`.

This option allow you to tell parser to act as if `emitDecoratorMetadata: true` is set in `tsconfig.json`, but without [type-aware linting](https://typescript-eslint.io/docs/linting/type-linting). In other words, you don't have to specify `parserOptions.project` in this case, making the linting process faster.

## Utilities

### `createProgram(configFile, projectDirectory)`
Expand Down
8 changes: 6 additions & 2 deletions packages/parser/src/parser.ts
Expand Up @@ -132,6 +132,7 @@ function parseForESLint(
const { ast, services } = parseAndGenerateServices(code, parserOptions);
ast.sourceType = options.sourceType;

let emitDecoratorMetadata = options.emitDecoratorMetadata === true;
if (services.hasFullTypeInformation) {
// automatically apply the options configured for the program
const compilerOptions = services.program.getCompilerOptions();
Expand Down Expand Up @@ -165,11 +166,14 @@ function parseForESLint(
}
}
if (compilerOptions.emitDecoratorMetadata === true) {
analyzeOptions.emitDecoratorMetadata =
compilerOptions.emitDecoratorMetadata;
emitDecoratorMetadata = true;
}
}

if (emitDecoratorMetadata) {
analyzeOptions.emitDecoratorMetadata = true;
}

const scopeManager = analyze(ast, analyzeOptions);

return { ast, services, scopeManager, visitorKeys };
Expand Down
3 changes: 3 additions & 0 deletions packages/types/src/parser-options.ts
Expand Up @@ -37,6 +37,9 @@ interface ParserOptions {
jsxFragmentName?: string | null;
lib?: Lib[];

// use emitDecoratorMetadata without specifying parserOptions.project
emitDecoratorMetadata?: boolean;

// typescript-estree specific
comment?: boolean;
debugLevel?: DebugLevel;
Expand Down

0 comments on commit e3dd343

Please sign in to comment.