Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: remove partial type-information program#6066

New issue

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

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

Already on GitHub?Sign in to your account

Merged
bradzacher merged 7 commits intov6fromremove-partial-type-info-parse
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 24 additions & 29 deletionspackages/eslint-plugin/src/rules/consistent-type-exports.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
import type {
ParserServices,
TSESLint,
TSESTree,
} from '@typescript-eslint/utils';
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { SymbolFlags } from 'typescript';

Expand DownExpand Up@@ -75,6 +71,28 @@ export default util.createRule<Options, MessageIds>({
const sourceExportsMap: { [key: string]: SourceExports } = {};
const parserServices = util.getParserServices(context);

/**
* Helper for identifying if an export specifier resolves to a
* JavaScript value or a TypeScript type.
*
* @returns True/false if is a type or not, or undefined if the specifier
* can't be resolved.
*/
function isSpecifierTypeBased(
specifier: TSESTree.ExportSpecifier,
): boolean | undefined {
const checker = parserServices.program.getTypeChecker();
const node = parserServices.esTreeNodeToTSNodeMap.get(specifier.exported);
const symbol = checker.getSymbolAtLocation(node);
const aliasedSymbol = checker.getAliasedSymbol(symbol!);

if (!aliasedSymbol || aliasedSymbol.escapedName === 'unknown') {
return undefined;
}

return !(aliasedSymbol.flags & SymbolFlags.Value);
}

return {
ExportNamedDeclaration(node: TSESTree.ExportNamedDeclaration): void {
// Coerce the source into a string for use as a lookup entry.
Expand DownExpand Up@@ -112,7 +130,7 @@ export default util.createRule<Options, MessageIds>({
continue;
}

const isTypeBased = isSpecifierTypeBased(parserServices,specifier);
const isTypeBased = isSpecifierTypeBased(specifier);

if (isTypeBased === true) {
typeBasedSpecifiers.push(specifier);
Expand DownExpand Up@@ -199,29 +217,6 @@ export default util.createRule<Options, MessageIds>({
},
});

/**
* Helper for identifying if an export specifier resolves to a
* JavaScript value or a TypeScript type.
*
* @returns True/false if is a type or not, or undefined if the specifier
* can't be resolved.
*/
function isSpecifierTypeBased(
parserServices: ParserServices,
specifier: TSESTree.ExportSpecifier,
): boolean | undefined {
const checker = parserServices.program.getTypeChecker();
const node = parserServices.esTreeNodeToTSNodeMap.get(specifier.exported);
const symbol = checker.getSymbolAtLocation(node);
const aliasedSymbol = checker.getAliasedSymbol(symbol!);

if (!aliasedSymbol || aliasedSymbol.escapedName === 'unknown') {
return undefined;
}

return !(aliasedSymbol.flags & SymbolFlags.Value);
}

/**
* Inserts "type" into an export.
*
Expand Down
6 changes: 2 additions & 4 deletionspackages/eslint-plugin/src/rules/naming-convention.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -90,10 +90,8 @@ export default util.createRule<Options, MessageIds>({

const validators = parseOptions(context);

// getParserServices(context, false) -- dirty hack to work around the docs checker test...
const compilerOptions = util
.getParserServices(context, true)
.program.getCompilerOptions();
const compilerOptions =
util.getParserServices(context, true).program?.getCompilerOptions() ?? {};
function handleMember(
validator: ValidatorFunction | null,
node:
Expand Down
11 changes: 11 additions & 0 deletionspackages/eslint-plugin/tests/docs.test.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -120,6 +120,10 @@ describe('Validating rule docs', () => {
});

describe('Validating rule metadata', () => {
const rulesThatRequireTypeInformationInAWayThatsHardToDetect = new Set([
// the core rule file doesn't use type information, instead it's used in `src/rules/naming-convention-utils/validator.ts`
'naming-convention',
]);
function requiresFullTypeInformation(content: string): boolean {
return /getParserServices(\(\s*[^,\s)]+)\s*(,\s*false\s*)?\)/.test(content);
}
Expand All@@ -135,6 +139,13 @@ describe('Validating rule metadata', () => {
});

it('`requiresTypeChecking` should be set if the rule uses type information', () => {
if (
rulesThatRequireTypeInformationInAWayThatsHardToDetect.has(ruleName)
) {
expect(true).toEqual(rule.meta.docs?.requiresTypeChecking ?? false);
return;
}

// quick-and-dirty check to see if it uses parserServices
// not perfect but should be good enough
const ruleFileContents = fs.readFileSync(
Expand Down
2 changes: 2 additions & 0 deletionspackages/parser/src/index.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
export { parse, parseForESLint, ParserOptions } from './parser';
export {
ParserServices,
ParserServicesWithTypeInformation,
ParserServicesWithoutTypeInformation,
clearCaches,
createProgram,
} from '@typescript-eslint/typescript-estree';
Expand Down
2 changes: 1 addition & 1 deletionpackages/parser/src/parser.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -128,7 +128,7 @@ function parseForESLint(
ast.sourceType = options.sourceType;

let emitDecoratorMetadata = options.emitDecoratorMetadata === true;
if (services.hasFullTypeInformation) {
if (services.program) {
// automatically apply the options configured for the program
const compilerOptions = services.program.getCompilerOptions();
if (analyzeOptions.lib == null) {
Expand Down
2 changes: 2 additions & 0 deletionspackages/type-utils/tests/isTypeReadonly.test.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@ import {
type ReadonlynessOptions,
isTypeReadonly,
} from '../src/isTypeReadonly';
import { expectToHaveParserServices } from './test-utils/expectToHaveParserServices';

describe('isTypeReadonly', () => {
const rootDir = path.join(__dirname, 'fixtures');
Expand All@@ -21,6 +22,7 @@ describe('isTypeReadonly', () => {
filePath: path.join(rootDir, 'file.ts'),
tsconfigRootDir: rootDir,
});
expectToHaveParserServices(services);
const checker = services.program.getTypeChecker();
const esTreeNodeToTSNodeMap = services.esTreeNodeToTSNodeMap;

Expand Down
2 changes: 2 additions & 0 deletionspackages/type-utils/tests/isUnsafeAssignment.test.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@ import path from 'path';
import type * as ts from 'typescript';

import { isUnsafeAssignment } from '../src/isUnsafeAssignment';
import { expectToHaveParserServices } from './test-utils/expectToHaveParserServices';

describe('isUnsafeAssignment', () => {
const rootDir = path.join(__dirname, 'fixtures');
Expand All@@ -19,6 +20,7 @@ describe('isUnsafeAssignment', () => {
filePath: path.join(rootDir, 'file.ts'),
tsconfigRootDir: rootDir,
});
expectToHaveParserServices(services);
const checker = services.program.getTypeChecker();
const esTreeNodeToTSNodeMap = services.esTreeNodeToTSNodeMap;

Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
import type {
ParserServices,
ParserServicesWithTypeInformation,
} from '@typescript-eslint/typescript-estree';

export function expectToHaveParserServices(
services: ParserServices | null | undefined,
): asserts services is ParserServicesWithTypeInformation {
expect(services?.program).toBeDefined();
expect(services?.esTreeNodeToTSNodeMap).toBeDefined();
expect(services?.tsNodeToESTreeNodeMap).toBeDefined();
}
2 changes: 1 addition & 1 deletionpackages/typescript-estree/jest.config.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@
module.exports = {
...require('../../jest.config.base.js'),
testRegex: [
'./tests/lib/.*\\.ts$',
'./tests/lib/.*\\.test\\.ts$',
'./tests/ast-alignment/spec\\.ts$',
'./tests/[^/]+\\.test\\.ts$',
],
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ import path from 'path';
import * as ts from 'typescript';

import type { ParseSettings } from '../parseSettings';
import type {ASTAndProgram } from './shared';
import type {ASTAndDefiniteProgram } from './shared';
import {
createDefaultCompilerOptionsFromExtra,
getModuleResolver,
Expand All@@ -20,7 +20,7 @@ const log = debug('typescript-eslint:typescript-estree:createDefaultProgram');
*/
function createDefaultProgram(
parseSettings: ParseSettings,
):ASTAndProgram | undefined {
):ASTAndDefiniteProgram | undefined {
log(
'Getting default program for: %s',
parseSettings.filePath || 'unnamed file',
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,7 +3,7 @@ import * as ts from 'typescript';

import type { ParseSettings } from '../parseSettings';
import { getScriptKind } from './getScriptKind';
import type {ASTAndProgram } from './shared';
import type {ASTAndDefiniteProgram } from './shared';
import { createDefaultCompilerOptionsFromExtra } from './shared';

const log = debug('typescript-eslint:typescript-estree:createIsolatedProgram');
Expand All@@ -12,7 +12,9 @@ const log = debug('typescript-eslint:typescript-estree:createIsolatedProgram');
* @param code The code of the file being linted
* @returns Returns a new source file and program corresponding to the linted code
*/
function createIsolatedProgram(parseSettings: ParseSettings): ASTAndProgram {
function createIsolatedProgram(
parseSettings: ParseSettings,
): ASTAndDefiniteProgram {
log(
'Getting isolated program in %s mode for: %s',
parseSettings.jsx ? 'TSX' : 'TS',
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,7 +5,7 @@ import * as ts from 'typescript';
import { firstDefined } from '../node-utils';
import type { ParseSettings } from '../parseSettings';
import { getWatchProgramsForProjects } from './getWatchProgramsForProjects';
import type {ASTAndProgram } from './shared';
import type {ASTAndDefiniteProgram } from './shared';
import { getAstFromProgram } from './shared';

const log = debug('typescript-eslint:typescript-estree:createProjectProgram');
Expand All@@ -27,7 +27,7 @@ const DEFAULT_EXTRA_FILE_EXTENSIONS = [
*/
function createProjectProgram(
parseSettings: ParseSettings,
):ASTAndProgram | undefined {
):ASTAndDefiniteProgram | undefined {
log('Creating project program for: %s', parseSettings.filePath);

const programsForProjects = getWatchProgramsForProjects(parseSettings);
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@ import * as ts from 'typescript';
import type { ParseSettings } from '../parseSettings';
import { isSourceFile } from '../source-files';
import { getScriptKind } from './getScriptKind';
import type { ASTAndNoProgram } from './shared';

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

Expand All@@ -25,4 +26,11 @@ function createSourceFile(parseSettings: ParseSettings): ts.SourceFile {
);
}

export { createSourceFile };
function createNoProgram(parseSettings: ParseSettings): ASTAndNoProgram {
return {
ast: createSourceFile(parseSettings),
program: null,
};
}

export { createSourceFile, createNoProgram };
11 changes: 9 additions & 2 deletionspackages/typescript-estree/src/create-program/shared.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,10 +5,15 @@ import * as ts from 'typescript';
import type { ModuleResolver } from '../parser-options';
import type { ParseSettings } from '../parseSettings';

interface ASTAndProgram {
interface ASTAndNoProgram {
ast: ts.SourceFile;
program: null;
}
interface ASTAndDefiniteProgram {
ast: ts.SourceFile;
program: ts.Program;
}
type ASTAndProgram = ASTAndNoProgram | ASTAndDefiniteProgram;

/**
* Compiler options required to avoid critical functionality issues
Expand DownExpand Up@@ -94,7 +99,7 @@ function getExtension(fileName: string | undefined): string | null {
function getAstFromProgram(
currentProgram: Program,
parseSettings: ParseSettings,
):ASTAndProgram | undefined {
):ASTAndDefiniteProgram | undefined {
const ast = currentProgram.getSourceFile(parseSettings.filePath);

// working around https://github.com/typescript-eslint/typescript-eslint/issues/1573
Expand DownExpand Up@@ -125,6 +130,8 @@ function getModuleResolver(moduleResolverPath: string): ModuleResolver {
}

export {
ASTAndDefiniteProgram,
ASTAndNoProgram,
ASTAndProgram,
CORE_COMPILER_OPTIONS,
canonicalDirname,
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,21 +4,21 @@ import * as path from 'path';
import * as ts from 'typescript';

import type { ParseSettings } from '../parseSettings';
import type {ASTAndProgram } from './shared';
import type {ASTAndDefiniteProgram } from './shared';
import { CORE_COMPILER_OPTIONS, getAstFromProgram } from './shared';

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

function useProvidedPrograms(
programInstances: Iterable<ts.Program>,
parseSettings: ParseSettings,
):ASTAndProgram | undefined {
):ASTAndDefiniteProgram | undefined {
log(
'Retrieving ast for %s from provided program instance(s)',
parseSettings.filePath,
);

let astAndProgram:ASTAndProgram | undefined;
let astAndProgram:ASTAndDefiniteProgram | undefined;
for (const programInstance of programInstances) {
astAndProgram = getAstFromProgram(programInstance, parseSettings);
// Stop at the first applicable program instance
Expand Down
7 changes: 6 additions & 1 deletionpackages/typescript-estree/src/index.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,7 +7,12 @@ export {
ParseWithNodeMapsResult,
clearProgramCache,
} from './parser';
export { ParserServices, TSESTreeOptions } from './parser-options';
export {
ParserServices,
ParserServicesWithTypeInformation,
ParserServicesWithoutTypeInformation,
TSESTreeOptions,
} from './parser-options';
export { simpleTraverse } from './simple-traverse';
export * from './ts-estree';
export { clearWatchCaches as clearCaches } from './create-program/getWatchProgramsForProjects';
Expand Down
15 changes: 12 additions & 3 deletionspackages/typescript-estree/src/parser-options.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -182,12 +182,21 @@ export interface ParserWeakMapESTreeToTSNode<
has(key: unknown): boolean;
}

export interface ParserServices {
program: ts.Program;
export interface ParserServicesNodeMaps {
esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode;
tsNodeToESTreeNodeMap: ParserWeakMap<TSNode | TSToken, TSESTree.Node>;
hasFullTypeInformation: boolean;
}
export interface ParserServicesWithTypeInformation
extends ParserServicesNodeMaps {
program: ts.Program;
}
export interface ParserServicesWithoutTypeInformation
extends ParserServicesNodeMaps {
program: null;
}
export type ParserServices =
| ParserServicesWithTypeInformation
| ParserServicesWithoutTypeInformation;

export interface ModuleResolver {
version: 1;
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp