diff --git a/eslint.config.js b/eslint.config.js index 91e3a6c31d6..0a69ba15dac 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1434,5 +1434,97 @@ export default tseslint.config( '@typescript-eslint/prefer-optional-chain': 'warn', '@typescript-eslint/prefer-readonly': 'warn', } - } + }, + // TODO: @lego + { + extends: [ + ...tseslint.configs.recommendedTypeChecked, + // TODO: @lego + // ...tseslint.configs.strictTypeChecked, + ], + files: [ + 'src/vs/platform/prompts/**/*.ts', + 'src/vs/editor/common/codecs/**/*.ts', + 'src/vs/workbench/contrib/chat/common/promptSyntax/**/*.ts', + ], + languageOptions: { + parser: tseslint.parser, + parserOptions: { + // TODO: @lego + project: [ + 'src/tsconfig.strict.json', + ], + } + }, + plugins: { + '@typescript-eslint': tseslint.plugin, + '@stylistic/ts': stylisticTs, + }, + rules: { + '@typescript-eslint/prefer-readonly': 'warn', + '@typescript-eslint/await-thenable': 'error', + '@typescript-eslint/consistent-type-assertions': ['error', { 'assertionStyle': 'never' }], + '@typescript-eslint/explicit-function-return-type': [ + 'error', + { + allowDirectConstAssertionInArrowFunctions: false, + }, + ], + '@typescript-eslint/explicit-member-accessibility': [ + 'error', + { + accessibility: 'explicit', + ignoredMethodNames: ['constructor'], + } + ], + '@typescript-eslint/explicit-module-boundary-types': 'error', + 'no-shadow': 'off', '@typescript-eslint/no-shadow': 'error', + '@typescript-eslint/ban-ts-comment': 'error', + 'default-param-last': 'off', '@typescript-eslint/default-param-last': 'error', + 'no-array-constructor': 'off', '@typescript-eslint/no-array-constructor': 'error', + '@typescript-eslint/no-array-delete': 'error', + '@typescript-eslint/no-base-to-string': 'error', + '@typescript-eslint/no-confusing-non-null-assertion': 'error', + '@typescript-eslint/no-confusing-void-expression': 'error', + '@typescript-eslint/no-duplicate-enum-values': 'error', + '@typescript-eslint/no-dynamic-delete': 'error', + 'no-empty-function': 'off', '@typescript-eslint/no-empty-function': [ + 'error', + { + 'allow': [ + 'private-constructors' + ] + } + ], + '@typescript-eslint/no-empty-object-type': 'error', + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-extra-non-null-assertion': 'error', + '@typescript-eslint/no-extraneous-class': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-for-in-array': 'error', + 'no-implied-eval': 'off', '@typescript-eslint/no-implied-eval': 'error', + '@typescript-eslint/no-invalid-void-type': 'error', + 'no-loop-func': 'off', '@typescript-eslint/no-loop-func': 'error', + '@typescript-eslint/no-misused-new': 'warn', + '@typescript-eslint/no-misused-promises': 'error', + '@typescript-eslint/no-mixed-enums': 'error', + '@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error', + '@typescript-eslint/no-non-null-asserted-optional-chain': 'error', + '@typescript-eslint/no-non-null-assertion': 'error', + '@typescript-eslint/no-redundant-type-constituents': 'error', + '@typescript-eslint/naming-convention': [ + 'warn', + { 'selector': 'variable', 'format': ['camelCase', 'UPPER_CASE', 'PascalCase'] }, + { 'selector': 'variable', 'filter': '^I.+Service$', 'format': ['PascalCase'], 'prefix': ['I'] }, + { 'selector': 'enumMember', 'format': ['PascalCase'] }, + { 'selector': 'typeAlias', 'format': ['PascalCase'], 'prefix': ['T'] }, + { 'selector': 'interface', 'format': ['PascalCase'], 'prefix': ['I'] } + ], + 'comma-dangle': ['warn', 'only-multiline'], + // // TODO: @lego + // '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'off', + // TODO: @lego - comes from 'tseslint.configs.recommendedTypeChecked', but does not allow objects with `toString()` implementations + '@typescript-eslint/restrict-template-expressions': 'off', + } + }, ); diff --git a/src/tsconfig.strict.json b/src/tsconfig.strict.json new file mode 100644 index 00000000000..c4b8970aca0 --- /dev/null +++ b/src/tsconfig.strict.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "alwaysStrict": true, + "exactOptionalPropertyTypes": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true, + } +} diff --git a/src/vs/editor/common/codecs/baseToken.ts b/src/vs/editor/common/codecs/baseToken.ts index 558905cb64a..14919c9a44d 100644 --- a/src/vs/editor/common/codecs/baseToken.ts +++ b/src/vs/editor/common/codecs/baseToken.ts @@ -114,6 +114,7 @@ export abstract class BaseToken { firstToken.range.startLineNumber <= lastToken.range.startLineNumber, 'First token must start on previous or the same line as the last token.', ); + if ((firstToken !== lastToken) && (firstToken.range.startLineNumber === lastToken.range.startLineNumber)) { assert( firstToken.range.endColumn <= lastToken.range.startColumn, diff --git a/src/vs/editor/common/codecs/compositeToken.ts b/src/vs/editor/common/codecs/compositeToken.ts index a751865f323..0659b55a0d6 100644 --- a/src/vs/editor/common/codecs/compositeToken.ts +++ b/src/vs/editor/common/codecs/compositeToken.ts @@ -17,7 +17,7 @@ export abstract class CompositeToken< super(BaseToken.fullRange(childTokens)); } - public override get text() { + public override get text(): string { return BaseToken.render(this.childTokens); } diff --git a/src/vs/editor/common/codecs/markdownCodec/markdownDecoder.ts b/src/vs/editor/common/codecs/markdownCodec/markdownDecoder.ts index 7825ab6ac88..7dd32661181 100644 --- a/src/vs/editor/common/codecs/markdownCodec/markdownDecoder.ts +++ b/src/vs/editor/common/codecs/markdownCodec/markdownDecoder.ts @@ -91,8 +91,8 @@ export class MarkdownDecoder extends BaseDecoder while (i < lineText.length) { // index is 0-based, but column numbers are 1-based const columnNumber = i + 1; + const character = lineText[i]; // check if the current character is a well-known token const tokenConstructor = WELL_KNOWN_TOKENS .find((wellKnownToken) => { - return wellKnownToken.symbol === lineText[i]; + return wellKnownToken.symbol === character; }); // if it is a well-known token, emit it and continue to the next one diff --git a/src/vs/platform/prompts/common/config.ts b/src/vs/platform/prompts/common/config.ts index 1b992112e08..f46d38bff3b 100644 --- a/src/vs/platform/prompts/common/config.ts +++ b/src/vs/platform/prompts/common/config.ts @@ -107,9 +107,9 @@ export namespace PromptsConfig { } // copy all the enabled paths to the result list - for (const [path, enabled] of Object.entries(value)) { + for (const [path, enabledValue] of Object.entries(value)) { // we already added the default source folder, so skip it - if ((enabled === false) || (path === defaultSourceFolder)) { + if ((enabledValue === false) || (path === defaultSourceFolder)) { continue; } @@ -132,7 +132,7 @@ export namespace PromptsConfig { * be clearly mapped to a boolean (e.g., `"true"`, `"TRUE"`, `"FaLSe"`, etc.), * `undefined` for rest of the values */ -export const asBoolean = (value: any): boolean | undefined => { +export const asBoolean = (value: unknown): boolean | undefined => { if (typeof value === 'boolean') { return value; } diff --git a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts index 8fc054c5d81..4c0c59e73f3 100644 --- a/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts +++ b/src/vs/workbench/contrib/chat/common/promptSyntax/service/promptsService.ts @@ -8,16 +8,16 @@ import { localize } from '../../../../../../nls.js'; import { PROMPT_LANGUAGE_ID } from '../constants.js'; import { flatten, forEach } from '../utils/treeUtils.js'; import { PromptParser } from '../parsers/promptParser.js'; -import { URI } from '../../../../../../base/common/uri.js'; -import { IPromptFileReference } from '../parsers/types.js'; import { match } from '../../../../../../base/common/glob.js'; import { pick } from '../../../../../../base/common/arrays.js'; +import { type URI } from '../../../../../../base/common/uri.js'; +import { type IPromptFileReference } from '../parsers/types.js'; import { assert } from '../../../../../../base/common/assert.js'; import { basename } from '../../../../../../base/common/path.js'; import { ResourceSet } from '../../../../../../base/common/map.js'; import { PromptFilesLocator } from '../utils/promptFilesLocator.js'; -import { ITextModel } from '../../../../../../editor/common/model.js'; import { Disposable } from '../../../../../../base/common/lifecycle.js'; +import { type ITextModel } from '../../../../../../editor/common/model.js'; import { ObjectCache } from '../../../../../../base/common/objectCache.js'; import { ILogService } from '../../../../../../platform/log/common/log.js'; import { TextModelPromptParser } from '../parsers/textModelPromptParser.js'; @@ -27,13 +27,13 @@ import { logTime, TLogFunction } from '../../../../../../base/common/decorators/ import { PROMPT_FILE_EXTENSION } from '../../../../../../platform/prompts/common/constants.js'; import { IInstantiationService } from '../../../../../../platform/instantiation/common/instantiation.js'; import { IUserDataProfileService } from '../../../../../services/userDataProfile/common/userDataProfile.js'; -import { IChatPromptSlashCommand, TCombinedToolsMetadata, IMetadata, IPromptPath, IPromptsService, TPromptsStorage, TPromptsType } from './types.js'; +import type { IChatPromptSlashCommand, TCombinedToolsMetadata, IMetadata, IPromptPath, IPromptsService, TPromptsStorage, TPromptsType } from './types.js'; /** * Provides prompt services. */ export class PromptsService extends Disposable implements IPromptsService { - declare readonly _serviceBrand: undefined; + public declare readonly _serviceBrand: undefined; /** * Cache of text model content prompt parsers. @@ -160,9 +160,9 @@ export class PromptsService extends Disposable implements IPromptsService { if (result) { return result; } - const model = this.modelService.getModels().find(model => model.getLanguageId() === PROMPT_LANGUAGE_ID && getPromptCommandName(model.uri.path) === command); - if (model) { - return { uri: model.uri, storage: 'local', type: 'prompt' }; + const textModel = this.modelService.getModels().find(model => model.getLanguageId() === PROMPT_LANGUAGE_ID && getPromptCommandName(model.uri.path) === command); + if (textModel) { + return { uri: textModel.uri, storage: 'local', type: 'prompt' }; } return undefined; } @@ -300,7 +300,7 @@ export class PromptsService extends Disposable implements IPromptsService { return false; }, fileMetadata); - if ((chatMode) === ChatMode.Agent) { + if (chatMode === ChatMode.Agent) { return { tools: (hasTools) ? [...new Set(result)] @@ -410,8 +410,7 @@ const collectMetadata = ( }; }; - -export function getPromptCommandName(path: string) { +export function getPromptCommandName(path: string): string { const name = basename(path, PROMPT_FILE_EXTENSION); return name; }