Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
43 changes: 42 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,16 @@ export default tseslint.config(
'no-cond-assign': 'error',
'no-debugger': 'error',
'no-duplicate-case': 'error',
'no-restricted-syntax': ['error', ...commonRestrictedSyntaxRules],
'no-restricted-syntax': [
'error',
...commonRestrictedSyntaxRules,
{
selector:
'UnaryExpression[operator="typeof"] > MemberExpression[computed=true][property.type="Literal"]',
message:
'Do not use typeof to check object properties. Define a TypeScript interface and a type guard function instead.',
},
],
'no-unsafe-finally': 'error',
'no-unused-expressions': 'off', // Disable base rule
'@typescript-eslint/no-unused-expressions': [
Expand Down Expand Up @@ -263,6 +272,38 @@ export default tseslint.config(
...vitest.configs.recommended.rules,
'vitest/expect-expect': 'off',
'vitest/no-commented-out-tests': 'off',
'no-restricted-syntax': [
'error',
{
selector: 'CallExpression[callee.name="require"]',
message: 'Avoid using require(). Use ES6 imports instead.',
},
{
selector: 'ThrowStatement > Literal:not([value=/^\\w+Error:/])',
message:
'Do not throw string literals or non-Error objects. Throw new Error("...") instead.',
},
],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

To improve maintainability and prevent the configurations from drifting apart, you can reuse the commonRestrictedSyntaxRules constant here instead of duplicating the rules. The same applies to the configuration for integration-tests and evals below.

      'no-restricted-syntax': ['error', ...commonRestrictedSyntaxRules],

},
},
{
files: [
'integration-tests/**/*.ts',
'evals/**/*.ts',
],
rules: {
'no-restricted-syntax': [
'error',
{
selector: 'CallExpression[callee.name="require"]',
message: 'Avoid using require(). Use ES6 imports instead.',
},
{
selector: 'ThrowStatement > Literal:not([value=/^\\w+Error:/])',
message:
'Do not throw string literals or non-Error objects. Throw new Error("...") instead.',
},
],
},
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

To improve maintainability and avoid code duplication, please use the commonRestrictedSyntaxRules constant that is already defined in this file. Both of these new no-restricted-syntax blocks are duplicating the rules from that constant.

      'no-restricted-syntax': ['error', ...commonRestrictedSyntaxRules],
    },
  },
  {
    files: [
      'integration-tests/**/*.ts',
      'evals/**/*.ts',
    ],
    rules: {
      'no-restricted-syntax': ['error', ...commonRestrictedSyntaxRules],
    },
  },

{
Expand Down
2 changes: 2 additions & 0 deletions packages/a2a-server/src/agent/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,9 @@ export class Task {
if (
part.kind !== 'data' ||
!part.data ||
// eslint-disable-next-line no-restricted-syntax
typeof part.data['callId'] !== 'string' ||
// eslint-disable-next-line no-restricted-syntax
typeof part.data['outcome'] !== 'string'
) {
return false;
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/commands/hooks/migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ function migrateClaudeHook(claudeHook: unknown): unknown {
migrated['command'] = hook['command'];

// Replace CLAUDE_PROJECT_DIR with GEMINI_PROJECT_DIR in command
// eslint-disable-next-line no-restricted-syntax
if (typeof migrated['command'] === 'string') {
migrated['command'] = migrated['command'].replace(
/\$CLAUDE_PROJECT_DIR/g,
Expand All @@ -93,6 +94,7 @@ function migrateClaudeHook(claudeHook: unknown): unknown {
}

// Map timeout field (Claude uses seconds, Gemini uses seconds)
// eslint-disable-next-line no-restricted-syntax
if ('timeout' in hook && typeof hook['timeout'] === 'number') {
migrated['timeout'] = hook['timeout'];
}
Expand Down Expand Up @@ -140,6 +142,7 @@ function migrateClaudeHooks(claudeConfig: unknown): Record<string, unknown> {
// Transform matcher
if (
'matcher' in definition &&
// eslint-disable-next-line no-restricted-syntax
typeof definition['matcher'] === 'string'
) {
migratedDef['matcher'] = transformMatcher(definition['matcher']);
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/ui/hooks/slashCommandProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,9 @@ export const useSlashCommandProcessor = (
const props = result.props as Record<string, unknown>;
if (
!props ||
// eslint-disable-next-line no-restricted-syntax
typeof props['name'] !== 'string' ||
// eslint-disable-next-line no-restricted-syntax
typeof props['displayName'] !== 'string' ||
!props['definition']
) {
Expand Down
10 changes: 6 additions & 4 deletions packages/cli/src/utils/activityLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,10 @@ export class ActivityLogger extends EventEmitter {

req.write = function (chunk: string | Uint8Array, ...etc: unknown[]) {
if (chunk) {
const arg0 = etc[0];
const encoding =
typeof etc[0] === 'string' && Buffer.isEncoding(etc[0])
? etc[0]
typeof arg0 === 'string' && Buffer.isEncoding(arg0)
? arg0
: undefined;
requestChunks.push(
Buffer.isBuffer(chunk)
Expand All @@ -519,9 +520,10 @@ export class ActivityLogger extends EventEmitter {
) {
const chunk = typeof chunkOrCb === 'function' ? undefined : chunkOrCb;
if (chunk) {
const arg0 = etc[0];
const encoding =
typeof etc[0] === 'string' && Buffer.isEncoding(etc[0])
? etc[0]
typeof arg0 === 'string' && Buffer.isEncoding(arg0)
? arg0
: undefined;
requestChunks.push(
Buffer.isBuffer(chunk)
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/hooks/hookAggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ export class HookAggregator {
// Extract additionalContext from various hook types
if (
'additionalContext' in specific &&
// eslint-disable-next-line no-restricted-syntax
typeof specific['additionalContext'] === 'string'
) {
contexts.push(specific['additionalContext']);
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/services/chatCompressionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,13 @@ async function truncateHistoryToBudget(
} else if (responseObj && typeof responseObj === 'object') {
if (
'output' in responseObj &&
// eslint-disable-next-line no-restricted-syntax
typeof responseObj['output'] === 'string'
) {
contentStr = responseObj['output'];
} else if (
'content' in responseObj &&
// eslint-disable-next-line no-restricted-syntax
typeof responseObj['content'] === 'string'
) {
contentStr = responseObj['content'];
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/telemetry/semantic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ function getStringReferences(parts: AnyPart[]): StringReference[] {
});
}
} else if (part instanceof GenericPart) {
// eslint-disable-next-line no-restricted-syntax
if (part.type === 'executableCode' && typeof part['code'] === 'string') {
refs.push({
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
Expand All @@ -73,6 +74,7 @@ function getStringReferences(parts: AnyPart[]): StringReference[] {
});
} else if (
part.type === 'codeExecutionResult' &&
// eslint-disable-next-line no-restricted-syntax
typeof part['output'] === 'string'
) {
refs.push({
Expand Down
Loading