Run TS eslint rules directly with strip-types

Wth node 20.18, we can now run these typescript files directly instead of having to use ts-node
This commit is contained in:
Matt Bierner
2025-11-14 14:38:15 -08:00
parent 18279e23d7
commit b8329a3ffc
44 changed files with 127 additions and 136 deletions

View File

@@ -4,11 +4,12 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { readFileSync } from 'fs';
import { join } from 'path';
export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
export default new class ApiProviderNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -22,7 +23,8 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
const modules = new Set<string>();
try {
const { dependencies, optionalDependencies } = require(join(__dirname, '../package.json'));
const packageJson = JSON.parse(readFileSync(join(import.meta.dirname, '../package.json'), 'utf-8'));
const { dependencies, optionalDependencies } = packageJson;
const all = Object.keys(dependencies).concat(Object.keys(optionalDependencies));
for (const key of all) {
modules.add(key);

View File

@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class DeclareServiceBrand implements eslint.Rule.RuleModule {
export default new class DeclareServiceBrand implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
fixable: 'code',

View File

@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import { Node } from 'estree';
import type * as estree from 'estree';
export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rule.RuleModule {
export default new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
type: 'problem',
@@ -18,7 +18,7 @@ export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rul
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ exclude: string[] }>context.options[0];
const config = context.options[0] as { exclude: string[] };
const needle = context.getFilename().replace(/\\/g, '/');
if (config.exclude.some((e) => needle.endsWith(e))) {
@@ -26,7 +26,7 @@ export = new class EnsureNoDisposablesAreLeakedInTestSuite implements eslint.Rul
}
return {
[`Program > ExpressionStatement > CallExpression[callee.name='suite']`]: (node: Node) => {
[`Program > ExpressionStatement > CallExpression[callee.name='suite']`]: (node: estree.Node) => {
const src = context.getSourceCode().getText(node);
if (!src.includes('ensureNoDisposablesAreLeakedInTestSuite(')) {
context.report({

View File

@@ -7,9 +7,9 @@ import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/utils';
import * as path from 'path';
import minimatch from 'minimatch';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
const REPO_ROOT = path.normalize(path.join(__dirname, '../'));
const REPO_ROOT = path.normalize(path.join(import.meta.dirname, '../'));
interface ConditionalPattern {
when?: 'hasBrowser' | 'hasNode' | 'hasElectron' | 'test';
@@ -31,7 +31,7 @@ interface LayerAllowRule {
type RawOption = RawImportPatternsConfig | LayerAllowRule;
function isLayerAllowRule(option: RawOption): option is LayerAllowRule {
return !!((<LayerAllowRule>option).when && (<LayerAllowRule>option).allow);
return !!((option as LayerAllowRule).when && (option as LayerAllowRule).allow);
}
interface ImportPatternsConfig {
@@ -39,7 +39,7 @@ interface ImportPatternsConfig {
restrictions: string[];
}
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -55,7 +55,7 @@ export = new class implements eslint.Rule.RuleModule {
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const options = <RawOption[]>context.options;
const options = context.options as RawOption[];
const configs = this._processOptions(options);
const relativeFilename = getRelativeFilename(context);
@@ -217,7 +217,7 @@ export = new class implements eslint.Rule.RuleModule {
configs.push(testConfig);
}
} else {
configs.push({ target, restrictions: <string[]>restrictions.filter(r => typeof r === 'string') });
configs.push({ target, restrictions: restrictions.filter(r => typeof r === 'string') as string[] });
}
}
this._optionsCache.set(options, configs);

View File

@@ -5,14 +5,14 @@
import * as eslint from 'eslint';
import { join, dirname } from 'path';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
type Config = {
allowed: Set<string>;
disallowed: Set<string>;
};
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -38,9 +38,7 @@ export = new class implements eslint.Rule.RuleModule {
const fileDirname = dirname(context.getFilename());
const parts = fileDirname.split(/\\|\//);
const ruleArgs = <Record<string, string[]>>context.options[0];
let config: Config | undefined;
const ruleArgs = context.options[0] as Record<string, string[]>; let config: Config | undefined;
for (let i = parts.length - 1; i >= 0; i--) {
if (ruleArgs[parts[i]]) {
config = {
@@ -91,4 +89,3 @@ export = new class implements eslint.Rule.RuleModule {
});
}
};

View File

@@ -6,9 +6,9 @@
import * as eslint from 'eslint';
import { dirname, relative } from 'path';
import minimatch from 'minimatch';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -29,11 +29,11 @@ export = new class implements eslint.Rule.RuleModule {
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
let fileRelativePath = relative(dirname(__dirname), context.getFilename());
let fileRelativePath = relative(dirname(import.meta.dirname), context.getFilename());
if (!fileRelativePath.endsWith('/')) {
fileRelativePath += '/';
}
const ruleArgs = <Record<string, string[]>>context.options[0];
const ruleArgs = context.options[0] as Record<string, string[]>;
const matchingKey = Object.keys(ruleArgs).find(key => fileRelativePath.startsWith(key) || minimatch(fileRelativePath, key));
if (!matchingKey) {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
const VALID_USES = new Set<TSESTree.AST_NODE_TYPES | undefined>([
@@ -12,14 +12,14 @@ const VALID_USES = new Set<TSESTree.AST_NODE_TYPES | undefined>([
TSESTree.AST_NODE_TYPES.VariableDeclarator,
]);
export = new class MustUseResults implements eslint.Rule.RuleModule {
export default new class MustUseResults implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
schema: false
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ message: string; functions: string[] }[]>context.options[0];
const config = context.options[0] as { message: string; functions: string[] }[];
const listener: eslint.Rule.RuleListener = {};
for (const { message, functions } of config) {

View File

@@ -3,11 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import type * as ESTree from 'estree';
export = new class NoAsyncSuite implements eslint.Rule.RuleModule {
export default new class NoAsyncSuite implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function doesCallSuperDispose(node: TSESTree.MethodDefinition) {

View File

@@ -6,7 +6,7 @@
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/utils';
export = new class NoAnyCasts implements eslint.Rule.RuleModule {
export default new class NoAnyCasts implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {

View File

@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
export = new class NoDangerousTypeAssertions implements eslint.Rule.RuleModule {
export default new class NoDangerousTypeAssertions implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {

View File

@@ -5,9 +5,9 @@
import * as eslint from 'eslint';
import { join, dirname } from 'path';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {

View File

@@ -5,7 +5,7 @@
import * as eslint from 'eslint';
export = new class NoGlobalDocumentListener implements eslint.Rule.RuleModule {
export default new class NoGlobalDocumentListener implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
/**
@@ -17,7 +17,7 @@ import { TSESTree } from '@typescript-eslint/utils';
* Exception: Type predicate functions are allowed to use the `in` operator
* since they are the standard way to perform runtime type checking.
*/
export = new class NoInOperator implements eslint.Rule.RuleModule {
export default new class NoInOperator implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {

View File

@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
export default new class ApiProviderNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {

View File

@@ -5,9 +5,9 @@
import * as eslint from 'eslint';
import { join } from 'path';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule {
export default new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {

View File

@@ -6,9 +6,9 @@
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import * as visitorKeys from 'eslint-visitor-keys';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class NoObservableGetInReactiveContext implements eslint.Rule.RuleModule {
export default new class NoObservableGetInReactiveContext implements eslint.Rule.RuleModule {
meta: eslint.Rule.RuleMetaData = {
type: 'problem',
docs: {

View File

@@ -4,14 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
/**
* Checks for potentially unsafe usage of `DisposableStore` / `MutableDisposable`.
*
* These have been the source of leaks in the past.
*/
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function checkVariableDeclaration(inNode: ESTree.Node) {

View File

@@ -5,9 +5,9 @@
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class NoReaderAfterAwait implements eslint.Rule.RuleModule {
export default new class NoReaderAfterAwait implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {
'CallExpression': (node: ESTree.CallExpression) => {

View File

@@ -7,9 +7,9 @@ import { TSESTree } from '@typescript-eslint/typescript-estree';
import * as eslint from 'eslint';
import { dirname, join, relative } from 'path';
import minimatch from 'minimatch';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -30,11 +30,11 @@ export = new class implements eslint.Rule.RuleModule {
};
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
let fileRelativePath = relative(dirname(__dirname), context.getFilename());
let fileRelativePath = relative(dirname(import.meta.dirname), context.getFilename());
if (!fileRelativePath.endsWith('/')) {
fileRelativePath += '/';
}
const ruleArgs = <Record<string, string[]>>context.options[0];
const ruleArgs = context.options[0] as Record<string, string[]>;
const matchingKey = Object.keys(ruleArgs).find(key => fileRelativePath.startsWith(key) || minimatch(fileRelativePath, key));
if (!matchingKey) {

View File

@@ -5,9 +5,9 @@
import * as eslint from 'eslint';
import { join } from 'path';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule {
export default new class NoNlsInStandaloneEditorRule implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {

View File

@@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
/**
* WORKAROUND for https://github.com/evanw/esbuild/issues/3823
*/
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
function isCallExpression(node: TSESTree.Node): node is TSESTree.CallExpression {
@@ -15,7 +15,7 @@ function isFunctionExpression(node: TSESTree.Node): node is TSESTree.FunctionExp
return node.type.includes('FunctionExpression');
}
export = new class NoAsyncSuite implements eslint.Rule.RuleModule {
export default new class NoAsyncSuite implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function hasAsyncSuite(node: ESTree.Node) {

View File

@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class NoTestOnly implements eslint.Rule.RuleModule {
export default new class NoTestOnly implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
return {

View File

@@ -5,7 +5,7 @@
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
function isStringLiteral(node: TSESTree.Node | ESTree.Node | null | undefined): node is TSESTree.StringLiteral {
return !!node && node.type === AST_NODE_TYPES.Literal && typeof node.value === 'string';
@@ -24,7 +24,7 @@ function isDoubleQuoted(node: TSESTree.StringLiteral): boolean {
const enableDoubleToSingleQuoteFixes = false;
export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
export default new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
private static _rNlsKeys = /^[_a-zA-Z0-9][ .\-_a-zA-Z0-9]*$/;
@@ -100,9 +100,7 @@ export = new class NoUnexternalizedStrings implements eslint.Rule.RuleModule {
function visitL10NCall(node: TSESTree.CallExpression) {
// localize(key, message)
const [messageNode] = (<TSESTree.CallExpression>node).arguments;
// remove message-argument from doubleQuoted list and make
const [messageNode] = (node as TSESTree.CallExpression).arguments; // remove message-argument from doubleQuoted list and make
// sure it is a string-literal
if (isStringLiteral(messageNode)) {
doubleQuotedStringLiterals.delete(messageNode);

View File

@@ -13,13 +13,13 @@
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
export default {
meta: {
type: 'suggestion',
@@ -141,8 +141,8 @@ module.exports = {
return {
ExpressionStatement(node: TSESTree.ExpressionStatement) {
if (!isValidExpression(node.expression) && !isDirective(node, <TSESTree.Node[]>context.sourceCode.getAncestors(node as ESTree.Node))) {
context.report({ node: <ESTree.Node>node, message: `Expected an assignment or function call and instead saw an expression. ${node.expression}` });
if (!isValidExpression(node.expression) && !isDirective(node, context.sourceCode.getAncestors(node as ESTree.Node) as TSESTree.Node[])) {
context.report({ node: node as ESTree.Node, message: `Expected an assignment or function call and instead saw an expression. ${node.expression}` });
}
}
};

View File

@@ -11,7 +11,7 @@ import * as eslint from 'eslint';
*
* This catches a common bug where a service is accidentally made public by simply writing: `readonly prop: Foo`
*/
export = new class implements eslint.Rule.RuleModule {
export default new class implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function check(node: TSESTree.TSParameterProperty) {

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
/**
* Ensures that localization keys in policy blocks match the keys used in nls.localize() calls.
@@ -22,7 +22,7 @@ import * as ESTree from 'estree';
* The key property ('autoApprove2.description') must match the first argument
* to nls.localize() ('autoApprove2.description').
*/
export = new class PolicyLocalizationKeyMatch implements eslint.Rule.RuleModule {
export default new class PolicyLocalizationKeyMatch implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {

View File

@@ -6,10 +6,10 @@
import * as eslint from 'eslint';
import { TSESTree } from '@typescript-eslint/utils';
import { readFileSync } from 'fs';
import { createImportRuleListener } from './utils';
import { createImportRuleListener } from './utils.ts';
export = new class TranslationRemind implements eslint.Rule.RuleModule {
export default new class TranslationRemind implements eslint.Rule.RuleModule {
private static NLS_MODULE = 'vs/nls';

View File

@@ -1,25 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// @ts-check
const glob = require('glob');
const path = require('path');
require('ts-node').register({
experimentalResolver: true,
transpileOnly: true,
compilerOptions: {
module: 'nodenext',
moduleResolution: 'nodenext',
}
});
// Re-export all .ts files as rules
/** @type {Record<string, import('@typescript-eslint/utils/ts-eslint').LooseRuleDefinition>} */
const rules = {};
glob.sync(`${__dirname}/*.ts`).forEach((file) => {
rules[path.basename(file, '.ts')] = require(file);
});
exports.rules = rules;

View File

@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type { LooseRuleDefinition } from '@typescript-eslint/utils/ts-eslint';
import glob from 'glob';
import { createRequire } from 'module';
import path from 'path';
const require = createRequire(import.meta.url);
// Re-export all .ts files as rules
const rules: Record<string, LooseRuleDefinition> = {};
glob.sync(`${import.meta.dirname}/*.ts`)
.filter(file => !file.endsWith('index.ts') && !file.endsWith('utils.ts'))
.map(file => {
rules[path.basename(file, '.ts')] = require(file).default;
});
export { rules };

View File

@@ -1,5 +1,5 @@
{
"type": "commonjs",
"type": "module",
"scripts": {
"typecheck": "tsgo -p tsconfig.json --noEmit"
}

View File

@@ -5,27 +5,25 @@
"ES2024"
],
"rootDir": ".",
"module": "commonjs",
"esModuleInterop": true,
"alwaysStrict": true,
"allowJs": true,
"module": "esnext",
"allowImportingTsExtensions": true,
"erasableSyntaxOnly": true,
"noEmit": true,
"strict": true,
"exactOptionalPropertyTypes": false,
"useUnknownInCatchVariables": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"newLine": "lf",
"noEmit": true,
"typeRoots": [
"."
]
},
"include": [
"./**/*.ts",
"./**/*.js"
],
"exclude": [
"node_modules/**",
"tests/**"
"./tests/**"
]
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
export function createImportRuleListener(validateImport: (node: TSESTree.Literal, value: string) => any): eslint.Rule.RuleListener {

View File

@@ -6,7 +6,7 @@
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
export default new class ApiProviderNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -21,7 +21,7 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature[key.name=/^(provide|resolve).+/]']: (node: TSESTree.Node) => {
let found = false;
for (const param of (<TSESTree.TSMethodSignature>node).params) {
for (const param of (node as TSESTree.TSMethodSignature).params) {
if (param.type === AST_NODE_TYPES.Identifier) {
found = found || param.name === 'token';
}

View File

@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils';
export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
export default new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#creating-objects' },
@@ -20,7 +20,7 @@ export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
return {
['TSDeclareFunction Identifier[name=/create.*/]']: (node: ESTree.Node) => {
const decl = <TSESTree.FunctionDeclaration>(<TSESTree.Identifier>node).parent;
const decl = (node as TSESTree.Identifier).parent as TSESTree.FunctionDeclaration;
if (decl.returnType?.typeAnnotation.type !== AST_NODE_TYPES.TSTypeReference) {
return;

View File

@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils';
export = new class ApiEventNaming implements eslint.Rule.RuleModule {
export default new class ApiEventNaming implements eslint.Rule.RuleModule {
private static _nameRegExp = /on(Did|Will)([A-Z][a-z]+)([A-Z][a-z]+)?/;
@@ -26,14 +26,14 @@ export = new class ApiEventNaming implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ allowed: string[]; verbs: string[] }>context.options[0];
const config = context.options[0] as { allowed: string[]; verbs: string[] };
const allowed = new Set(config.allowed);
const verbs = new Set(config.verbs);
return {
['TSTypeAnnotation TSTypeReference Identifier[name="Event"]']: (node: ESTree.Identifier) => {
const def = (<TSESTree.Identifier>node).parent?.parent?.parent;
const def = (node as TSESTree.Identifier).parent?.parent?.parent;
const ident = this.getIdent(def);
if (!ident) {

View File

@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
export = new class ApiInterfaceNaming implements eslint.Rule.RuleModule {
export default new class ApiInterfaceNaming implements eslint.Rule.RuleModule {
private static _nameRegExp = /^I[A-Z]/;
@@ -23,7 +23,7 @@ export = new class ApiInterfaceNaming implements eslint.Rule.RuleModule {
return {
['TSInterfaceDeclaration Identifier']: (node: ESTree.Identifier) => {
const name = (<TSESTree.Identifier>node).name;
const name = (node as TSESTree.Identifier).name;
if (ApiInterfaceNaming._nameRegExp.test(name)) {
context.report({
node,

View File

@@ -6,7 +6,7 @@
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
export = new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
export default new class ApiLiteralOrTypes implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines#enums' },

View File

@@ -6,7 +6,7 @@
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
export default new class ApiProviderNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {
@@ -19,18 +19,18 @@ export = new class ApiProviderNaming implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
const config = <{ allowed: string[] }>context.options[0];
const config = context.options[0] as { allowed: string[] };
const allowed = new Set(config.allowed);
return {
['TSInterfaceDeclaration[id.name=/.+Provider/] TSMethodSignature']: (node: TSESTree.Node) => {
const interfaceName = (<TSESTree.TSInterfaceDeclaration>(<TSESTree.Identifier>node).parent?.parent).id.name;
const interfaceName = ((node as TSESTree.Identifier).parent?.parent as TSESTree.TSInterfaceDeclaration).id.name;
if (allowed.has(interfaceName)) {
// allowed
return;
}
const methodName = ((<TSESTree.TSMethodSignatureNonComputedName>node).key as TSESTree.Identifier).name;
const methodName = ((node as TSESTree.TSMethodSignatureNonComputedName).key as TSESTree.Identifier).name;
if (!ApiProviderNaming._providerFunctionNames.test(methodName)) {
context.report({

View File

@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
import { TSESTree } from '@typescript-eslint/utils';
export = new class ApiTypeDiscrimination implements eslint.Rule.RuleModule {
export default new class ApiTypeDiscrimination implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
docs: { url: 'https://github.com/microsoft/vscode/wiki/Extension-API-guidelines' },

View File

@@ -5,9 +5,9 @@
import { TSESTree } from '@typescript-eslint/utils';
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class VscodeDtsUseExport implements eslint.Rule.RuleModule {
export default new class VscodeDtsUseExport implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {

View File

@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class ApiEventNaming implements eslint.Rule.RuleModule {
export default new class ApiEventNaming implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {

View File

@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import * as eslint from 'eslint';
import * as ESTree from 'estree';
import type * as ESTree from 'estree';
export = new class ApiVsCodeInComments implements eslint.Rule.RuleModule {
export default new class ApiVsCodeInComments implements eslint.Rule.RuleModule {
readonly meta: eslint.Rule.RuleMetaData = {
messages: {

View File

@@ -8,7 +8,7 @@ import path from 'path';
import tseslint from 'typescript-eslint';
import stylisticTs from '@stylistic/eslint-plugin-ts';
import * as pluginLocal from './.eslint-plugin-local/index.js';
import * as pluginLocal from './.eslint-plugin-local/index.ts';
import pluginJsdoc from 'eslint-plugin-jsdoc';
import pluginHeader from 'eslint-plugin-header';
@@ -183,7 +183,8 @@ export default tseslint.config(
// Disallow 'in' operator except in type predicates
{
files: [
'**/*.ts'
'**/*.ts',
'.eslint-plugin-local/**/*.ts', // Explicitly include files under dot directories
],
ignores: [
'src/bootstrap-node.ts',