From 392a758ba5456dbe13582a222e839d098535caf5 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sat, 27 Jan 2018 18:48:47 -0800 Subject: [PATCH 01/23] Initial eslint type defintion --- types/eslint/eslint-tests.ts | 99 ++++++++++++++++++ types/eslint/index.d.ts | 190 +++++++++++++++++++++++++++++++++++ types/eslint/tsconfig.json | 23 +++++ types/eslint/tslint.json | 1 + 4 files changed, 313 insertions(+) create mode 100644 types/eslint/eslint-tests.ts create mode 100644 types/eslint/index.d.ts create mode 100644 types/eslint/tsconfig.json create mode 100644 types/eslint/tslint.json diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts new file mode 100644 index 0000000000..6b60ef8757 --- /dev/null +++ b/types/eslint/eslint-tests.ts @@ -0,0 +1,99 @@ +import { SourceCode, Linter, CLIEngine, RuleTester } from 'eslint'; + +// ============================================= +// Linter +// ============================================= + +const SOURCE = `var foo = bar;`; + +const sourceCode = new SourceCode(SOURCE, {}); + +const linter = new Linter(); + +linter.verify(SOURCE, { + rules: { + eqeqeq: 'off', + 'no-console': 'error', + quotes: ['error', 'double'] + }, +}, { + filename: 'test.js', +}); + +linter.verifyAndFix(SOURCE, { + rules: { + 'no-console': 'error', + } +}, { + filename: 'test.js', +}); + +linter.defineRule('my-fancy-rule', { + create() {}, +}); + +linter.defineRules({ + 'my-fancy-rule': { create() {} }, + 'my-fancy-other-rule': { create() {} } +}); + +linter.getRules(); + +linter.getSourceCode(); + +// ============================================= +// CLI +// ============================================= + +const cli = new CLIEngine({ + envs: ['browser', 'mocha'], + useEslintrc: false, + rules: { + semi: 2 + } +}); + +cli.executeOnFiles(['myfile.js', 'lib/']); + +const report = cli.executeOnText(SOURCE, 'foo'); + +cli.resolveFileGlobPatterns(['**/*']); + +cli.getConfigForFile('./config.json'); + +cli.addPlugin('my-fancy-plugin', {}); + +cli.isPathIgnored('./dist/index.js'); + +const formatter = cli.getFormatter('codeframe'); +formatter(report.results); + +CLIEngine.getErrorResults(report.results); + +CLIEngine.outputFixes(report); + +// ============================================= +// RuleTester +// ============================================= + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } }); + +ruleTester.run("my-rule", {}, { + valid: [ + { + code: "var foo = true", + options: [{ allowFoo: true }] + } + ], + + invalid: [ + { + code: "var invalidVariable = true", + errors: [{ message: "Unexpected invalid variable." }] + }, + { + code: "var invalidVariable = true", + errors: [{ message: /^Unexpected.+variable/ }] + } + ] +}); diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts new file mode 100644 index 0000000000..7e04f5ebc7 --- /dev/null +++ b/types/eslint/index.d.ts @@ -0,0 +1,190 @@ +// Type definitions for eslint 4.16 +// Project: https://eslint.org +// Definitions by: Pierre-Marie Dartus +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped + +export class SourceCode { + text: string; + ast: any; + lines: string[]; + + constructor(text: string, ast: any); +} + +export type RuleLevel = 'off' | 'warn' | 'error' | 0 | 1 | 2; + +export interface Config { + rules?: { + [name: string]: (RuleLevel | [RuleLevel, any]) + }; + parser?: string; + parserOptions?: any; + settings?: any; + env?: { [name: string]: boolean }; + globals?: { [name: string]: boolean }; +} + +export interface LintOptions { + filename?: string; + preprocess?: (code: string) => string[]; + postprocess?: (problemLists: LintMessage[][]) => LintMessage[]; + allowInlineConfig?: boolean; + reportUnusedDisableDirectives?: boolean; +} + +export type Severity = 1 | 2; + +export interface LintMessage { + column: number; + line: number; + endColumn?: number; + endLine?: number; + ruleId: string | null; + message: string; + nodeType: string; + fatal?: true; + severity: Severity; + fix?: Fix; + source: string | null; +} + +export interface FixOptions extends LintOptions { + fix?: boolean; +} + +export interface Fix { + range: [number, number]; + text: string; +} + +export interface FixReport { + fixed: boolean; + output: string; + messages: LintMessage[]; +} + +export type RuleModule = any; + +export type ParserModule = any; + +export class Linter { + version: string; + + verify(code: SourceCode | string, config: Config, filename?: string): LintMessage[]; + verify(code: SourceCode | string, config: Config, options: LintOptions): LintMessage[]; + + verifyAndFix(code: string, config: Config, filename?: string): FixReport; + verifyAndFix(code: string, config: Config, options: FixOptions): FixReport; + + getSourceCode(): SourceCode; + + defineRule(name: string, rule: RuleModule): void; + + defineRules(rules: { [name: string]: RuleModule }): void; + + getRules(): Map; + + defineParser(name: string, parser: ParserModule): void; +} + +export class CLIEngineOptions { + allowInlineConfig?: boolean; + baseConfig?: boolean; + cache?: boolean; + cacheFile?: string; + configFile?: string; + cwd?: string; + envs?: string[]; + extensions?: string[]; + fix?: boolean; + globals?: string[]; + ignore?: boolean; + ignorePath?: string; + ignorePattern?: string; + useEslintrc?: boolean; + parser?: string; + parserOptions?: any; + plugins?: string[]; + rules?: { + [name: string]: (RuleLevel | [RuleLevel, any]); + }; + rulePaths?: string[]; +} + +export interface LintResult { + filePath: string; + messages: LintMessage[]; + errorCount: number; + warningCount: number; + fixableErrorCount: number; + fixableWarningCount: number; + output?: string; + source?: string; +} + +export interface LintReport { + results: LintResult[]; + errorCount: number; + warningCount: number; + fixableErrorCount: number; + fixableWarningCount: number; +} + +export type Formatter = (results: LintResult[]) => string; + +export class CLIEngine { + version: string; + + constructor(options: CLIEngineOptions); + + executeOnFiles(patterns: string[]): LintReport; + + resolveFileGlobPatterns(patterns: string[]): string[]; + + getConfigForFile(filePath: string): Config; + + executeOnText(text: string, filename?: string): LintReport; + + addPlugin(name: string, pluginObject: any): void; + + isPathIgnored(filePath: string): boolean; + + getFormatter(format: string): Formatter; + + static getErrorResults(results: LintResult[]): LintResult[]; + + static outputFixes(report: LintReport): void; + + getRules(): Map; +} + +export interface ValidTestCase { + code: string; + options?: any; + filename?: string; + parserOptions?: any; +} + +export interface TestCaseError { + message?: string | RegExp; + type?: string; + line?: number; + column?: number; + endLine?: number; + endColumn?: number; +} + +export interface InvalidTestCase extends ValidTestCase { + errors: number | Array; +} + +export interface Test { + valid?: ValidTestCase[]; + invalid: InvalidTestCase[]; +} + +export class RuleTester { + constructor(config?: any); + + run(name: string, rule: any, tests: Test): void; +} diff --git a/types/eslint/tsconfig.json b/types/eslint/tsconfig.json new file mode 100644 index 0000000000..2e820d4971 --- /dev/null +++ b/types/eslint/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "eslint-tests.ts" + ] +} diff --git a/types/eslint/tslint.json b/types/eslint/tslint.json new file mode 100644 index 0000000000..3db14f85ea --- /dev/null +++ b/types/eslint/tslint.json @@ -0,0 +1 @@ +{ "extends": "dtslint/dt.json" } From fdedcdfaa5ecd49b243f53157e91410cfe50fabd Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sun, 28 Jan 2018 10:03:03 -0800 Subject: [PATCH 02/23] Add missing types to source code --- types/eslint/eslint-tests.ts | 15 ++++- types/eslint/index.d.ts | 119 +++++++++++++++++++++++++++++++++-- 2 files changed, 127 insertions(+), 7 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 6b60ef8757..2d4a4347d9 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -1,12 +1,23 @@ import { SourceCode, Linter, CLIEngine, RuleTester } from 'eslint'; // ============================================= -// Linter +// SourceCode // ============================================= const SOURCE = `var foo = bar;`; -const sourceCode = new SourceCode(SOURCE, {}); +const ast = { comments: [], tokens: [], loc: {}, range: [] }; +const sourceCode = new SourceCode(SOURCE, ast); + +const text: string = sourceCode.getText(); + +const lines: string[] = sourceCode.getLines(); + +SourceCode.splitLines(SOURCE); + +// ============================================= +// Linter +// ============================================= const linter = new Linter(); diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 7e04f5ebc7..b4b0a921ed 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -3,12 +3,121 @@ // Definitions by: Pierre-Marie Dartus // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -export class SourceCode { - text: string; - ast: any; - lines: string[]; +export interface Ast { + comments: any[], + tokens: any[], + loc: any, + range: any[]; +} - constructor(text: string, ast: any); +export type AstNode = any; +export type Token = any; +export type Comment = any; + +export type FilterPredicate = (tokenOrComment: Token | Comment) => boolean; + +export type CursorWithSkipOptions = number | FilterPredicate | { + includeComments?: boolean; + filter?: FilterPredicate; + skip?: number; +} + +export type CursorWithCountOptions = number | FilterPredicate | { + includeComments?: boolean; + filter?: FilterPredicate; + count?: number; +} + +export class TokenStore { + getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): Token | null; + + getFirstToken(node: AstNode, options: CursorWithSkipOptions): Token | null; + + getFirstTokens(node: AstNode, options: CursorWithCountOptions): Token[]; + + getLastToken(node: AstNode, options: CursorWithSkipOptions): Token | null; + + getLastTokens(node: AstNode, options: CursorWithCountOptions): Token[]; + + getTokenBefore(node: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + + getTokensBefore(node: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + + getTokenAfter(node: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + + getTokensAfter(node: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + + getFirstTokenBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + + getFirstTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + + getLastTokenBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + + getLastTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + + getTokens(node: AstNode, beforeCount?: number, afterCount?: number): Token[]; + getTokens(node: AstNode, options: FilterPredicate | CursorWithCountOptions): Token[]; + + getTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, padding: number): Token[]; + getTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, padding: FilterPredicate | CursorWithCountOptions): Token[]; + + commentsExistBetween(left: AstNode, right: AstNode): boolean; + + getCommentsBefore(nodeOrToken: AstNode | Token): Comment[]; + + getCommentsAfter(nodeOrToken: AstNode | Token): Comment[]; + + getCommentsInside(node: AstNode): Comment[]; +} + +export interface SourceCodeConfig { + text: string; + ast: Ast; + parserServices?: ParserServices; + scopeManager?: ScopeManager; + visitorKeys?: VisitorKeys; +} + +export interface Location { + line: number; + column: number; +} + +type ParserServices = any; +type ScopeManager = any; +type VisitorKeys = any; + +export class SourceCode extends TokenStore { + text: string; + ast: Ast; + lines: string[]; + hasBOM: boolean; + parserServices: ParserServices; + scopeManager: ScopeManager; + visitorKeys: VisitorKeys; + + constructor(text: string, ast: Ast); + constructor(config: SourceCodeConfig); + + static splitLines(text: string): string[]; + + getText(node?: AstNode, beforeCount?: number, afterCount?: number): string; + + getLines(): string[]; + + getAllComments(): AstNode[]; + + getComments(node: AstNode): { leading: Comment[], trailing: Comment[] }; + + getJSDocComment(node: AstNode): Token | null; + + getNodeByRangeIndex(index: number): AstNode | null; + + isSpaceBetweenTokens(first: Token, second: Token): boolean; + + getLocFromIndex(index: number): Location; + + getIndexFromLoc(location: Location): number; } export type RuleLevel = 'off' | 'warn' | 'error' | 0 | 1 | 2; From ba6ee11d7c9b1cfb8ea5058240f107b1289a9f79 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sun, 28 Jan 2018 10:59:55 -0800 Subject: [PATCH 03/23] Add RuleModule type defintion --- types/eslint/index.d.ts | 72 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index b4b0a921ed..425f5f6c00 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -161,8 +161,10 @@ export interface FixOptions extends LintOptions { fix?: boolean; } +export type Range = [number, number]; + export interface Fix { - range: [number, number]; + range: Range; text: string; } @@ -172,7 +174,73 @@ export interface FixReport { messages: LintMessage[]; } -export type RuleModule = any; +export interface RuleModule { + create(context: RuleContext): any; + meta?: RuleMetaData; +} + +export interface RuleMetaData { + docs?: { + description?: string; + category?: string; + recommended?: boolean; + url?: string; + } + messages?: { [messageId: string]: string }; + fixable?: 'code' | 'whitespace'; + schema?: any; + deprecated?: boolean; +} + +interface RuleContext { + id: string; + options: any[]; + settings: any; + parserPath: string; + parserOptions: any; + parserServices: any; + + getAncestors(): AstNode[]; + + getDeclaredVariables(node: AstNode): any[]; + + getFilename(): string; + + getScope(): any; + + getSourceCode(): SourceCode; + + markVariableAsUsed(name: string): boolean; + + report(descriptor: ReportDescriptor): void; +} + +type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions; +type ReportDescriptorMessage = { message: string } | { messageId: string }; +type ReportDescriptorLocation = { node: AstNode } | { loc: { start: Location, end: Location } | { line: number, column: number } } +type ReportDescriptorOptions = { + data?: any; + + fix?(fixer: RuleFixer): null | Fix | IterableIterator; +} + +interface RuleFixer { + insertTextAfter(nodeOrToken: AstNode | Token, text: string): Fix; + + insertTextAfterRange(range: Range, text: string): Fix; + + insertTextBefore(nodeOrToken: AstNode | Token, text: string): Fix; + + insertTextBeforeRange(range: Range, text: string): Fix; + + remove(nodeOrToken: AstNode | Token): Fix; + + removeRange(range: Range): Fix; + + replaceText(nodeOrToken: AstNode | Token, text: string): Fix; + + replaceTextRange(range: Range, text: string): Fix; +} export type ParserModule = any; From 4edc769299bfd486bda5b24141901b0bd00f3158 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sun, 28 Jan 2018 11:03:43 -0800 Subject: [PATCH 04/23] Add ParserModule types --- types/eslint/index.d.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 425f5f6c00..6fca406a62 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -242,7 +242,18 @@ interface RuleFixer { replaceTextRange(range: Range, text: string): Fix; } -export type ParserModule = any; +export type ParserModule = { + parse(text: string, options?: any): AstNode; +} | { + parseForESLint(text: string, options?: any): ESLintParseResult; +} + +export interface ESLintParseResult { + ast: AstNode; + parserServices?: any; + scopeManager?: any; + visitorKeys?: { [type: string]: string[] }; +} export class Linter { version: string; From e1a8c9446c0dc88ec233ae43a956634451d195df Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sun, 28 Jan 2018 11:16:23 -0800 Subject: [PATCH 05/23] Add RuleTester missing types --- types/eslint/index.d.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 6fca406a62..80a19f144c 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -280,6 +280,7 @@ export class CLIEngineOptions { baseConfig?: boolean; cache?: boolean; cacheFile?: string; + cacheLocation?: string; configFile?: string; cwd?: string; envs?: string[]; @@ -297,6 +298,7 @@ export class CLIEngineOptions { [name: string]: (RuleLevel | [RuleLevel, any]); }; rulePaths?: string[]; + reportUnusedDisableDirectives?: true; } export interface LintResult { @@ -351,11 +353,16 @@ export interface ValidTestCase { options?: any; filename?: string; parserOptions?: any; + settings?: any; + parser?: string; + globals?: { [name: string]: boolean }; } export interface TestCaseError { message?: string | RegExp; + messageId?: string; type?: string; + data?: any; line?: number; column?: number; endLine?: number; @@ -364,6 +371,7 @@ export interface TestCaseError { export interface InvalidTestCase extends ValidTestCase { errors: number | Array; + output?: string; } export interface Test { From d63e1610023551f14fff3a3be5792d4057dca6b6 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sun, 28 Jan 2018 19:24:57 -0800 Subject: [PATCH 06/23] Fix linting errors --- types/eslint/index.d.ts | 43 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 80a19f144c..d5c9556f65 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -4,9 +4,9 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped export interface Ast { - comments: any[], - tokens: any[], - loc: any, + comments: any[]; + tokens: any[]; + loc: any; range: any[]; } @@ -20,13 +20,13 @@ export type CursorWithSkipOptions = number | FilterPredicate | { includeComments?: boolean; filter?: FilterPredicate; skip?: number; -} +}; export type CursorWithCountOptions = number | FilterPredicate | { includeComments?: boolean; filter?: FilterPredicate; count?: number; -} +}; export class TokenStore { getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): Token | null; @@ -47,19 +47,18 @@ export class TokenStore { getTokensAfter(node: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; - getFirstTokenBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + getFirstTokenBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; - getFirstTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + getFirstTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; - getLastTokenBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + getLastTokenBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; - getLastTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + getLastTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; getTokens(node: AstNode, beforeCount?: number, afterCount?: number): Token[]; getTokens(node: AstNode, options: FilterPredicate | CursorWithCountOptions): Token[]; - getTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, padding: number): Token[]; - getTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, padding: FilterPredicate | CursorWithCountOptions): Token[]; + getTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, padding: number | FilterPredicate | CursorWithCountOptions): Token[]; commentsExistBetween(left: AstNode, right: AstNode): boolean; @@ -83,9 +82,9 @@ export interface Location { column: number; } -type ParserServices = any; -type ScopeManager = any; -type VisitorKeys = any; +export type ParserServices = any; +export type ScopeManager = any; +export type VisitorKeys = any; export class SourceCode extends TokenStore { text: string; @@ -185,14 +184,14 @@ export interface RuleMetaData { category?: string; recommended?: boolean; url?: string; - } + }; messages?: { [messageId: string]: string }; fixable?: 'code' | 'whitespace'; schema?: any; deprecated?: boolean; } -interface RuleContext { +export interface RuleContext { id: string; options: any[]; settings: any; @@ -215,16 +214,16 @@ interface RuleContext { report(descriptor: ReportDescriptor): void; } -type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions; -type ReportDescriptorMessage = { message: string } | { messageId: string }; -type ReportDescriptorLocation = { node: AstNode } | { loc: { start: Location, end: Location } | { line: number, column: number } } -type ReportDescriptorOptions = { +export type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions; +export type ReportDescriptorMessage = { message: string } | { messageId: string }; +export type ReportDescriptorLocation = { node: AstNode } | { loc: { start: Location, end: Location } | { line: number, column: number } }; +export interface ReportDescriptorOptions { data?: any; fix?(fixer: RuleFixer): null | Fix | IterableIterator; } -interface RuleFixer { +export interface RuleFixer { insertTextAfter(nodeOrToken: AstNode | Token, text: string): Fix; insertTextAfterRange(range: Range, text: string): Fix; @@ -246,7 +245,7 @@ export type ParserModule = { parse(text: string, options?: any): AstNode; } | { parseForESLint(text: string, options?: any): ESLintParseResult; -} +}; export interface ESLintParseResult { ast: AstNode; From eedcaa68b89399e97131f19a63c994665584af9f Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Mon, 29 Jan 2018 07:48:41 -0800 Subject: [PATCH 07/23] Add types for ASTNode and scope namager --- types/eslint/index.d.ts | 179 ++++++++++++++++++++++++++++------------ 1 file changed, 128 insertions(+), 51 deletions(-) diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index d5c9556f65..5afa86d809 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -2,19 +2,21 @@ // Project: https://eslint.org // Definitions by: Pierre-Marie Dartus // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.1 + +import { JSONSchema4 } from 'json-schema'; +import * as ESTree from 'estree'; + +export type Token = any; export interface Ast { - comments: any[]; + comments: ESTree.Comment[]; tokens: any[]; loc: any; range: any[]; } -export type AstNode = any; -export type Token = any; -export type Comment = any; - -export type FilterPredicate = (tokenOrComment: Token | Comment) => boolean; +export type FilterPredicate = (tokenOrComment: Token | ESTree.Comment) => boolean; export type CursorWithSkipOptions = number | FilterPredicate | { includeComments?: boolean; @@ -31,42 +33,42 @@ export type CursorWithCountOptions = number | FilterPredicate | { export class TokenStore { getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): Token | null; - getFirstToken(node: AstNode, options: CursorWithSkipOptions): Token | null; + getFirstToken(node: ESTree.Node, options: CursorWithSkipOptions): Token | null; - getFirstTokens(node: AstNode, options: CursorWithCountOptions): Token[]; + getFirstTokens(node: ESTree.Node, options: CursorWithCountOptions): Token[]; - getLastToken(node: AstNode, options: CursorWithSkipOptions): Token | null; + getLastToken(node: ESTree.Node, options: CursorWithSkipOptions): Token | null; - getLastTokens(node: AstNode, options: CursorWithCountOptions): Token[]; + getLastTokens(node: ESTree.Node, options: CursorWithCountOptions): Token[]; - getTokenBefore(node: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + getTokenBefore(node: ESTree.Node | Token | ESTree.Comment, options: CursorWithSkipOptions): Token | null; - getTokensBefore(node: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + getTokensBefore(node: ESTree.Node | Token | ESTree.Comment, options: CursorWithCountOptions): Token[]; - getTokenAfter(node: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + getTokenAfter(node: ESTree.Node | Token | ESTree.Comment, options: CursorWithSkipOptions): Token | null; - getTokensAfter(node: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + getTokensAfter(node: ESTree.Node | Token | ESTree.Comment, options: CursorWithCountOptions): Token[]; - getFirstTokenBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + getFirstTokenBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, options: CursorWithSkipOptions): Token | null; - getFirstTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + getFirstTokensBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, options: CursorWithCountOptions): Token[]; - getLastTokenBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithSkipOptions): Token | null; + getLastTokenBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, options: CursorWithSkipOptions): Token | null; - getLastTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, options: CursorWithCountOptions): Token[]; + getLastTokensBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, options: CursorWithCountOptions): Token[]; - getTokens(node: AstNode, beforeCount?: number, afterCount?: number): Token[]; - getTokens(node: AstNode, options: FilterPredicate | CursorWithCountOptions): Token[]; + getTokens(node: ESTree.Node, beforeCount?: number, afterCount?: number): Token[]; + getTokens(node: ESTree.Node, options: FilterPredicate | CursorWithCountOptions): Token[]; - getTokensBetween(left: AstNode | Token | Comment, right: AstNode | Token | Comment, padding: number | FilterPredicate | CursorWithCountOptions): Token[]; + getTokensBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, padding: number | FilterPredicate | CursorWithCountOptions): Token[]; - commentsExistBetween(left: AstNode, right: AstNode): boolean; + commentsExistBetween(left: ESTree.Node, right: ESTree.Node): boolean; - getCommentsBefore(nodeOrToken: AstNode | Token): Comment[]; + getCommentsBefore(nodeOrToken: ESTree.Node | Token): ESTree.Comment[]; - getCommentsAfter(nodeOrToken: AstNode | Token): Comment[]; + getCommentsAfter(nodeOrToken: ESTree.Node | Token): ESTree.Comment[]; - getCommentsInside(node: AstNode): Comment[]; + getCommentsInside(node: ESTree.Node): ESTree.Comment[]; } export interface SourceCodeConfig { @@ -83,8 +85,70 @@ export interface Location { } export type ParserServices = any; -export type ScopeManager = any; -export type VisitorKeys = any; + +export interface ScopeManager { + scopes: Scope[]; + globalScope: Scope | null; + + acquire(node: ESTree.Node, inner?: boolean): Scope | null; + + getDeclaredVariables(node: ESTree.Node): any[]; +} + +export interface Scope { + type: 'block' | 'catch' | 'class' | 'for' | 'function' | 'function-expression-name' | 'global' | 'module' | 'switch' | 'with' | 'TDZ'; + isStrict: boolean; + upper: Scope | null; + childScopes: Scope[]; + variableScope: Scope; + block: ESTree.Node; + variables: Variable[]; + set: Map; + references: Reference[]; + through: Reference[]; + functionExpressionScope: boolean; +} + +export interface Variable { + name: string; + identifiers: ESTree.Identifier; + references: Reference[]; + defs: Definition[]; +} + +export interface Reference { + identifier: ESTree.Identifier; + from: Scope; + resolved: Variable | null; + writeExpr: ESTree.Node | null; + init: boolean; + + isWrite(): boolean; + + isRead(): boolean; + + isWriteOnly(): boolean; + + isReadOnly(): boolean; + + isReadWrite(): boolean; +} + +export type DefinitionType = + | { type: 'CatchClause', node: ESTree.CatchClause, parent: null } + | { type: 'ClassName', node: ESTree.ClassDeclaration | ESTree.ClassExpression, parent: null } + | { type: 'FunctionName', node: ESTree.FunctionDeclaration | ESTree.FunctionExpression, parent: null } + | { type: 'ImplicitGlobalVariable', node: ESTree.Program, parent: null } + | { type: 'ImportBinding', node: ESTree.ImportSpecifier | ESTree.ImportDefaultSpecifier | ESTree.ImportNamespaceSpecifier, parent: ESTree.ImportDeclaration } + | { type: 'Parameter', node: ESTree.FunctionDeclaration | ESTree.FunctionExpression | ESTree.ArrowFunctionExpression, parent: null } + | { type: 'TDZ', node: any, parent: null } + | { type: 'Variable', node: ESTree.VariableDeclarator, parent: ESTree.VariableDeclaration }; + +export type Definition = DefinitionType & { name: ESTree.Identifier }; + +export interface VisitorKeys { + [nodeType: string]: string[]; +} export class SourceCode extends TokenStore { text: string; @@ -100,17 +164,17 @@ export class SourceCode extends TokenStore { static splitLines(text: string): string[]; - getText(node?: AstNode, beforeCount?: number, afterCount?: number): string; + getText(node?: ESTree.Node, beforeCount?: number, afterCount?: number): string; getLines(): string[]; - getAllComments(): AstNode[]; + getAllComments(): ESTree.Node[]; - getComments(node: AstNode): { leading: Comment[], trailing: Comment[] }; + getComments(node: ESTree.Node): { leading: ESTree.Comment[], trailing: ESTree.Comment[] }; - getJSDocComment(node: AstNode): Token | null; + getJSDocComment(node: ESTree.Node): Token | null; - getNodeByRangeIndex(index: number): AstNode | null; + getNodeByRangeIndex(index: number): ESTree.Node | null; isSpaceBetweenTokens(first: Token, second: Token): boolean; @@ -121,13 +185,26 @@ export class SourceCode extends TokenStore { export type RuleLevel = 'off' | 'warn' | 'error' | 0 | 1 | 2; +export interface ParserOptions { + ecmaVersion?: 3 | 5 | 6 | 7 | 8 | 9 | 2015 | 2016 | 2017 | 2018; + sourceType?: 'script' | 'module'; + ecmaFeatures?: { + globalReturn?: boolean; + impliedStrict?: boolean; + jsx?: boolean; + experimentalObjectRestSpread?: boolean; + [key: string]: any; + }; + [key: string]: any; +} + export interface Config { rules?: { [name: string]: (RuleLevel | [RuleLevel, any]) }; parser?: string; - parserOptions?: any; - settings?: any; + parserOptions?: ParserOptions; + settings?: { [name: string]: any }; env?: { [name: string]: boolean }; globals?: { [name: string]: boolean }; } @@ -187,21 +264,21 @@ export interface RuleMetaData { }; messages?: { [messageId: string]: string }; fixable?: 'code' | 'whitespace'; - schema?: any; + schema?: JSONSchema4 | JSONSchema4[]; deprecated?: boolean; } export interface RuleContext { id: string; options: any[]; - settings: any; + settings: { [name: string]: any }; parserPath: string; - parserOptions: any; + parserOptions: ParserOptions; parserServices: any; - getAncestors(): AstNode[]; + getAncestors(): ESTree.Node[]; - getDeclaredVariables(node: AstNode): any[]; + getDeclaredVariables(node: ESTree.Node): any[]; getFilename(): string; @@ -216,42 +293,42 @@ export interface RuleContext { export type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions; export type ReportDescriptorMessage = { message: string } | { messageId: string }; -export type ReportDescriptorLocation = { node: AstNode } | { loc: { start: Location, end: Location } | { line: number, column: number } }; +export type ReportDescriptorLocation = { node: ESTree.Node } | { loc: { start: Location, end: Location } | { line: number, column: number } }; export interface ReportDescriptorOptions { - data?: any; + data?: { [key: string]: string }; fix?(fixer: RuleFixer): null | Fix | IterableIterator; } export interface RuleFixer { - insertTextAfter(nodeOrToken: AstNode | Token, text: string): Fix; + insertTextAfter(nodeOrToken: ESTree.Node | Token, text: string): Fix; insertTextAfterRange(range: Range, text: string): Fix; - insertTextBefore(nodeOrToken: AstNode | Token, text: string): Fix; + insertTextBefore(nodeOrToken: ESTree.Node | Token, text: string): Fix; insertTextBeforeRange(range: Range, text: string): Fix; - remove(nodeOrToken: AstNode | Token): Fix; + remove(nodeOrToken: ESTree.Node | Token): Fix; removeRange(range: Range): Fix; - replaceText(nodeOrToken: AstNode | Token, text: string): Fix; + replaceText(nodeOrToken: ESTree.Node | Token, text: string): Fix; replaceTextRange(range: Range, text: string): Fix; } export type ParserModule = { - parse(text: string, options?: any): AstNode; + parse(text: string, options?: any): ESTree.Node; } | { parseForESLint(text: string, options?: any): ESLintParseResult; }; export interface ESLintParseResult { - ast: AstNode; + ast: ESTree.Node; parserServices?: any; scopeManager?: any; - visitorKeys?: { [type: string]: string[] }; + visitorKeys?: VisitorKeys; } export class Linter { @@ -291,7 +368,7 @@ export class CLIEngineOptions { ignorePattern?: string; useEslintrc?: boolean; parser?: string; - parserOptions?: any; + parserOptions?: ParserOptions; plugins?: string[]; rules?: { [name: string]: (RuleLevel | [RuleLevel, any]); @@ -351,8 +428,8 @@ export interface ValidTestCase { code: string; options?: any; filename?: string; - parserOptions?: any; - settings?: any; + parserOptions?: ParserOptions; + settings?: { [name: string]: any }; parser?: string; globals?: { [name: string]: boolean }; } From 9526476d01730159e7bfe0187ebd2d5c300323b9 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Tue, 30 Jan 2018 07:33:19 -0800 Subject: [PATCH 08/23] Add RuleListener type --- types/eslint/index.d.ts | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 5afa86d809..b4bb9e4e84 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -255,6 +255,43 @@ export interface RuleModule { meta?: RuleMetaData; } +export interface RuleListener { + onCodePathStart?(codePath: CodePath, node: ESTree.Node): void; + + onCodePathEnd?(codePath: CodePath, node: ESTree.Node): void; + + onCodePathSegmentStart?(segment: CodePathSegment, node: ESTree.Node): void; + + onCodePathSegmentEnd?(segment: CodePathSegment, node: ESTree.Node): void; + + onCodePathSegmentLoop?(fromSegment: CodePathSegment, toSegment: CodePathSegment, node: ESTree.Node): void; + + [key: string]: + | ((codePath: CodePath, node: ESTree.Node) => void) + | ((segment: CodePathSegment, node: ESTree.Node) => void) + | ((fromSegment: CodePathSegment, toSegment: CodePathSegment, node: ESTree.Node) => void) + | ((node: ESTree.Node) => void) + | undefined; +} + +export interface CodePath { + id: string; + initialSegment: CodePathSegment; + finalSegments: CodePathSegment[]; + returnedSegments: CodePathSegment[]; + thrownSegments: CodePathSegment[]; + currentSegments: CodePathSegment[]; + upper: CodePath | null; + childCodePaths: CodePath[]; +} + +export interface CodePathSegment { + id: string; + nextSegments: CodePathSegment[]; + prevSegments: CodePathSegment[]; + reachable: boolean; +} + export interface RuleMetaData { docs?: { description?: string; From 48378a71f6e7d5b93143f8b2268acdd38fd399d9 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Tue, 30 Jan 2018 07:35:58 -0800 Subject: [PATCH 09/23] Bump min typescript version for json-schema --- types/eslint/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index b4bb9e4e84..ee6b4eab0d 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -2,7 +2,7 @@ // Project: https://eslint.org // Definitions by: Pierre-Marie Dartus // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.1 +// TypeScript Version: 2.2 import { JSONSchema4 } from 'json-schema'; import * as ESTree from 'estree'; From 211e27a68e7d7666810d37a1290bc7c375c3708e Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Tue, 30 Jan 2018 21:53:07 -0800 Subject: [PATCH 10/23] Make type consistent --- types/eslint/eslint-tests.ts | 4 +-- types/eslint/index.d.ts | 58 +++++++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 2d4a4347d9..a1c4ddbbc8 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -1,4 +1,4 @@ -import { SourceCode, Linter, CLIEngine, RuleTester } from 'eslint'; +import { SourceCode, Linter, CLIEngine, RuleTester, Ast } from 'eslint'; // ============================================= // SourceCode @@ -6,7 +6,7 @@ import { SourceCode, Linter, CLIEngine, RuleTester } from 'eslint'; const SOURCE = `var foo = bar;`; -const ast = { comments: [], tokens: [], loc: {}, range: [] }; +const ast: Ast = { comments: [], tokens: [], loc: { start: { line: 0, column: 0 }, end: { line: 0, column: 10 } }, range: [0, 17] }; const sourceCode = new SourceCode(SOURCE, ast); const text: string = sourceCode.getText(); diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index ee6b4eab0d..5ad0f7df8d 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -7,13 +7,42 @@ import { JSONSchema4 } from 'json-schema'; import * as ESTree from 'estree'; -export type Token = any; +export type TokenType = + | 'Boolean' + | 'Null' + | 'Identifier' + | 'Keyword' + | 'Punctuator' + | 'JSXIdentifier' + | 'JSXText' + | 'Numeric' + | 'String' + | 'RegularExpression'; + +export interface Token { + type: TokenType; + value: string; + range: Range; + loc: SourceLocation; +} + +export interface SourceLocation { + start: Location; + end: Location; +} + +export interface Location { + line: number; + column: number; +} + +export type Range = [number, number]; export interface Ast { comments: ESTree.Comment[]; - tokens: any[]; - loc: any; - range: any[]; + tokens: Token[]; + loc: SourceLocation; + range: Range; } export type FilterPredicate = (tokenOrComment: Token | ESTree.Comment) => boolean; @@ -79,11 +108,6 @@ export interface SourceCodeConfig { visitorKeys?: VisitorKeys; } -export interface Location { - line: number; - column: number; -} - export type ParserServices = any; export interface ScopeManager { @@ -92,7 +116,7 @@ export interface ScopeManager { acquire(node: ESTree.Node, inner?: boolean): Scope | null; - getDeclaredVariables(node: ESTree.Node): any[]; + getDeclaredVariables(node: ESTree.Node): Variable[]; } export interface Scope { @@ -237,8 +261,6 @@ export interface FixOptions extends LintOptions { fix?: boolean; } -export type Range = [number, number]; - export interface Fix { range: Range; text: string; @@ -311,15 +333,15 @@ export interface RuleContext { settings: { [name: string]: any }; parserPath: string; parserOptions: ParserOptions; - parserServices: any; + parserServices: ParserServices; getAncestors(): ESTree.Node[]; - getDeclaredVariables(node: ESTree.Node): any[]; + getDeclaredVariables(node: ESTree.Node): Variable[]; getFilename(): string; - getScope(): any; + getScope(): Scope; getSourceCode(): SourceCode; @@ -330,7 +352,7 @@ export interface RuleContext { export type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions; export type ReportDescriptorMessage = { message: string } | { messageId: string }; -export type ReportDescriptorLocation = { node: ESTree.Node } | { loc: { start: Location, end: Location } | { line: number, column: number } }; +export type ReportDescriptorLocation = { node: ESTree.Node } | { loc: SourceLocation | { line: number, column: number } }; export interface ReportDescriptorOptions { data?: { [key: string]: string }; @@ -363,8 +385,8 @@ export type ParserModule = { export interface ESLintParseResult { ast: ESTree.Node; - parserServices?: any; - scopeManager?: any; + parserServices?: ParserServices; + scopeManager?: ScopeManager; visitorKeys?: VisitorKeys; } From 581167305d724a2ca4e2bb2e40a91e4511b09805 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Tue, 30 Jan 2018 21:55:15 -0800 Subject: [PATCH 11/23] Add @j-f1 to the definition author list --- types/eslint/index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 5ad0f7df8d..d6326c4ad5 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -1,6 +1,7 @@ // Type definitions for eslint 4.16 // Project: https://eslint.org // Definitions by: Pierre-Marie Dartus +// Jed Fox // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.2 From 871c58a7b4c8ce83c8bfc94e51e1b13e9fe6fce9 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Wed, 31 Jan 2018 20:35:55 -0800 Subject: [PATCH 12/23] Refactor type defition to leverage namespaces --- types/eslint/eslint-tests.ts | 8 +- types/eslint/index.d.ts | 832 +++++++++++++++++++---------------- 2 files changed, 450 insertions(+), 390 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index a1c4ddbbc8..46f960dbd4 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -15,6 +15,10 @@ const lines: string[] = sourceCode.getLines(); SourceCode.splitLines(SOURCE); +class Foo { + foo = 1; +} + // ============================================= // Linter // ============================================= @@ -89,7 +93,9 @@ CLIEngine.outputFixes(report); const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } }); -ruleTester.run("my-rule", {}, { +ruleTester.run("my-rule", { + create() {}, +}, { valid: [ { code: "var foo = true", diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index d6326c4ad5..d30abc5aa1 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -9,16 +9,16 @@ import { JSONSchema4 } from 'json-schema'; import * as ESTree from 'estree'; export type TokenType = - | 'Boolean' - | 'Null' - | 'Identifier' - | 'Keyword' - | 'Punctuator' - | 'JSXIdentifier' - | 'JSXText' - | 'Numeric' - | 'String' - | 'RegularExpression'; + | 'Boolean' + | 'Null' + | 'Identifier' + | 'Keyword' + | 'Punctuator' + | 'JSXIdentifier' + | 'JSXText' + | 'Numeric' + | 'String' + | 'RegularExpression'; export interface Token { type: TokenType; @@ -46,146 +46,81 @@ export interface Ast { range: Range; } -export type FilterPredicate = (tokenOrComment: Token | ESTree.Comment) => boolean; +export namespace Scope { + interface ScopeManager { + scopes: Scope[]; + globalScope: Scope | null; -export type CursorWithSkipOptions = number | FilterPredicate | { - includeComments?: boolean; - filter?: FilterPredicate; - skip?: number; -}; + acquire(node: ESTree.Node, inner?: boolean): Scope | null; -export type CursorWithCountOptions = number | FilterPredicate | { - includeComments?: boolean; - filter?: FilterPredicate; - count?: number; -}; + getDeclaredVariables(node: ESTree.Node): Variable[]; + } -export class TokenStore { - getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): Token | null; + interface Scope { + type: 'block' | 'catch' | 'class' | 'for' | 'function' | 'function-expression-name' | 'global' | 'module' | 'switch' | 'with' | 'TDZ'; + isStrict: boolean; + upper: Scope | null; + childScopes: Scope[]; + variableScope: Scope; + block: ESTree.Node; + variables: Variable[]; + set: Map; + references: Reference[]; + through: Reference[]; + functionExpressionScope: boolean; + } - getFirstToken(node: ESTree.Node, options: CursorWithSkipOptions): Token | null; + interface Variable { + name: string; + identifiers: ESTree.Identifier; + references: Reference[]; + defs: Definition[]; + } - getFirstTokens(node: ESTree.Node, options: CursorWithCountOptions): Token[]; + interface Reference { + identifier: ESTree.Identifier; + from: Scope; + resolved: Variable | null; + writeExpr: ESTree.Node | null; + init: boolean; - getLastToken(node: ESTree.Node, options: CursorWithSkipOptions): Token | null; + isWrite(): boolean; - getLastTokens(node: ESTree.Node, options: CursorWithCountOptions): Token[]; + isRead(): boolean; - getTokenBefore(node: ESTree.Node | Token | ESTree.Comment, options: CursorWithSkipOptions): Token | null; + isWriteOnly(): boolean; - getTokensBefore(node: ESTree.Node | Token | ESTree.Comment, options: CursorWithCountOptions): Token[]; + isReadOnly(): boolean; - getTokenAfter(node: ESTree.Node | Token | ESTree.Comment, options: CursorWithSkipOptions): Token | null; + isReadWrite(): boolean; + } - getTokensAfter(node: ESTree.Node | Token | ESTree.Comment, options: CursorWithCountOptions): Token[]; + type DefinitionType = + | { type: 'CatchClause', node: ESTree.CatchClause, parent: null } + | { type: 'ClassName', node: ESTree.ClassDeclaration | ESTree.ClassExpression, parent: null } + | { type: 'FunctionName', node: ESTree.FunctionDeclaration | ESTree.FunctionExpression, parent: null } + | { type: 'ImplicitGlobalVariable', node: ESTree.Program, parent: null } + | { type: 'ImportBinding', node: ESTree.ImportSpecifier | ESTree.ImportDefaultSpecifier | ESTree.ImportNamespaceSpecifier, parent: ESTree.ImportDeclaration } + | { type: 'Parameter', node: ESTree.FunctionDeclaration | ESTree.FunctionExpression | ESTree.ArrowFunctionExpression, parent: null } + | { type: 'TDZ', node: any, parent: null } + | { type: 'Variable', node: ESTree.VariableDeclarator, parent: ESTree.VariableDeclaration }; - getFirstTokenBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, options: CursorWithSkipOptions): Token | null; - - getFirstTokensBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, options: CursorWithCountOptions): Token[]; - - getLastTokenBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, options: CursorWithSkipOptions): Token | null; - - getLastTokensBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, options: CursorWithCountOptions): Token[]; - - getTokens(node: ESTree.Node, beforeCount?: number, afterCount?: number): Token[]; - getTokens(node: ESTree.Node, options: FilterPredicate | CursorWithCountOptions): Token[]; - - getTokensBetween(left: ESTree.Node | Token | ESTree.Comment, right: ESTree.Node | Token | ESTree.Comment, padding: number | FilterPredicate | CursorWithCountOptions): Token[]; - - commentsExistBetween(left: ESTree.Node, right: ESTree.Node): boolean; - - getCommentsBefore(nodeOrToken: ESTree.Node | Token): ESTree.Comment[]; - - getCommentsAfter(nodeOrToken: ESTree.Node | Token): ESTree.Comment[]; - - getCommentsInside(node: ESTree.Node): ESTree.Comment[]; + type Definition = DefinitionType & { name: ESTree.Identifier }; } -export interface SourceCodeConfig { - text: string; - ast: Ast; - parserServices?: ParserServices; - scopeManager?: ScopeManager; - visitorKeys?: VisitorKeys; -} +//#region SourceCode -export type ParserServices = any; - -export interface ScopeManager { - scopes: Scope[]; - globalScope: Scope | null; - - acquire(node: ESTree.Node, inner?: boolean): Scope | null; - - getDeclaredVariables(node: ESTree.Node): Variable[]; -} - -export interface Scope { - type: 'block' | 'catch' | 'class' | 'for' | 'function' | 'function-expression-name' | 'global' | 'module' | 'switch' | 'with' | 'TDZ'; - isStrict: boolean; - upper: Scope | null; - childScopes: Scope[]; - variableScope: Scope; - block: ESTree.Node; - variables: Variable[]; - set: Map; - references: Reference[]; - through: Reference[]; - functionExpressionScope: boolean; -} - -export interface Variable { - name: string; - identifiers: ESTree.Identifier; - references: Reference[]; - defs: Definition[]; -} - -export interface Reference { - identifier: ESTree.Identifier; - from: Scope; - resolved: Variable | null; - writeExpr: ESTree.Node | null; - init: boolean; - - isWrite(): boolean; - - isRead(): boolean; - - isWriteOnly(): boolean; - - isReadOnly(): boolean; - - isReadWrite(): boolean; -} - -export type DefinitionType = - | { type: 'CatchClause', node: ESTree.CatchClause, parent: null } - | { type: 'ClassName', node: ESTree.ClassDeclaration | ESTree.ClassExpression, parent: null } - | { type: 'FunctionName', node: ESTree.FunctionDeclaration | ESTree.FunctionExpression, parent: null } - | { type: 'ImplicitGlobalVariable', node: ESTree.Program, parent: null } - | { type: 'ImportBinding', node: ESTree.ImportSpecifier | ESTree.ImportDefaultSpecifier | ESTree.ImportNamespaceSpecifier, parent: ESTree.ImportDeclaration } - | { type: 'Parameter', node: ESTree.FunctionDeclaration | ESTree.FunctionExpression | ESTree.ArrowFunctionExpression, parent: null } - | { type: 'TDZ', node: any, parent: null } - | { type: 'Variable', node: ESTree.VariableDeclarator, parent: ESTree.VariableDeclaration }; - -export type Definition = DefinitionType & { name: ESTree.Identifier }; - -export interface VisitorKeys { - [nodeType: string]: string[]; -} - -export class SourceCode extends TokenStore { +export class SourceCode { text: string; ast: Ast; lines: string[]; hasBOM: boolean; - parserServices: ParserServices; - scopeManager: ScopeManager; - visitorKeys: VisitorKeys; + parserServices: SourceCode.ParserServices; + scopeManager: Scope.ScopeManager; + visitorKeys: SourceCode.VisitorKeys; constructor(text: string, ast: Ast); - constructor(config: SourceCodeConfig); + constructor(config: SourceCode.Config); static splitLines(text: string): string[]; @@ -206,317 +141,436 @@ export class SourceCode extends TokenStore { getLocFromIndex(index: number): Location; getIndexFromLoc(location: Location): number; + + // Inherited methods from TokenStore + // --------------------------------- + + getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): Token | null; + + getFirstToken(node: ESTree.Node, options: SourceCode.CursorWithSkipOptions): Token | null; + + getFirstTokens(node: ESTree.Node, options: SourceCode.CursorWithCountOptions): Token[]; + + getLastToken(node: ESTree.Node, options: SourceCode.CursorWithSkipOptions): Token | null; + + getLastTokens(node: ESTree.Node, options: SourceCode.CursorWithCountOptions): Token[]; + + getTokenBefore(node: ESTree.Node | Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions): Token | null; + + getTokensBefore(node: ESTree.Node | Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions): Token[]; + + getTokenAfter(node: ESTree.Node | Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions): Token | null; + + getTokensAfter(node: ESTree.Node | Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions): Token[]; + + getFirstTokenBetween( + left: ESTree.Node | Token | ESTree.Comment, + right: ESTree.Node | Token | ESTree.Comment, + options: SourceCode.CursorWithSkipOptions + ): Token | null; + + getFirstTokensBetween( + left: ESTree.Node | Token | ESTree.Comment, + right: ESTree.Node | Token | ESTree.Comment, + options: SourceCode.CursorWithCountOptions + ): Token[]; + + getLastTokenBetween( + left: ESTree.Node | Token | ESTree.Comment, + right: ESTree.Node | Token | ESTree.Comment, + options: SourceCode.CursorWithSkipOptions + ): Token | null; + + getLastTokensBetween( + left: ESTree.Node | Token | ESTree.Comment, + right: ESTree.Node | Token | ESTree.Comment, + options: SourceCode.CursorWithCountOptions + ): Token[]; + + getTokensBetween( + left: ESTree.Node | Token | ESTree.Comment, + right: ESTree.Node | Token | ESTree.Comment, + padding: number | SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions + ): Token[]; + + getTokens(node: ESTree.Node, beforeCount?: number, afterCount?: number): Token[]; + getTokens(node: ESTree.Node, options: SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): Token[]; + + commentsExistBetween(left: ESTree.Node, right: ESTree.Node): boolean; + + getCommentsBefore(nodeOrToken: ESTree.Node | Token): ESTree.Comment[]; + + getCommentsAfter(nodeOrToken: ESTree.Node | Token): ESTree.Comment[]; + + getCommentsInside(node: ESTree.Node): ESTree.Comment[]; } -export type RuleLevel = 'off' | 'warn' | 'error' | 0 | 1 | 2; +export namespace SourceCode { + interface Config { + text: string; + ast: Ast; + parserServices?: ParserServices; + scopeManager?: Scope.ScopeManager; + visitorKeys?: VisitorKeys; + } -export interface ParserOptions { - ecmaVersion?: 3 | 5 | 6 | 7 | 8 | 9 | 2015 | 2016 | 2017 | 2018; - sourceType?: 'script' | 'module'; - ecmaFeatures?: { - globalReturn?: boolean; - impliedStrict?: boolean; - jsx?: boolean; - experimentalObjectRestSpread?: boolean; - [key: string]: any; + type ParserServices = any; + + interface VisitorKeys { + [nodeType: string]: string[]; + } + + type FilterPredicate = (tokenOrComment: Token | ESTree.Comment) => boolean; + + type CursorWithSkipOptions = number | FilterPredicate | { + includeComments?: boolean; + filter?: FilterPredicate; + skip?: number; }; - [key: string]: any; -} -export interface Config { - rules?: { - [name: string]: (RuleLevel | [RuleLevel, any]) + type CursorWithCountOptions = number | FilterPredicate | { + includeComments?: boolean; + filter?: FilterPredicate; + count?: number; }; - parser?: string; - parserOptions?: ParserOptions; - settings?: { [name: string]: any }; - env?: { [name: string]: boolean }; - globals?: { [name: string]: boolean }; } -export interface LintOptions { - filename?: string; - preprocess?: (code: string) => string[]; - postprocess?: (problemLists: LintMessage[][]) => LintMessage[]; - allowInlineConfig?: boolean; - reportUnusedDisableDirectives?: boolean; +//#endregion + +export namespace Rule { + interface RuleModule { + create(context: RuleContext): any; + meta?: RuleMetaData; + } + + interface RuleListener { + onCodePathStart?(codePath: CodePath, node: ESTree.Node): void; + + onCodePathEnd?(codePath: CodePath, node: ESTree.Node): void; + + onCodePathSegmentStart?(segment: CodePathSegment, node: ESTree.Node): void; + + onCodePathSegmentEnd?(segment: CodePathSegment, node: ESTree.Node): void; + + onCodePathSegmentLoop?(fromSegment: CodePathSegment, toSegment: CodePathSegment, node: ESTree.Node): void; + + [key: string]: + | ((codePath: CodePath, node: ESTree.Node) => void) + | ((segment: CodePathSegment, node: ESTree.Node) => void) + | ((fromSegment: CodePathSegment, toSegment: CodePathSegment, node: ESTree.Node) => void) + | ((node: ESTree.Node) => void) + | undefined; + } + + interface CodePath { + id: string; + initialSegment: CodePathSegment; + finalSegments: CodePathSegment[]; + returnedSegments: CodePathSegment[]; + thrownSegments: CodePathSegment[]; + currentSegments: CodePathSegment[]; + upper: CodePath | null; + childCodePaths: CodePath[]; + } + + interface CodePathSegment { + id: string; + nextSegments: CodePathSegment[]; + prevSegments: CodePathSegment[]; + reachable: boolean; + } + + interface RuleMetaData { + docs?: { + description?: string; + category?: string; + recommended?: boolean; + url?: string; + }; + messages?: { [messageId: string]: string }; + fixable?: 'code' | 'whitespace'; + schema?: JSONSchema4 | JSONSchema4[]; + deprecated?: boolean; + } + + interface RuleContext { + id: string; + options: any[]; + settings: { [name: string]: any }; + parserPath: string; + parserOptions: Linter.ParserOptions; + parserServices: SourceCode.ParserServices; + + getAncestors(): ESTree.Node[]; + + getDeclaredVariables(node: ESTree.Node): Scope.Variable[]; + + getFilename(): string; + + getScope(): Scope.Scope; + + getSourceCode(): SourceCode; + + markVariableAsUsed(name: string): boolean; + + report(descriptor: ReportDescriptor): void; + } + + type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions; + type ReportDescriptorMessage = { message: string } | { messageId: string }; + type ReportDescriptorLocation = { node: ESTree.Node } | { loc: SourceLocation | { line: number, column: number } }; + interface ReportDescriptorOptions { + data?: { [key: string]: string }; + + fix?(fixer: RuleFixer): null | Fix | IterableIterator; + } + + interface RuleFixer { + insertTextAfter(nodeOrToken: ESTree.Node | Token, text: string): Fix; + + insertTextAfterRange(range: Range, text: string): Fix; + + insertTextBefore(nodeOrToken: ESTree.Node | Token, text: string): Fix; + + insertTextBeforeRange(range: Range, text: string): Fix; + + remove(nodeOrToken: ESTree.Node | Token): Fix; + + removeRange(range: Range): Fix; + + replaceText(nodeOrToken: ESTree.Node | Token, text: string): Fix; + + replaceTextRange(range: Range, text: string): Fix; + } + + interface Fix { + range: Range; + text: string; + } } -export type Severity = 1 | 2; - -export interface LintMessage { - column: number; - line: number; - endColumn?: number; - endLine?: number; - ruleId: string | null; - message: string; - nodeType: string; - fatal?: true; - severity: Severity; - fix?: Fix; - source: string | null; -} - -export interface FixOptions extends LintOptions { - fix?: boolean; -} - -export interface Fix { - range: Range; - text: string; -} - -export interface FixReport { - fixed: boolean; - output: string; - messages: LintMessage[]; -} - -export interface RuleModule { - create(context: RuleContext): any; - meta?: RuleMetaData; -} - -export interface RuleListener { - onCodePathStart?(codePath: CodePath, node: ESTree.Node): void; - - onCodePathEnd?(codePath: CodePath, node: ESTree.Node): void; - - onCodePathSegmentStart?(segment: CodePathSegment, node: ESTree.Node): void; - - onCodePathSegmentEnd?(segment: CodePathSegment, node: ESTree.Node): void; - - onCodePathSegmentLoop?(fromSegment: CodePathSegment, toSegment: CodePathSegment, node: ESTree.Node): void; - - [key: string]: - | ((codePath: CodePath, node: ESTree.Node) => void) - | ((segment: CodePathSegment, node: ESTree.Node) => void) - | ((fromSegment: CodePathSegment, toSegment: CodePathSegment, node: ESTree.Node) => void) - | ((node: ESTree.Node) => void) - | undefined; -} - -export interface CodePath { - id: string; - initialSegment: CodePathSegment; - finalSegments: CodePathSegment[]; - returnedSegments: CodePathSegment[]; - thrownSegments: CodePathSegment[]; - currentSegments: CodePathSegment[]; - upper: CodePath | null; - childCodePaths: CodePath[]; -} - -export interface CodePathSegment { - id: string; - nextSegments: CodePathSegment[]; - prevSegments: CodePathSegment[]; - reachable: boolean; -} - -export interface RuleMetaData { - docs?: { - description?: string; - category?: string; - recommended?: boolean; - url?: string; - }; - messages?: { [messageId: string]: string }; - fixable?: 'code' | 'whitespace'; - schema?: JSONSchema4 | JSONSchema4[]; - deprecated?: boolean; -} - -export interface RuleContext { - id: string; - options: any[]; - settings: { [name: string]: any }; - parserPath: string; - parserOptions: ParserOptions; - parserServices: ParserServices; - - getAncestors(): ESTree.Node[]; - - getDeclaredVariables(node: ESTree.Node): Variable[]; - - getFilename(): string; - - getScope(): Scope; - - getSourceCode(): SourceCode; - - markVariableAsUsed(name: string): boolean; - - report(descriptor: ReportDescriptor): void; -} - -export type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions; -export type ReportDescriptorMessage = { message: string } | { messageId: string }; -export type ReportDescriptorLocation = { node: ESTree.Node } | { loc: SourceLocation | { line: number, column: number } }; -export interface ReportDescriptorOptions { - data?: { [key: string]: string }; - - fix?(fixer: RuleFixer): null | Fix | IterableIterator; -} - -export interface RuleFixer { - insertTextAfter(nodeOrToken: ESTree.Node | Token, text: string): Fix; - - insertTextAfterRange(range: Range, text: string): Fix; - - insertTextBefore(nodeOrToken: ESTree.Node | Token, text: string): Fix; - - insertTextBeforeRange(range: Range, text: string): Fix; - - remove(nodeOrToken: ESTree.Node | Token): Fix; - - removeRange(range: Range): Fix; - - replaceText(nodeOrToken: ESTree.Node | Token, text: string): Fix; - - replaceTextRange(range: Range, text: string): Fix; -} - -export type ParserModule = { - parse(text: string, options?: any): ESTree.Node; -} | { - parseForESLint(text: string, options?: any): ESLintParseResult; -}; - -export interface ESLintParseResult { - ast: ESTree.Node; - parserServices?: ParserServices; - scopeManager?: ScopeManager; - visitorKeys?: VisitorKeys; -} +//#region Linter export class Linter { version: string; - verify(code: SourceCode | string, config: Config, filename?: string): LintMessage[]; - verify(code: SourceCode | string, config: Config, options: LintOptions): LintMessage[]; + verify(code: SourceCode | string, config: Linter.Config, filename?: string): Linter.LintMessage[]; + verify(code: SourceCode | string, config: Linter.Config, options: Linter.LintOptions): Linter.LintMessage[]; - verifyAndFix(code: string, config: Config, filename?: string): FixReport; - verifyAndFix(code: string, config: Config, options: FixOptions): FixReport; + verifyAndFix(code: string, config: Linter.Config, filename?: string): Linter.FixReport; + verifyAndFix(code: string, config: Linter.Config, options: Linter.FixOptions): Linter.FixReport; getSourceCode(): SourceCode; - defineRule(name: string, rule: RuleModule): void; + defineRule(name: string, rule: Rule.RuleModule): void; - defineRules(rules: { [name: string]: RuleModule }): void; + defineRules(rules: { [name: string]: Rule.RuleModule }): void; - getRules(): Map; + getRules(): Map; - defineParser(name: string, parser: ParserModule): void; + defineParser(name: string, parser: Linter.ParserModule): void; } -export class CLIEngineOptions { - allowInlineConfig?: boolean; - baseConfig?: boolean; - cache?: boolean; - cacheFile?: string; - cacheLocation?: string; - configFile?: string; - cwd?: string; - envs?: string[]; - extensions?: string[]; - fix?: boolean; - globals?: string[]; - ignore?: boolean; - ignorePath?: string; - ignorePattern?: string; - useEslintrc?: boolean; - parser?: string; - parserOptions?: ParserOptions; - plugins?: string[]; - rules?: { - [name: string]: (RuleLevel | [RuleLevel, any]); +export namespace Linter { + type Severity = 0 | 1 | 2; + type RuleLevel = Severity | 'off' | 'warn' | 'error'; + + interface RuleLevelAndOptions extends Array { + 0: RuleLevel; + } + + interface Config { + rules?: { + [name: string]: RuleLevel | RuleLevelAndOptions + }; + parser?: string; + parserOptions?: ParserOptions; + settings?: { [name: string]: any }; + env?: { [name: string]: boolean }; + globals?: { [name: string]: boolean }; + } + + interface ParserOptions { + ecmaVersion?: 3 | 5 | 6 | 7 | 8 | 9 | 2015 | 2016 | 2017 | 2018; + sourceType?: 'script' | 'module'; + ecmaFeatures?: { + globalReturn?: boolean; + impliedStrict?: boolean; + jsx?: boolean; + experimentalObjectRestSpread?: boolean; + [key: string]: any; + }; + [key: string]: any; + } + + interface LintOptions { + filename?: string; + preprocess?: (code: string) => string[]; + postprocess?: (problemLists: LintMessage[][]) => LintMessage[]; + allowInlineConfig?: boolean; + reportUnusedDisableDirectives?: boolean; + } + + interface LintMessage { + column: number; + line: number; + endColumn?: number; + endLine?: number; + ruleId: string | null; + message: string; + nodeType: string; + fatal?: true; + severity: Severity; + fix?: Rule.Fix; + source: string | null; + } + + interface FixOptions extends LintOptions { + fix?: boolean; + } + + interface FixReport { + fixed: boolean; + output: string; + messages: LintMessage[]; + } + + type ParserModule = { + parse(text: string, options?: any): ESTree.Node; + } | { + parseForESLint(text: string, options?: any): ESLintParseResult; }; - rulePaths?: string[]; - reportUnusedDisableDirectives?: true; + + interface ESLintParseResult { + ast: ESTree.Node; + parserServices?: SourceCode.ParserServices; + scopeManager?: Scope.ScopeManager; + visitorKeys?: SourceCode.VisitorKeys; + } } -export interface LintResult { - filePath: string; - messages: LintMessage[]; - errorCount: number; - warningCount: number; - fixableErrorCount: number; - fixableWarningCount: number; - output?: string; - source?: string; -} +//#endregion -export interface LintReport { - results: LintResult[]; - errorCount: number; - warningCount: number; - fixableErrorCount: number; - fixableWarningCount: number; -} - -export type Formatter = (results: LintResult[]) => string; +//#region CLIEngine export class CLIEngine { version: string; - constructor(options: CLIEngineOptions); + constructor(options: CLIEngine.Options); - executeOnFiles(patterns: string[]): LintReport; + executeOnFiles(patterns: string[]): CLIEngine.LintReport; resolveFileGlobPatterns(patterns: string[]): string[]; - getConfigForFile(filePath: string): Config; + getConfigForFile(filePath: string): Linter.Config; - executeOnText(text: string, filename?: string): LintReport; + executeOnText(text: string, filename?: string): CLIEngine.LintReport; addPlugin(name: string, pluginObject: any): void; isPathIgnored(filePath: string): boolean; - getFormatter(format: string): Formatter; + getFormatter(format: string): CLIEngine.Formatter; - static getErrorResults(results: LintResult[]): LintResult[]; + getRules(): Map; - static outputFixes(report: LintReport): void; + static getErrorResults(results: CLIEngine.LintResult[]): CLIEngine.LintResult[]; - getRules(): Map; + static outputFixes(report: CLIEngine.LintReport): void; } -export interface ValidTestCase { - code: string; - options?: any; - filename?: string; - parserOptions?: ParserOptions; - settings?: { [name: string]: any }; - parser?: string; - globals?: { [name: string]: boolean }; +export namespace CLIEngine { + class Options { + allowInlineConfig?: boolean; + baseConfig?: boolean; + cache?: boolean; + cacheFile?: string; + cacheLocation?: string; + configFile?: string; + cwd?: string; + envs?: string[]; + extensions?: string[]; + fix?: boolean; + globals?: string[]; + ignore?: boolean; + ignorePath?: string; + ignorePattern?: string; + useEslintrc?: boolean; + parser?: string; + parserOptions?: Linter.ParserOptions; + plugins?: string[]; + rules?: { + [name: string]: (Linter.RuleLevel | [Linter.RuleLevel, any]); + }; + rulePaths?: string[]; + reportUnusedDisableDirectives?: true; + } + + interface LintResult { + filePath: string; + messages: Linter.LintMessage[]; + errorCount: number; + warningCount: number; + fixableErrorCount: number; + fixableWarningCount: number; + output?: string; + source?: string; + } + + interface LintReport { + results: LintResult[]; + errorCount: number; + warningCount: number; + fixableErrorCount: number; + fixableWarningCount: number; + } + + type Formatter = (results: LintResult[]) => string; } -export interface TestCaseError { - message?: string | RegExp; - messageId?: string; - type?: string; - data?: any; - line?: number; - column?: number; - endLine?: number; - endColumn?: number; -} +//#endregion -export interface InvalidTestCase extends ValidTestCase { - errors: number | Array; - output?: string; -} - -export interface Test { - valid?: ValidTestCase[]; - invalid: InvalidTestCase[]; -} +//#region RuleTester export class RuleTester { constructor(config?: any); - run(name: string, rule: any, tests: Test): void; + run( + name: string, + rule: Rule.RuleModule, + tests: { + valid?: RuleTester.ValidTestCase[]; + invalid?: RuleTester.InvalidTestCase[]; + }, + ): void; } + +export namespace RuleTester { + interface ValidTestCase { + code: string; + options?: any; + filename?: string; + parserOptions?: Linter.ParserOptions; + settings?: { [name: string]: any }; + parser?: string; + globals?: { [name: string]: boolean }; + } + + interface InvalidTestCase extends ValidTestCase { + errors: number | Array; + output?: string; + } + + interface TestCaseError { + message?: string | RegExp; + messageId?: string; + type?: string; + data?: any; + line?: number; + column?: number; + endLine?: number; + endColumn?: number; + } +} + +//#endregion From 4e6dd4d9bc9736fcfe063ffec6850b2c298cebde Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Thu, 1 Feb 2018 07:27:21 -0800 Subject: [PATCH 13/23] Add namespace for AST and intrgrate misc feedback --- types/eslint/index.d.ts | 161 ++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 82 deletions(-) diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index d30abc5aa1..2ef75b2612 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -8,42 +8,39 @@ import { JSONSchema4 } from 'json-schema'; import * as ESTree from 'estree'; -export type TokenType = - | 'Boolean' - | 'Null' - | 'Identifier' - | 'Keyword' - | 'Punctuator' - | 'JSXIdentifier' - | 'JSXText' - | 'Numeric' - | 'String' - | 'RegularExpression'; +export namespace AST { + export type TokenType = + | 'Boolean' + | 'Null' + | 'Identifier' + | 'Keyword' + | 'Punctuator' + | 'JSXIdentifier' + | 'JSXText' + | 'Numeric' + | 'String' + | 'RegularExpression'; -export interface Token { - type: TokenType; - value: string; - range: Range; - loc: SourceLocation; -} + export interface Token { + type: TokenType; + value: string; + range: Range; + loc: SourceLocation; + } -export interface SourceLocation { - start: Location; - end: Location; -} + export interface SourceLocation { + start: ESTree.Position; + end: ESTree.Position; + } -export interface Location { - line: number; - column: number; -} + export type Range = [number, number]; -export type Range = [number, number]; - -export interface Ast { - comments: ESTree.Comment[]; - tokens: Token[]; - loc: SourceLocation; - range: Range; + export interface Program extends ESTree.Program { + comments: ESTree.Comment[]; + tokens: Token[]; + loc: SourceLocation; + range: Range; + } } export namespace Scope { @@ -112,14 +109,14 @@ export namespace Scope { export class SourceCode { text: string; - ast: Ast; + ast: AST.Program; lines: string[]; hasBOM: boolean; parserServices: SourceCode.ParserServices; scopeManager: Scope.ScopeManager; visitorKeys: SourceCode.VisitorKeys; - constructor(text: string, ast: Ast); + constructor(text: string, ast: AST.Program); constructor(config: SourceCode.Config); static splitLines(text: string): string[]; @@ -132,75 +129,75 @@ export class SourceCode { getComments(node: ESTree.Node): { leading: ESTree.Comment[], trailing: ESTree.Comment[] }; - getJSDocComment(node: ESTree.Node): Token | null; + getJSDocComment(node: ESTree.Node): AST.Token | null; getNodeByRangeIndex(index: number): ESTree.Node | null; - isSpaceBetweenTokens(first: Token, second: Token): boolean; + isSpaceBetweenTokens(first: AST.Token, second: AST.Token): boolean; - getLocFromIndex(index: number): Location; + getLocFromIndex(index: number): ESTree.SourceLocation; - getIndexFromLoc(location: Location): number; + getIndexFromLoc(location: ESTree.SourceLocation): number; // Inherited methods from TokenStore // --------------------------------- - getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): Token | null; + getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): AST.Token | null; - getFirstToken(node: ESTree.Node, options: SourceCode.CursorWithSkipOptions): Token | null; + getFirstToken(node: ESTree.Node, options: SourceCode.CursorWithSkipOptions): AST.Token | null; - getFirstTokens(node: ESTree.Node, options: SourceCode.CursorWithCountOptions): Token[]; + getFirstTokens(node: ESTree.Node, options: SourceCode.CursorWithCountOptions): AST.Token[]; - getLastToken(node: ESTree.Node, options: SourceCode.CursorWithSkipOptions): Token | null; + getLastToken(node: ESTree.Node, options: SourceCode.CursorWithSkipOptions): AST.Token | null; - getLastTokens(node: ESTree.Node, options: SourceCode.CursorWithCountOptions): Token[]; + getLastTokens(node: ESTree.Node, options: SourceCode.CursorWithCountOptions): AST.Token[]; - getTokenBefore(node: ESTree.Node | Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions): Token | null; + getTokenBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions): AST.Token | null; - getTokensBefore(node: ESTree.Node | Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions): Token[]; + getTokensBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions): AST.Token[]; - getTokenAfter(node: ESTree.Node | Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions): Token | null; + getTokenAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions): AST.Token | null; - getTokensAfter(node: ESTree.Node | Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions): Token[]; + getTokensAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions): AST.Token[]; getFirstTokenBetween( - left: ESTree.Node | Token | ESTree.Comment, - right: ESTree.Node | Token | ESTree.Comment, + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions - ): Token | null; + ): AST.Token | null; getFirstTokensBetween( - left: ESTree.Node | Token | ESTree.Comment, - right: ESTree.Node | Token | ESTree.Comment, + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions - ): Token[]; + ): AST.Token[]; getLastTokenBetween( - left: ESTree.Node | Token | ESTree.Comment, - right: ESTree.Node | Token | ESTree.Comment, + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions - ): Token | null; + ): AST.Token | null; getLastTokensBetween( - left: ESTree.Node | Token | ESTree.Comment, - right: ESTree.Node | Token | ESTree.Comment, + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions - ): Token[]; + ): AST.Token[]; getTokensBetween( - left: ESTree.Node | Token | ESTree.Comment, - right: ESTree.Node | Token | ESTree.Comment, + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, padding: number | SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions - ): Token[]; + ): AST.Token[]; - getTokens(node: ESTree.Node, beforeCount?: number, afterCount?: number): Token[]; - getTokens(node: ESTree.Node, options: SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): Token[]; + getTokens(node: ESTree.Node, beforeCount?: number, afterCount?: number): AST.Token[]; + getTokens(node: ESTree.Node, options: SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): AST.Token[]; commentsExistBetween(left: ESTree.Node, right: ESTree.Node): boolean; - getCommentsBefore(nodeOrToken: ESTree.Node | Token): ESTree.Comment[]; + getCommentsBefore(nodeOrToken: ESTree.Node | AST.Token): ESTree.Comment[]; - getCommentsAfter(nodeOrToken: ESTree.Node | Token): ESTree.Comment[]; + getCommentsAfter(nodeOrToken: ESTree.Node | AST.Token): ESTree.Comment[]; getCommentsInside(node: ESTree.Node): ESTree.Comment[]; } @@ -208,7 +205,7 @@ export class SourceCode { export namespace SourceCode { interface Config { text: string; - ast: Ast; + ast: AST.Program; parserServices?: ParserServices; scopeManager?: Scope.ScopeManager; visitorKeys?: VisitorKeys; @@ -220,7 +217,7 @@ export namespace SourceCode { [nodeType: string]: string[]; } - type FilterPredicate = (tokenOrComment: Token | ESTree.Comment) => boolean; + type FilterPredicate = (tokenOrComment: AST.Token | ESTree.Comment) => boolean; type CursorWithSkipOptions = number | FilterPredicate | { includeComments?: boolean; @@ -318,7 +315,7 @@ export namespace Rule { type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions; type ReportDescriptorMessage = { message: string } | { messageId: string }; - type ReportDescriptorLocation = { node: ESTree.Node } | { loc: SourceLocation | { line: number, column: number } }; + type ReportDescriptorLocation = { node: ESTree.Node } | { loc: AST.SourceLocation | { line: number, column: number } }; interface ReportDescriptorOptions { data?: { [key: string]: string }; @@ -326,25 +323,25 @@ export namespace Rule { } interface RuleFixer { - insertTextAfter(nodeOrToken: ESTree.Node | Token, text: string): Fix; + insertTextAfter(nodeOrToken: ESTree.Node | AST.Token, text: string): Fix; - insertTextAfterRange(range: Range, text: string): Fix; + insertTextAfterRange(range: AST.Range, text: string): Fix; - insertTextBefore(nodeOrToken: ESTree.Node | Token, text: string): Fix; + insertTextBefore(nodeOrToken: ESTree.Node | AST.Token, text: string): Fix; - insertTextBeforeRange(range: Range, text: string): Fix; + insertTextBeforeRange(range: AST.Range, text: string): Fix; - remove(nodeOrToken: ESTree.Node | Token): Fix; + remove(nodeOrToken: ESTree.Node | AST.Token): Fix; - removeRange(range: Range): Fix; + removeRange(range: AST.Range): Fix; - replaceText(nodeOrToken: ESTree.Node | Token, text: string): Fix; + replaceText(nodeOrToken: ESTree.Node | AST.Token, text: string): Fix; - replaceTextRange(range: Range, text: string): Fix; + replaceTextRange(range: AST.Range, text: string): Fix; } interface Fix { - range: Range; + range: AST.Range; text: string; } } @@ -442,7 +439,7 @@ export namespace Linter { }; interface ESLintParseResult { - ast: ESTree.Node; + ast: AST.Program; parserServices?: SourceCode.ParserServices; scopeManager?: Scope.ScopeManager; visitorKeys?: SourceCode.VisitorKeys; @@ -500,10 +497,10 @@ export namespace CLIEngine { parserOptions?: Linter.ParserOptions; plugins?: string[]; rules?: { - [name: string]: (Linter.RuleLevel | [Linter.RuleLevel, any]); + [name: string]: Linter.RuleLevel | Linter.RuleLevelAndOptions; }; rulePaths?: string[]; - reportUnusedDisableDirectives?: true; + reportUnusedDisableDirectives?: boolean; } interface LintResult { @@ -558,7 +555,7 @@ export namespace RuleTester { interface InvalidTestCase extends ValidTestCase { errors: number | Array; - output?: string; + output?: string | null; } interface TestCaseError { From 883e14890adacb1199d4e48785d11fabe9185415 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Fri, 2 Feb 2018 07:28:10 -0800 Subject: [PATCH 14/23] Add source code coverage --- types/eslint/eslint-tests.ts | 233 +++++++++++++++++++++++++++++++---- types/eslint/index.d.ts | 14 +-- 2 files changed, 219 insertions(+), 28 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 46f960dbd4..65bfcc294d 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -1,27 +1,216 @@ -import { SourceCode, Linter, CLIEngine, RuleTester, Ast } from 'eslint'; - -// ============================================= -// SourceCode -// ============================================= +import { Comment } from 'estree'; +import { SourceCode, Linter, CLIEngine, RuleTester, AST } from 'eslint'; const SOURCE = `var foo = bar;`; -const ast: Ast = { comments: [], tokens: [], loc: { start: { line: 0, column: 0 }, end: { line: 0, column: 10 } }, range: [0, 17] }; -const sourceCode = new SourceCode(SOURCE, ast); +const AST: AST.Program = { + type: 'Program', + sourceType: 'module', + body: [], + comments: [], + tokens: [], + loc: { + start: { line: 0, column: 0 }, + end: { line: 0, column: 0 } + }, + range: [0, 0], +}; -const text: string = sourceCode.getText(); +const TOKEN: AST.Token = { + type: 'Identifier', + value: 'foo', + loc: { + start: { line: 0, column: 0 }, + end: { line: 0, column: 3 } + }, + range: [0, 3] +}; -const lines: string[] = sourceCode.getLines(); +const COMMENT: Comment = { + type: 'Block', + value: 'foo', + loc: { + start: { line: 0, column: 0 }, + end: { line: 0, column: 0 } + }, + range: [0, 0], +}; + +//#region SourceCode + +const sourceCode = new SourceCode(SOURCE, AST); SourceCode.splitLines(SOURCE); -class Foo { - foo = 1; -} +sourceCode.getText(); +sourceCode.getText(AST); +sourceCode.getText(AST, 0); +sourceCode.getText(AST, 0, 0); -// ============================================= -// Linter -// ============================================= +sourceCode.getLines(); + +sourceCode.getAllComments(); + +sourceCode.getComments(AST).leading; +sourceCode.getComments(AST).trailing; + +sourceCode.getJSDocComment(AST); + +sourceCode.getNodeByRangeIndex(0); + +sourceCode.getNodeByRangeIndex(0); + +sourceCode.isSpaceBetweenTokens(TOKEN, TOKEN); + +sourceCode.getLocFromIndex(0); + +sourceCode.getIndexFromLoc({ line: 0, column: 0 }); + +sourceCode.getTokenByRangeStart(0); +sourceCode.getTokenByRangeStart(0, { includeComments: true }); + +// TODO: Should accept no second parameter? +sourceCode.getFirstToken(AST, 0); +sourceCode.getFirstToken(AST, { skip: 0 }); +sourceCode.getFirstToken(AST, t => t.type === 'Identifier'); +sourceCode.getFirstToken(AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getFirstToken(AST, { skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getFirstToken(AST, { includeComments: true }); +sourceCode.getFirstToken(AST, { includeComments: true, skip: 0 }); +sourceCode.getFirstToken(AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); + +sourceCode.getFirstTokens(AST, 0); +sourceCode.getFirstTokens(AST, { count: 0 }); +sourceCode.getFirstTokens(AST, t => t.type === 'Identifier'); +sourceCode.getFirstTokens(AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getFirstTokens(AST, { count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getFirstTokens(AST, { includeComments: true }); +sourceCode.getFirstTokens(AST, { includeComments: true, count: 0 }); +sourceCode.getFirstTokens(AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); + +sourceCode.getLastToken(AST, 0); +sourceCode.getLastToken(AST, { skip: 0 }); +sourceCode.getLastToken(AST, t => t.type === 'Identifier'); +sourceCode.getLastToken(AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getLastToken(AST, { skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getLastToken(AST, { includeComments: true }); +sourceCode.getLastToken(AST, { includeComments: true, skip: 0 }); +sourceCode.getLastToken(AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); + +sourceCode.getLastTokens(AST, 0); +sourceCode.getLastTokens(AST, { count: 0 }); +sourceCode.getLastTokens(AST, t => t.type === 'Identifier'); +sourceCode.getLastTokens(AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getLastTokens(AST, { count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getLastTokens(AST, { includeComments: true }); +sourceCode.getLastTokens(AST, { includeComments: true, count: 0 }); +sourceCode.getLastTokens(AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); + +sourceCode.getTokenBefore(AST, 0); +sourceCode.getTokenBefore(AST, { skip: 0 }); +sourceCode.getTokenBefore(AST, t => t.type === 'Identifier'); +sourceCode.getTokenBefore(AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getTokenBefore(AST, { skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokenBefore(AST, { includeComments: true }); +sourceCode.getTokenBefore(AST, { includeComments: true, skip: 0 }); +sourceCode.getTokenBefore(AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokenBefore(TOKEN, 0); +sourceCode.getTokenBefore(COMMENT, 0); + +sourceCode.getTokensBefore(AST, 0); +sourceCode.getTokensBefore(AST, { count: 0 }); +sourceCode.getTokensBefore(AST, t => t.type === 'Identifier'); +sourceCode.getTokensBefore(AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getTokensBefore(AST, { count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokensBefore(AST, { includeComments: true }); +sourceCode.getTokensBefore(AST, { includeComments: true, count: 0 }); +sourceCode.getTokensBefore(AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokensBefore(TOKEN, 0); +sourceCode.getTokensBefore(COMMENT, 0); + +sourceCode.getTokenAfter(AST, 0); +sourceCode.getTokenAfter(AST, { skip: 0 }); +sourceCode.getTokenAfter(AST, t => t.type === 'Identifier'); +sourceCode.getTokenAfter(AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getTokenAfter(AST, { skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokenAfter(AST, { includeComments: true }); +sourceCode.getTokenAfter(AST, { includeComments: true, skip: 0 }); +sourceCode.getTokenAfter(AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokenAfter(TOKEN, 0); +sourceCode.getTokenAfter(COMMENT, 0); + +sourceCode.getTokensAfter(AST, 0); +sourceCode.getTokensAfter(AST, { count: 0 }); +sourceCode.getTokensAfter(AST, t => t.type === 'Identifier'); +sourceCode.getTokensAfter(AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getTokensAfter(AST, { count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokensAfter(AST, { includeComments: true }); +sourceCode.getTokensAfter(AST, { includeComments: true, count: 0 }); +sourceCode.getTokensAfter(AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokensAfter(TOKEN, 0); +sourceCode.getTokensAfter(COMMENT, 0); + +sourceCode.getFirstTokenBetween(AST, AST, 0); +sourceCode.getFirstTokenBetween(AST, AST, { skip: 0 }); +sourceCode.getFirstTokenBetween(AST, AST, t => t.type === 'Identifier'); +sourceCode.getFirstTokenBetween(AST, AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getFirstTokenBetween(AST, AST, { skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getFirstTokenBetween(AST, AST, { includeComments: true }); +sourceCode.getFirstTokenBetween(AST, AST, { includeComments: true, skip: 0 }); +sourceCode.getFirstTokenBetween(AST, AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); + +sourceCode.getFirstTokensBetween(AST, AST, 0); +sourceCode.getFirstTokensBetween(AST, AST, { count: 0 }); +sourceCode.getFirstTokensBetween(AST, AST, t => t.type === 'Identifier'); +sourceCode.getFirstTokensBetween(AST, AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getFirstTokensBetween(AST, AST, { count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getFirstTokensBetween(AST, AST, { includeComments: true }); +sourceCode.getFirstTokensBetween(AST, AST, { includeComments: true, count: 0 }); +sourceCode.getFirstTokensBetween(AST, AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); + +sourceCode.getLastTokenBetween(AST, AST, 0); +sourceCode.getLastTokenBetween(AST, AST, { skip: 0 }); +sourceCode.getLastTokenBetween(AST, AST, t => t.type === 'Identifier'); +sourceCode.getLastTokenBetween(AST, AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getLastTokenBetween(AST, AST, { skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getLastTokenBetween(AST, AST, { includeComments: true }); +sourceCode.getLastTokenBetween(AST, AST, { includeComments: true, skip: 0 }); +sourceCode.getLastTokenBetween(AST, AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); + +sourceCode.getLastTokensBetween(AST, AST, 0); +sourceCode.getLastTokensBetween(AST, AST, { count: 0 }); +sourceCode.getLastTokensBetween(AST, AST, t => t.type === 'Identifier'); +sourceCode.getLastTokensBetween(AST, AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getLastTokensBetween(AST, AST, { count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getLastTokensBetween(AST, AST, { includeComments: true }); +sourceCode.getLastTokensBetween(AST, AST, { includeComments: true, count: 0 }); +sourceCode.getLastTokensBetween(AST, AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); + +sourceCode.getTokensBetween(AST, AST, 0); + +sourceCode.getTokens(AST); +sourceCode.getTokens(AST, 0); +sourceCode.getTokens(AST, 0, 0); +sourceCode.getTokens(AST, t => t.type === 'Identifier'); +sourceCode.getTokens(AST, { filter: t => t.type === 'Identifier' }); +sourceCode.getTokens(AST, { includeComments: true }); +sourceCode.getTokens(AST, { includeComments: true, filter: t => t.type === 'Identifier' }); + +// TODO: Is it token or Node ? +sourceCode.commentsExistBetween(AST, AST); + +sourceCode.getCommentsBefore(AST); +sourceCode.getCommentsBefore(TOKEN); + +sourceCode.getCommentsAfter(AST); +sourceCode.getCommentsAfter(TOKEN); + +// TODO: Should it support also token? +sourceCode.getCommentsInside(AST); + +//#endregion + +//#region Linter const linter = new Linter(); @@ -56,9 +245,9 @@ linter.getRules(); linter.getSourceCode(); -// ============================================= -// CLI -// ============================================= +//#endregion + +//#region CLIEngine const cli = new CLIEngine({ envs: ['browser', 'mocha'], @@ -87,9 +276,9 @@ CLIEngine.getErrorResults(report.results); CLIEngine.outputFixes(report); -// ============================================= -// RuleTester -// ============================================= +//#endregion + +//#region RuleTester const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } }); @@ -114,3 +303,5 @@ ruleTester.run("my-rule", { } ] }); + +//#endregion diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 2ef75b2612..1a0ec2b8f4 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -9,7 +9,7 @@ import { JSONSchema4 } from 'json-schema'; import * as ESTree from 'estree'; export namespace AST { - export type TokenType = + type TokenType = | 'Boolean' | 'Null' | 'Identifier' @@ -21,21 +21,21 @@ export namespace AST { | 'String' | 'RegularExpression'; - export interface Token { + interface Token { type: TokenType; value: string; range: Range; loc: SourceLocation; } - export interface SourceLocation { + interface SourceLocation { start: ESTree.Position; end: ESTree.Position; } - export type Range = [number, number]; + type Range = [number, number]; - export interface Program extends ESTree.Program { + interface Program extends ESTree.Program { comments: ESTree.Comment[]; tokens: Token[]; loc: SourceLocation; @@ -125,7 +125,7 @@ export class SourceCode { getLines(): string[]; - getAllComments(): ESTree.Node[]; + getAllComments(): ESTree.Comment[]; getComments(node: ESTree.Node): { leading: ESTree.Comment[], trailing: ESTree.Comment[] }; @@ -137,7 +137,7 @@ export class SourceCode { getLocFromIndex(index: number): ESTree.SourceLocation; - getIndexFromLoc(location: ESTree.SourceLocation): number; + getIndexFromLoc(location: ESTree.Position): number; // Inherited methods from TokenStore // --------------------------------- From f960c08627d257113c1755e45628c85cbeef87a3 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sat, 3 Feb 2018 08:59:40 -0800 Subject: [PATCH 15/23] Test for rules and fix --- types/eslint/eslint-tests.ts | 151 +++++++++++++++++++++++++++++------ types/eslint/index.d.ts | 3 +- 2 files changed, 128 insertions(+), 26 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 65bfcc294d..5f15b21039 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -1,5 +1,5 @@ import { Comment } from 'estree'; -import { SourceCode, Linter, CLIEngine, RuleTester, AST } from 'eslint'; +import { AST, SourceCode, Rule, Linter, CLIEngine, RuleTester } from 'eslint'; const SOURCE = `var foo = bar;`; @@ -210,40 +210,143 @@ sourceCode.getCommentsInside(AST); //#endregion +//#region Rule + +let rule: Rule.RuleModule; + +rule = { create(context) { return {}; } }; +rule = { create(context) { return {}; }, meta: {} }; +rule = { create(context) { return {}; }, meta: { + docs: { + description: 'disallow the use of `console`', + category: 'Possible Errors', + recommended: true, + url: 'https://eslint.org/docs/rules/no-console', + } +}}; +rule = { create(context) { return {}; }, meta: { fixable: 'whitespace' }}; +rule = { create(context) { return {}; }, meta: { fixable: 'code' }}; +rule = { create(context) { return {}; }, meta: { schema: [{ enum: ['always', 'never'] }] }}; +rule = { create(context) { return {}; }, meta: { deprecated: true }}; + +rule = { + create(context) { + context.getAncestors(); + + context.getDeclaredVariables(AST); + + context.getFilename(); + + context.getSourceCode(); + + // TODO: Add test for scope + context.getScope(); + + context.markVariableAsUsed('foo'); + + context.report({ message: 'foo', node: AST }); + context.report({ message: 'foo', loc: { line: 0, column: 0 } }); + context.report({ message: 'foo', node: AST, data: { foo: 'bar' } }); + context.report({ message: 'foo', node: AST, fix: () => null }); + context.report({ message: 'foo', node: AST, fix: ruleFixer => ruleFixer.replaceText(AST, 'foo') }); + + context.report({ + message: 'foo', + node: AST, + fix: ruleFixer => { + ruleFixer.insertTextAfter(AST, 'foo'); + ruleFixer.insertTextAfter(TOKEN, 'foo'); + + ruleFixer.insertTextAfterRange([0, 0], 'foo'); + + ruleFixer.insertTextBefore(AST, 'foo'); + ruleFixer.insertTextBefore(TOKEN, 'foo'); + + ruleFixer.insertTextBeforeRange([0, 0], 'foo'); + + ruleFixer.remove(AST); + ruleFixer.remove(TOKEN); + + ruleFixer.removeRange([0, 0]); + + ruleFixer.replaceText(AST, 'foo'); + ruleFixer.replaceText(TOKEN, 'foo'); + + ruleFixer.replaceTextRange([0, 0], 'foo'); + + return null; + } + }); + + return { + onCodePathStart(codePath, node) {}, + onCodePathEnd(codePath, node) {}, + onCodePathSegmentStart(segment, node) {}, + onCodePathSegmentEnd(segment, node) {}, + onCodePathSegmentLoop(fromSegment, toSegment, node) {}, + 'Program:exit'() {}, + }; + }, +}; + +//#endregion + //#region Linter const linter = new Linter(); -linter.verify(SOURCE, { - rules: { - eqeqeq: 'off', - 'no-console': 'error', - quotes: ['error', 'double'] - }, -}, { - filename: 'test.js', -}); +linter.version; -linter.verifyAndFix(SOURCE, { - rules: { - 'no-console': 'error', - } -}, { - filename: 'test.js', -}); +linter.verify(SOURCE, {}); +linter.verify(new SourceCode(SOURCE, AST), {}); -linter.defineRule('my-fancy-rule', { - create() {}, +linter.verify(SOURCE, {}, 'test.js'); +linter.verify(SOURCE, {}, {}); +linter.verify(SOURCE, {}, { filename: 'test.js' }); +linter.verify(SOURCE, {}, { allowInlineConfig: false }); +linter.verify(SOURCE, {}, { reportUnusedDisableDirectives: true }); +linter.verify(SOURCE, {}, { preprocess: input => input.split(' ') }); +linter.verify(SOURCE, {}, { postprocess: problemList => problemList[0] }); + +linter.verify(SOURCE, { parserOptions: { ecmaVersion: 6 } }, 'test.js'); +linter.verify(SOURCE, { parserOptions: { ecmaVersion: 6, ecmaFeatures: { globalReturn: true } } }, 'test.js'); +linter.verify(SOURCE, { parserOptions: { ecmaVersion: 6, ecmaFeatures: { experimentalObjectRestSpread: true } } }, 'test.js'); +linter.verify(SOURCE, { env: { node: true } }, 'test.js'); +linter.verify(SOURCE, { globals: { foo: true } }, 'test.js'); +linter.verify(SOURCE, { parser: 'custom-parser' }, 'test.js'); +linter.verify(SOURCE, { settings: { info: 'foo' } }, 'test.js'); + +linter.verify(SOURCE, { rules: {} }, 'test.js'); +linter.verify(SOURCE, { rules: { quotes: 2 } }, 'test.js'); +linter.verify(SOURCE, { rules: { quotes: [2, 'double'] } }, 'test.js'); +linter.verify(SOURCE, { rules: { 'no-unused-vars': [2, { vars: "all" }] } }, 'test.js'); +linter.verify(SOURCE, { rules: { 'no-console': 1 } }, 'test.js'); +linter.verify(SOURCE, { rules: { 'no-console': 0 } }, 'test.js'); +linter.verify(SOURCE, { rules: { 'no-console': 'error' } }, 'test.js'); +linter.verify(SOURCE, { rules: { 'no-console': 'warn' } }, 'test.js'); +linter.verify(SOURCE, { rules: { 'no-console': 'off' } }, 'test.js'); + +linter.verifyAndFix(SOURCE, {}); +linter.verifyAndFix(SOURCE, {}, 'test.js'); +linter.verifyAndFix(SOURCE, {}, { fix: false }); + +linter.getSourceCode(); + +// TODO: Fix me +linter.defineRule('test', { + create() => {}, }); +// TODO: Fix me linter.defineRules({ - 'my-fancy-rule': { create() {} }, - 'my-fancy-other-rule': { create() {} } + 'test': { create() => {} }, + 'test-2': { create() => {} }, }); linter.getRules(); -linter.getSourceCode(); +// TODO: Fix me +linter.defineParser('cutom-parser', ); //#endregion @@ -282,9 +385,7 @@ CLIEngine.outputFixes(report); const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } }); -ruleTester.run("my-rule", { - create() {}, -}, { +ruleTester.run("my-rule", rule, { valid: [ { code: "var foo = true", diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 1a0ec2b8f4..26f2452fe2 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -236,7 +236,7 @@ export namespace SourceCode { export namespace Rule { interface RuleModule { - create(context: RuleContext): any; + create(context: RuleContext): RuleListener; meta?: RuleMetaData; } @@ -284,6 +284,7 @@ export namespace Rule { recommended?: boolean; url?: string; }; + //TODO: Find usage of message field messages?: { [messageId: string]: string }; fixable?: 'code' | 'whitespace'; schema?: JSONSchema4 | JSONSchema4[]; From 317a828a2fd4fb2ea2072fb50f7dc161a36584d3 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sat, 3 Feb 2018 10:40:45 -0800 Subject: [PATCH 16/23] Close gaps in scope and linter tests --- types/eslint/eslint-tests.ts | 103 +++++++++++++++++++++++++++++++---- types/eslint/index.d.ts | 2 +- 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 5f15b21039..57a58d475e 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -1,5 +1,5 @@ import { Comment } from 'estree'; -import { AST, SourceCode, Rule, Linter, CLIEngine, RuleTester } from 'eslint'; +import { AST, SourceCode, Rule, Linter, CLIEngine, RuleTester, Scope } from 'eslint'; const SOURCE = `var foo = bar;`; @@ -38,7 +38,7 @@ const COMMENT: Comment = { //#region SourceCode -const sourceCode = new SourceCode(SOURCE, AST); +let sourceCode = new SourceCode(SOURCE, AST); SourceCode.splitLines(SOURCE); @@ -210,6 +210,48 @@ sourceCode.getCommentsInside(AST); //#endregion +//#region Scope + +const scopeManager: Scope.ScopeManager = { + scopes: [], + globalScope: null, + acquire(node, inner) { + return this.scopes[0]; + }, + getDeclaredVariables() { + return []; + } +}; + +const scope = scopeManager.scopes[0]; + +const variable = scope.variables[0]; + +variable.name = 'foo'; + +variable.identifiers[0].type = 'Identifier'; + +variable.defs[0].name.type = 'Identifier'; +variable.defs[0].type; +variable.defs[0].node; +variable.defs[0].parent; + +const reference = scope.references[0]; + +reference.from = scope; +reference.identifier.type = 'Identifier'; +reference.resolved = variable; +reference.writeExpr = AST; +reference.init = true; + +reference.isRead(); +reference.isReadOnly(); +reference.isWrite(); +reference.isWriteOnly(); +reference.isReadWrite(); + +//#endregion + //#region Rule let rule: Rule.RuleModule; @@ -326,27 +368,64 @@ linter.verify(SOURCE, { rules: { 'no-console': 'error' } }, 'test.js'); linter.verify(SOURCE, { rules: { 'no-console': 'warn' } }, 'test.js'); linter.verify(SOURCE, { rules: { 'no-console': 'off' } }, 'test.js'); +const lintingResult = linter.verify(SOURCE, {}); + +for (const msg of lintingResult) { + msg.severity = 1; + msg.severity = 2; + + msg.ruleId = 'foo'; + + msg.fatal = true; + + msg.line = 0; + msg.endLine = 0; + msg.column = 0; + msg.endColumn = 0; + + msg.source = SOURCE; + + if (msg.fix) { + msg.fix.text = 'foo'; + msg.fix.range = [0, 0]; + } +} + linter.verifyAndFix(SOURCE, {}); linter.verifyAndFix(SOURCE, {}, 'test.js'); linter.verifyAndFix(SOURCE, {}, { fix: false }); -linter.getSourceCode(); +const fixResult = linter.verifyAndFix(SOURCE, {}); -// TODO: Fix me -linter.defineRule('test', { - create() => {}, -}); +fixResult.fixed = true; +fixResult.output = 'foo'; + +for (const msg of fixResult.messages) { + msg.ruleId = 'foo'; +} + +sourceCode = linter.getSourceCode(); + +linter.defineRule('test', rule); -// TODO: Fix me linter.defineRules({ - 'test': { create() => {} }, - 'test-2': { create() => {} }, + foo: rule, + bar: rule, }); linter.getRules(); -// TODO: Fix me -linter.defineParser('cutom-parser', ); +linter.defineParser('custom-parser', { parse: (src, opts) => AST }); +linter.defineParser('custom-parser', { + parseForESLint(src, opts) { + return { + ast: AST, + visitorKeys: {}, + parserServices: {}, + scopeManager, + }; + } +}); //#endregion diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 26f2452fe2..4ba910329c 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -69,7 +69,7 @@ export namespace Scope { interface Variable { name: string; - identifiers: ESTree.Identifier; + identifiers: ESTree.Identifier[]; references: Reference[]; defs: Definition[]; } From 164beef44424ec8561966d584ecd2c7e2a3a2865 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sat, 3 Feb 2018 10:42:48 -0800 Subject: [PATCH 17/23] Fix linting errors --- types/eslint/eslint-tests.ts | 2 +- types/eslint/index.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 57a58d475e..a7aa0e3ba6 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -216,7 +216,7 @@ const scopeManager: Scope.ScopeManager = { scopes: [], globalScope: null, acquire(node, inner) { - return this.scopes[0]; + return scopeManager.scopes[0]; }, getDeclaredVariables() { return []; diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 4ba910329c..84503a2b40 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -284,7 +284,7 @@ export namespace Rule { recommended?: boolean; url?: string; }; - //TODO: Find usage of message field + // TODO: Find usage of message field messages?: { [messageId: string]: string }; fixable?: 'code' | 'whitespace'; schema?: JSONSchema4 | JSONSchema4[]; From 70945527bcadbbb5458eabc86bc9ae1b85b9b2fc Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sat, 3 Feb 2018 11:59:34 -0800 Subject: [PATCH 18/23] Add tests for RuleTester --- types/eslint/eslint-tests.ts | 89 +++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 26 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index a7aa0e3ba6..6b4b19e463 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -361,7 +361,7 @@ linter.verify(SOURCE, { settings: { info: 'foo' } }, 'test.js'); linter.verify(SOURCE, { rules: {} }, 'test.js'); linter.verify(SOURCE, { rules: { quotes: 2 } }, 'test.js'); linter.verify(SOURCE, { rules: { quotes: [2, 'double'] } }, 'test.js'); -linter.verify(SOURCE, { rules: { 'no-unused-vars': [2, { vars: "all" }] } }, 'test.js'); +linter.verify(SOURCE, { rules: { 'no-unused-vars': [2, { vars: 'all' }] } }, 'test.js'); linter.verify(SOURCE, { rules: { 'no-console': 1 } }, 'test.js'); linter.verify(SOURCE, { rules: { 'no-console': 0 } }, 'test.js'); linter.verify(SOURCE, { rules: { 'no-console': 'error' } }, 'test.js'); @@ -431,17 +431,31 @@ linter.defineParser('custom-parser', { //#region CLIEngine -const cli = new CLIEngine({ - envs: ['browser', 'mocha'], - useEslintrc: false, - rules: { - semi: 2 - } -}); +let cli: CLIEngine; -cli.executeOnFiles(['myfile.js', 'lib/']); +cli = new CLIEngine({ allowInlineConfig: false }); +cli = new CLIEngine({ baseConfig: false }); +cli = new CLIEngine({ cache: true }); +cli = new CLIEngine({ cacheFile: 'foo' }); +cli = new CLIEngine({ configFile: 'foo' }); +cli = new CLIEngine({ cwd: 'foo' }); +cli = new CLIEngine({ envs: ['browser'] }); +cli = new CLIEngine({ extensions: ['js'] }); +cli = new CLIEngine({ fix: true }); +cli = new CLIEngine({ globals: ['foo'] }); +cli = new CLIEngine({ ignore: true }); +cli = new CLIEngine({ ignorePath: 'foo' }); +cli = new CLIEngine({ ignorePattern: 'foo' }); +cli = new CLIEngine({ useEslintrc: false }); +cli = new CLIEngine({ parserOptions: {} }); +cli = new CLIEngine({ plugins: ['foo'] }); +cli = new CLIEngine({ rules: { 'test/example-rule': 1 } }); +cli = new CLIEngine({ rulePaths: ['foo'] }); +cli = new CLIEngine({ reportUnusedDisableDirectives: true }); -const report = cli.executeOnText(SOURCE, 'foo'); +let cliReport = cli.executeOnFiles(['myfile.js', 'lib/']); + +cliReport = cli.executeOnText(SOURCE, 'foo'); cli.resolveFileGlobPatterns(['**/*']); @@ -452,11 +466,33 @@ cli.addPlugin('my-fancy-plugin', {}); cli.isPathIgnored('./dist/index.js'); const formatter = cli.getFormatter('codeframe'); -formatter(report.results); -CLIEngine.getErrorResults(report.results); +formatter(cliReport.results); -CLIEngine.outputFixes(report); +CLIEngine.getErrorResults(cliReport.results); + +CLIEngine.outputFixes(cliReport); + +cliReport.errorCount = 0; +cliReport.warningCount = 0; +cliReport.fixableErrorCount = 0; +cliReport.fixableWarningCount = 0; + +for (const file of cliReport.results) { + file.filePath = 'foo.js'; + + file.errorCount = 0; + file.warningCount = 0; + file.fixableErrorCount = 0; + file.fixableWarningCount = 0; + + file.source = 'foo'; + file.output = 'foo'; + + for (const message of file.messages) { + message.ruleId = 'foo'; + } +} //#endregion @@ -464,23 +500,24 @@ CLIEngine.outputFixes(report); const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } }); -ruleTester.run("my-rule", rule, { +ruleTester.run('my-rule', rule, { valid: [ - { - code: "var foo = true", - options: [{ allowFoo: true }] - } + { code: 'foo' }, + { code: 'foo', options: [{ allowFoo: true }] }, + { code: 'foo', filename: 'test.js' }, + { code: 'foo', parserOptions: {} }, + { code: 'foo', settings: { foo: true } }, + { code: 'foo', parser: 'foo' }, + { code: 'foo', globals: { foo: true } }, ], invalid: [ - { - code: "var invalidVariable = true", - errors: [{ message: "Unexpected invalid variable." }] - }, - { - code: "var invalidVariable = true", - errors: [{ message: /^Unexpected.+variable/ }] - } + { code: 'foo', errors: 1 }, + { code: 'foo', errors: ['foo'] }, + { code: 'foo', errors: [{ message: 'foo' }] }, + { code: 'foo', errors: [{ message: 'foo', type: 'foo' }] }, + { code: 'foo', errors: [{ message: 'foo', data: { foo: true } }] }, + { code: 'foo', errors: [{ message: 'foo', line: 0 }] }, ] }); From 25d95f9e69d120ae213a09d0784c1a5426b8a271 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sat, 3 Feb 2018 12:08:36 -0800 Subject: [PATCH 19/23] Resolve trailing TODOs --- types/eslint/eslint-tests.ts | 17 +++++++++++++---- types/eslint/index.d.ts | 27 +++++++++++++-------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 6b4b19e463..624d438ea7 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -69,7 +69,7 @@ sourceCode.getIndexFromLoc({ line: 0, column: 0 }); sourceCode.getTokenByRangeStart(0); sourceCode.getTokenByRangeStart(0, { includeComments: true }); -// TODO: Should accept no second parameter? +sourceCode.getFirstToken(AST); sourceCode.getFirstToken(AST, 0); sourceCode.getFirstToken(AST, { skip: 0 }); sourceCode.getFirstToken(AST, t => t.type === 'Identifier'); @@ -79,6 +79,7 @@ sourceCode.getFirstToken(AST, { includeComments: true }); sourceCode.getFirstToken(AST, { includeComments: true, skip: 0 }); sourceCode.getFirstToken(AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getFirstTokens(AST); sourceCode.getFirstTokens(AST, 0); sourceCode.getFirstTokens(AST, { count: 0 }); sourceCode.getFirstTokens(AST, t => t.type === 'Identifier'); @@ -88,6 +89,7 @@ sourceCode.getFirstTokens(AST, { includeComments: true }); sourceCode.getFirstTokens(AST, { includeComments: true, count: 0 }); sourceCode.getFirstTokens(AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getLastToken(AST); sourceCode.getLastToken(AST, 0); sourceCode.getLastToken(AST, { skip: 0 }); sourceCode.getLastToken(AST, t => t.type === 'Identifier'); @@ -97,6 +99,7 @@ sourceCode.getLastToken(AST, { includeComments: true }); sourceCode.getLastToken(AST, { includeComments: true, skip: 0 }); sourceCode.getLastToken(AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getLastTokens(AST); sourceCode.getLastTokens(AST, 0); sourceCode.getLastTokens(AST, { count: 0 }); sourceCode.getLastTokens(AST, t => t.type === 'Identifier'); @@ -106,6 +109,7 @@ sourceCode.getLastTokens(AST, { includeComments: true }); sourceCode.getLastTokens(AST, { includeComments: true, count: 0 }); sourceCode.getLastTokens(AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokenBefore(AST); sourceCode.getTokenBefore(AST, 0); sourceCode.getTokenBefore(AST, { skip: 0 }); sourceCode.getTokenBefore(AST, t => t.type === 'Identifier'); @@ -117,6 +121,7 @@ sourceCode.getTokenBefore(AST, { includeComments: true, skip: 0, filter: t => t. sourceCode.getTokenBefore(TOKEN, 0); sourceCode.getTokenBefore(COMMENT, 0); +sourceCode.getTokensBefore(AST); sourceCode.getTokensBefore(AST, 0); sourceCode.getTokensBefore(AST, { count: 0 }); sourceCode.getTokensBefore(AST, t => t.type === 'Identifier'); @@ -128,6 +133,7 @@ sourceCode.getTokensBefore(AST, { includeComments: true, count: 0, filter: t => sourceCode.getTokensBefore(TOKEN, 0); sourceCode.getTokensBefore(COMMENT, 0); +sourceCode.getTokenAfter(AST); sourceCode.getTokenAfter(AST, 0); sourceCode.getTokenAfter(AST, { skip: 0 }); sourceCode.getTokenAfter(AST, t => t.type === 'Identifier'); @@ -139,6 +145,7 @@ sourceCode.getTokenAfter(AST, { includeComments: true, skip: 0, filter: t => t.t sourceCode.getTokenAfter(TOKEN, 0); sourceCode.getTokenAfter(COMMENT, 0); +sourceCode.getTokensAfter(AST); sourceCode.getTokensAfter(AST, 0); sourceCode.getTokensAfter(AST, { count: 0 }); sourceCode.getTokensAfter(AST, t => t.type === 'Identifier'); @@ -150,6 +157,7 @@ sourceCode.getTokensAfter(AST, { includeComments: true, count: 0, filter: t => t sourceCode.getTokensAfter(TOKEN, 0); sourceCode.getTokensAfter(COMMENT, 0); +sourceCode.getFirstTokenBetween(AST, AST); sourceCode.getFirstTokenBetween(AST, AST, 0); sourceCode.getFirstTokenBetween(AST, AST, { skip: 0 }); sourceCode.getFirstTokenBetween(AST, AST, t => t.type === 'Identifier'); @@ -159,6 +167,7 @@ sourceCode.getFirstTokenBetween(AST, AST, { includeComments: true }); sourceCode.getFirstTokenBetween(AST, AST, { includeComments: true, skip: 0 }); sourceCode.getFirstTokenBetween(AST, AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getFirstTokensBetween(AST, AST); sourceCode.getFirstTokensBetween(AST, AST, 0); sourceCode.getFirstTokensBetween(AST, AST, { count: 0 }); sourceCode.getFirstTokensBetween(AST, AST, t => t.type === 'Identifier'); @@ -168,6 +177,7 @@ sourceCode.getFirstTokensBetween(AST, AST, { includeComments: true }); sourceCode.getFirstTokensBetween(AST, AST, { includeComments: true, count: 0 }); sourceCode.getFirstTokensBetween(AST, AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getLastTokenBetween(AST, AST); sourceCode.getLastTokenBetween(AST, AST, 0); sourceCode.getLastTokenBetween(AST, AST, { skip: 0 }); sourceCode.getLastTokenBetween(AST, AST, t => t.type === 'Identifier'); @@ -177,6 +187,7 @@ sourceCode.getLastTokenBetween(AST, AST, { includeComments: true }); sourceCode.getLastTokenBetween(AST, AST, { includeComments: true, skip: 0 }); sourceCode.getLastTokenBetween(AST, AST, { includeComments: true, skip: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getLastTokensBetween(AST, AST); sourceCode.getLastTokensBetween(AST, AST, 0); sourceCode.getLastTokensBetween(AST, AST, { count: 0 }); sourceCode.getLastTokensBetween(AST, AST, t => t.type === 'Identifier'); @@ -186,6 +197,7 @@ sourceCode.getLastTokensBetween(AST, AST, { includeComments: true }); sourceCode.getLastTokensBetween(AST, AST, { includeComments: true, count: 0 }); sourceCode.getLastTokensBetween(AST, AST, { includeComments: true, count: 0, filter: t => t.type === 'Identifier' }); +sourceCode.getTokensBetween(AST, AST); sourceCode.getTokensBetween(AST, AST, 0); sourceCode.getTokens(AST); @@ -196,7 +208,6 @@ sourceCode.getTokens(AST, { filter: t => t.type === 'Identifier' }); sourceCode.getTokens(AST, { includeComments: true }); sourceCode.getTokens(AST, { includeComments: true, filter: t => t.type === 'Identifier' }); -// TODO: Is it token or Node ? sourceCode.commentsExistBetween(AST, AST); sourceCode.getCommentsBefore(AST); @@ -205,7 +216,6 @@ sourceCode.getCommentsBefore(TOKEN); sourceCode.getCommentsAfter(AST); sourceCode.getCommentsAfter(TOKEN); -// TODO: Should it support also token? sourceCode.getCommentsInside(AST); //#endregion @@ -281,7 +291,6 @@ rule = { context.getSourceCode(); - // TODO: Add test for scope context.getScope(); context.markVariableAsUsed('foo'); diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 84503a2b40..abe7b7ce90 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -144,50 +144,50 @@ export class SourceCode { getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): AST.Token | null; - getFirstToken(node: ESTree.Node, options: SourceCode.CursorWithSkipOptions): AST.Token | null; + getFirstToken(node: ESTree.Node, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getFirstTokens(node: ESTree.Node, options: SourceCode.CursorWithCountOptions): AST.Token[]; + getFirstTokens(node: ESTree.Node, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getLastToken(node: ESTree.Node, options: SourceCode.CursorWithSkipOptions): AST.Token | null; + getLastToken(node: ESTree.Node, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getLastTokens(node: ESTree.Node, options: SourceCode.CursorWithCountOptions): AST.Token[]; + getLastTokens(node: ESTree.Node, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getTokenBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions): AST.Token | null; + getTokenBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getTokensBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions): AST.Token[]; + getTokensBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getTokenAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithSkipOptions): AST.Token | null; + getTokenAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getTokensAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options: SourceCode.CursorWithCountOptions): AST.Token[]; + getTokensAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithCountOptions): AST.Token[]; getFirstTokenBetween( left: ESTree.Node | AST.Token | ESTree.Comment, right: ESTree.Node | AST.Token | ESTree.Comment, - options: SourceCode.CursorWithSkipOptions + options?: SourceCode.CursorWithSkipOptions ): AST.Token | null; getFirstTokensBetween( left: ESTree.Node | AST.Token | ESTree.Comment, right: ESTree.Node | AST.Token | ESTree.Comment, - options: SourceCode.CursorWithCountOptions + options?: SourceCode.CursorWithCountOptions ): AST.Token[]; getLastTokenBetween( left: ESTree.Node | AST.Token | ESTree.Comment, right: ESTree.Node | AST.Token | ESTree.Comment, - options: SourceCode.CursorWithSkipOptions + options?: SourceCode.CursorWithSkipOptions ): AST.Token | null; getLastTokensBetween( left: ESTree.Node | AST.Token | ESTree.Comment, right: ESTree.Node | AST.Token | ESTree.Comment, - options: SourceCode.CursorWithCountOptions + options?: SourceCode.CursorWithCountOptions ): AST.Token[]; getTokensBetween( left: ESTree.Node | AST.Token | ESTree.Comment, right: ESTree.Node | AST.Token | ESTree.Comment, - padding: number | SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions + padding?: number | SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions ): AST.Token[]; getTokens(node: ESTree.Node, beforeCount?: number, afterCount?: number): AST.Token[]; @@ -284,7 +284,6 @@ export namespace Rule { recommended?: boolean; url?: string; }; - // TODO: Find usage of message field messages?: { [messageId: string]: string }; fixable?: 'code' | 'whitespace'; schema?: JSONSchema4 | JSONSchema4[]; From f2ce6a9bb436ba43b6f352fa20a07422972bc5a1 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sun, 4 Feb 2018 08:01:41 -0800 Subject: [PATCH 20/23] Fix commentsExistBetween signature and make parse return Program --- types/eslint/eslint-tests.ts | 1 + types/eslint/index.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 624d438ea7..376cdf0a92 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -209,6 +209,7 @@ sourceCode.getTokens(AST, { includeComments: true }); sourceCode.getTokens(AST, { includeComments: true, filter: t => t.type === 'Identifier' }); sourceCode.commentsExistBetween(AST, AST); +sourceCode.commentsExistBetween(TOKEN, TOKEN); sourceCode.getCommentsBefore(AST); sourceCode.getCommentsBefore(TOKEN); diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index abe7b7ce90..9e0e68af0b 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -193,7 +193,7 @@ export class SourceCode { getTokens(node: ESTree.Node, beforeCount?: number, afterCount?: number): AST.Token[]; getTokens(node: ESTree.Node, options: SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): AST.Token[]; - commentsExistBetween(left: ESTree.Node, right: ESTree.Node): boolean; + commentsExistBetween(left: ESTree.Node | AST.Token, right: ESTree.Node | AST.Token): boolean; getCommentsBefore(nodeOrToken: ESTree.Node | AST.Token): ESTree.Comment[]; @@ -433,7 +433,7 @@ export namespace Linter { } type ParserModule = { - parse(text: string, options?: any): ESTree.Node; + parse(text: string, options?: any): AST.Program; } | { parseForESLint(text: string, options?: any): ESLintParseResult; }; From c84b2631309e1421913fc24666e6a32758b36d19 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Mon, 5 Feb 2018 06:46:30 -0800 Subject: [PATCH 21/23] Add Ranged interface --- types/eslint/eslint-tests.ts | 3 +- types/eslint/index.d.ts | 66 +++++++++++++++--------------------- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 376cdf0a92..425f14580b 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -1,4 +1,3 @@ -import { Comment } from 'estree'; import { AST, SourceCode, Rule, Linter, CLIEngine, RuleTester, Scope } from 'eslint'; const SOURCE = `var foo = bar;`; @@ -26,7 +25,7 @@ const TOKEN: AST.Token = { range: [0, 3] }; -const COMMENT: Comment = { +const COMMENT: AST.Comment = { type: 'Block', value: 'foo', loc: { diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 9e0e68af0b..81f3c875c8 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -35,12 +35,20 @@ export namespace AST { type Range = [number, number]; + interface Ranged { + range: Range; + } + interface Program extends ESTree.Program { comments: ESTree.Comment[]; tokens: Token[]; loc: SourceLocation; range: Range; } + + interface Comment extends ESTree.Comment { + range: Range; + } } export namespace Scope { @@ -144,62 +152,42 @@ export class SourceCode { getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): AST.Token | null; - getFirstToken(node: ESTree.Node, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getFirstToken(node: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getFirstTokens(node: ESTree.Node, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getFirstTokens(node: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getLastToken(node: ESTree.Node, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getLastToken(node: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getLastTokens(node: ESTree.Node, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getLastTokens(node: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getTokenBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getTokenBefore(node: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getTokensBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getTokensBefore(node: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getTokenAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getTokenAfter(node: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getTokensAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getTokensAfter(node: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getFirstTokenBetween( - left: ESTree.Node | AST.Token | ESTree.Comment, - right: ESTree.Node | AST.Token | ESTree.Comment, - options?: SourceCode.CursorWithSkipOptions - ): AST.Token | null; + getFirstTokenBetween(left: AST.Ranged, right: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getFirstTokensBetween( - left: ESTree.Node | AST.Token | ESTree.Comment, - right: ESTree.Node | AST.Token | ESTree.Comment, - options?: SourceCode.CursorWithCountOptions - ): AST.Token[]; + getFirstTokensBetween(left: AST.Ranged, right: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getLastTokenBetween( - left: ESTree.Node | AST.Token | ESTree.Comment, - right: ESTree.Node | AST.Token | ESTree.Comment, - options?: SourceCode.CursorWithSkipOptions - ): AST.Token | null; + getLastTokenBetween(left: AST.Ranged, right: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getLastTokensBetween( - left: ESTree.Node | AST.Token | ESTree.Comment, - right: ESTree.Node | AST.Token | ESTree.Comment, - options?: SourceCode.CursorWithCountOptions - ): AST.Token[]; + getLastTokensBetween(left: AST.Ranged, right: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getTokensBetween( - left: ESTree.Node | AST.Token | ESTree.Comment, - right: ESTree.Node | AST.Token | ESTree.Comment, - padding?: number | SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions - ): AST.Token[]; + getTokensBetween(left: AST.Ranged, right: AST.Ranged, padding?: number | SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): AST.Token[]; - getTokens(node: ESTree.Node, beforeCount?: number, afterCount?: number): AST.Token[]; - getTokens(node: ESTree.Node, options: SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): AST.Token[]; + getTokens(node: AST.Ranged, beforeCount?: number, afterCount?: number): AST.Token[]; + getTokens(node: AST.Ranged, options: SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): AST.Token[]; - commentsExistBetween(left: ESTree.Node | AST.Token, right: ESTree.Node | AST.Token): boolean; + commentsExistBetween(left: AST.Ranged, right: AST.Ranged): boolean; - getCommentsBefore(nodeOrToken: ESTree.Node | AST.Token): ESTree.Comment[]; + getCommentsBefore(nodeOrToken: AST.Ranged): ESTree.Comment[]; - getCommentsAfter(nodeOrToken: ESTree.Node | AST.Token): ESTree.Comment[]; + getCommentsAfter(nodeOrToken: AST.Ranged): ESTree.Comment[]; - getCommentsInside(node: ESTree.Node): ESTree.Comment[]; + getCommentsInside(node: AST.Ranged): ESTree.Comment[]; } export namespace SourceCode { From fb4adda46f35dac66760505c209f10d4308ab255 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sat, 10 Feb 2018 09:46:07 -0800 Subject: [PATCH 22/23] Revert "Add Ranged interface" This reverts commit c84b2631309e1421913fc24666e6a32758b36d19. --- types/eslint/eslint-tests.ts | 3 +- types/eslint/index.d.ts | 66 +++++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/types/eslint/eslint-tests.ts b/types/eslint/eslint-tests.ts index 425f14580b..376cdf0a92 100644 --- a/types/eslint/eslint-tests.ts +++ b/types/eslint/eslint-tests.ts @@ -1,3 +1,4 @@ +import { Comment } from 'estree'; import { AST, SourceCode, Rule, Linter, CLIEngine, RuleTester, Scope } from 'eslint'; const SOURCE = `var foo = bar;`; @@ -25,7 +26,7 @@ const TOKEN: AST.Token = { range: [0, 3] }; -const COMMENT: AST.Comment = { +const COMMENT: Comment = { type: 'Block', value: 'foo', loc: { diff --git a/types/eslint/index.d.ts b/types/eslint/index.d.ts index 81f3c875c8..9e0e68af0b 100644 --- a/types/eslint/index.d.ts +++ b/types/eslint/index.d.ts @@ -35,20 +35,12 @@ export namespace AST { type Range = [number, number]; - interface Ranged { - range: Range; - } - interface Program extends ESTree.Program { comments: ESTree.Comment[]; tokens: Token[]; loc: SourceLocation; range: Range; } - - interface Comment extends ESTree.Comment { - range: Range; - } } export namespace Scope { @@ -152,42 +144,62 @@ export class SourceCode { getTokenByRangeStart(offset: number, options?: { includeComments?: boolean }): AST.Token | null; - getFirstToken(node: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getFirstToken(node: ESTree.Node, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getFirstTokens(node: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getFirstTokens(node: ESTree.Node, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getLastToken(node: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getLastToken(node: ESTree.Node, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getLastTokens(node: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getLastTokens(node: ESTree.Node, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getTokenBefore(node: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getTokenBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getTokensBefore(node: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getTokensBefore(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getTokenAfter(node: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getTokenAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; - getTokensAfter(node: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getTokensAfter(node: ESTree.Node | AST.Token | ESTree.Comment, options?: SourceCode.CursorWithCountOptions): AST.Token[]; - getFirstTokenBetween(left: AST.Ranged, right: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getFirstTokenBetween( + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, + options?: SourceCode.CursorWithSkipOptions + ): AST.Token | null; - getFirstTokensBetween(left: AST.Ranged, right: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getFirstTokensBetween( + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, + options?: SourceCode.CursorWithCountOptions + ): AST.Token[]; - getLastTokenBetween(left: AST.Ranged, right: AST.Ranged, options?: SourceCode.CursorWithSkipOptions): AST.Token | null; + getLastTokenBetween( + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, + options?: SourceCode.CursorWithSkipOptions + ): AST.Token | null; - getLastTokensBetween(left: AST.Ranged, right: AST.Ranged, options?: SourceCode.CursorWithCountOptions): AST.Token[]; + getLastTokensBetween( + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, + options?: SourceCode.CursorWithCountOptions + ): AST.Token[]; - getTokensBetween(left: AST.Ranged, right: AST.Ranged, padding?: number | SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): AST.Token[]; + getTokensBetween( + left: ESTree.Node | AST.Token | ESTree.Comment, + right: ESTree.Node | AST.Token | ESTree.Comment, + padding?: number | SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions + ): AST.Token[]; - getTokens(node: AST.Ranged, beforeCount?: number, afterCount?: number): AST.Token[]; - getTokens(node: AST.Ranged, options: SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): AST.Token[]; + getTokens(node: ESTree.Node, beforeCount?: number, afterCount?: number): AST.Token[]; + getTokens(node: ESTree.Node, options: SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions): AST.Token[]; - commentsExistBetween(left: AST.Ranged, right: AST.Ranged): boolean; + commentsExistBetween(left: ESTree.Node | AST.Token, right: ESTree.Node | AST.Token): boolean; - getCommentsBefore(nodeOrToken: AST.Ranged): ESTree.Comment[]; + getCommentsBefore(nodeOrToken: ESTree.Node | AST.Token): ESTree.Comment[]; - getCommentsAfter(nodeOrToken: AST.Ranged): ESTree.Comment[]; + getCommentsAfter(nodeOrToken: ESTree.Node | AST.Token): ESTree.Comment[]; - getCommentsInside(node: AST.Ranged): ESTree.Comment[]; + getCommentsInside(node: ESTree.Node): ESTree.Comment[]; } export namespace SourceCode { From 7ed9c988abf562c033e62a29dc8cbce84da4132f Mon Sep 17 00:00:00 2001 From: Pierre-Marie Date: Sat, 10 Feb 2018 10:10:53 -0800 Subject: [PATCH 23/23] Set esModuleInterop to true to fix new test requirements --- types/eslint/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/eslint/tsconfig.json b/types/eslint/tsconfig.json index 2e820d4971..4f53b4a06b 100644 --- a/types/eslint/tsconfig.json +++ b/types/eslint/tsconfig.json @@ -14,7 +14,8 @@ ], "types": [], "noEmit": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true }, "files": [ "index.d.ts",