add linting config for the prompt files source code

This commit is contained in:
Oleg Solomko
2025-05-06 14:56:35 -07:00
parent fa00def553
commit 5ba5d94744
9 changed files with 132 additions and 21 deletions
+93 -1
View File
@@ -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',
}
},
);
+19
View File
@@ -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,
}
}
+1
View File
@@ -114,6 +114,7 @@ export abstract class BaseToken<TText extends string = string> {
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,
@@ -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);
}
@@ -91,8 +91,8 @@ export class MarkdownDecoder extends BaseDecoder<TMarkdownToken, TSimpleDecoderT
// if failed to parse a sequence of a tokens as a single markdown
// entity (e.g., a link), re-emit the tokens accumulated so far
// then reset the current parser object
for (const token of this.current.tokens) {
this._onData.fire(token);
for (const currentToken of this.current.tokens) {
this._onData.fire(currentToken);
}
delete this.current;
@@ -93,7 +93,7 @@ export class MarkdownExtensionsDecoder extends BaseDecoder<TMarkdownExtensionsTo
return;
}
} catch (_error) {
} catch {
// if failed to convert current parser object to a token,
// re-emit the tokens accumulated so far
this.reEmitCurrentTokens();
@@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Line } from '../linesCodec/tokens/line.js';
import { NewLine } from '../linesCodec/tokens/newLine.js';
import { VSBuffer } from '../../../../base/common/buffer.js';
import { ReadableStream } from '../../../../base/common/stream.js';
@@ -100,11 +99,12 @@ export class SimpleDecoder extends BaseDecoder<TSimpleDecoderToken, TLineToken>
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
+3 -3
View File
@@ -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;
}
@@ -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) === 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;
}