Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
17 changes: 7 additions & 10 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ const commonRestrictedSyntaxRules = [
message:
'Do not throw string literals or non-Error objects. Throw new Error("...") instead.',
},
{
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.',
},
];

export default tseslint.config(
Expand Down Expand Up @@ -133,16 +139,7 @@ export default tseslint.config(
'no-cond-assign': 'error',
'no-debugger': 'error',
'no-duplicate-case': 'error',
'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-restricted-syntax': ['error', ...commonRestrictedSyntaxRules],
'no-unsafe-finally': 'error',
'no-unused-expressions': 'off', // Disable base rule
'@typescript-eslint/no-unused-expressions': [
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"test:integration:sandbox:none": "cross-env GEMINI_SANDBOX=false vitest run --root ./integration-tests",
"test:integration:sandbox:docker": "cross-env GEMINI_SANDBOX=docker npm run build:sandbox && cross-env GEMINI_SANDBOX=docker vitest run --root ./integration-tests",
"test:integration:sandbox:podman": "cross-env GEMINI_SANDBOX=podman vitest run --root ./integration-tests",
"lint": "eslint . --cache",
"lint": "eslint . --cache --max-warnings 0",
"lint:fix": "eslint . --fix --ext .ts,.tsx && eslint integration-tests --fix && eslint scripts --fix && npm run format",
"lint:ci": "npm run lint:all",
"lint:all": "node scripts/lint.js",
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/nonInteractiveCli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,7 @@ describe('runNonInteractive', () => {

expect(
processStderrSpy.mock.calls.some(
// eslint-disable-next-line no-restricted-syntax
(call) => typeof call[0] === 'string' && call[0].includes('Cancelling'),
),
).toBe(true);
Expand Down
3 changes: 1 addition & 2 deletions packages/cli/src/test-utils/customMatchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export async function toMatchSvgSnapshot(
}

function toHaveOnlyValidCharacters(this: Assertion, buffer: TextBuffer) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion, @typescript-eslint/no-unsafe-assignment
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { isNot } = this as any;
let pass = true;
const invalidLines: Array<{ line: number; content: string }> = [];
Expand Down Expand Up @@ -108,7 +108,6 @@ function toHaveOnlyValidCharacters(this: Assertion, buffer: TextBuffer) {
};
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
expect.extend({
toHaveOnlyValidCharacters,
toMatchSvgSnapshot,
Expand Down
6 changes: 0 additions & 6 deletions packages/cli/src/test-utils/mockCommandContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,12 @@ export const createMockCommandContext = (
},
services: {
agentContext: null,

settings: {
merged: defaultMergedSettings,
setValue: vi.fn(),
forScope: vi.fn().mockReturnValue({ settings: {} }),
} as unknown as LoadedSettings,
git: undefined as GitService | undefined,

logger: {
log: vi.fn(),
logMessage: vi.fn(),
Expand All @@ -53,7 +51,6 @@ export const createMockCommandContext = (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} as any, // Cast because Logger is a class.
},

ui: {
addItem: vi.fn(),
clear: vi.fn(),
Expand All @@ -72,7 +69,6 @@ export const createMockCommandContext = (
} as any,
session: {
sessionShellAllowlist: new Set<string>(),

stats: {
sessionStartTime: new Date(),
lastPromptTokenCount: 0,
Expand All @@ -98,7 +94,6 @@ export const createMockCommandContext = (
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
const sourceValue = source[key];

const targetValue = output[key];

if (
Expand All @@ -109,7 +104,6 @@ export const createMockCommandContext = (
output[key] = merge(targetValue, sourceValue);
} else {
// If not, we do a direct assignment. This preserves Date objects and others.

output[key] = sourceValue;
}
}
Expand Down
1 change: 0 additions & 1 deletion packages/cli/src/test-utils/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,6 @@ export async function renderHook<Result, Props>(
generateSvg: () => string;
}> {
const result = { current: undefined as unknown as Result };

let currentProps = options?.initialProps as Props;

function TestComponent({
Expand Down
2 changes: 0 additions & 2 deletions packages/cli/src/test-utils/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export const createMockSettings = (
workspace,
isTrusted,
errors,

merged: mergedOverride,
...settingsOverrides
} = overrides;
Expand All @@ -61,7 +60,6 @@ export const createMockSettings = (
settings: settingsOverrides,
originalSettings: settingsOverrides,
},

(workspace as any) || { path: '', settings: {}, originalSettings: {} },
isTrusted ?? true,
errors || [],
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/ui/IdeIntegrationNudge.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ describe('IdeIntegrationNudge', () => {
beforeEach(() => {
vi.mocked(debugLogger.warn).mockImplementation((...args) => {
if (
// eslint-disable-next-line no-restricted-syntax
typeof args[0] === 'string' &&
/was not wrapped in act/.test(args[0])
) {
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/ui/auth/AuthInProgress.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ describe('AuthInProgress', () => {
vi.useFakeTimers();
vi.mocked(debugLogger.error).mockImplementation((...args) => {
if (
// eslint-disable-next-line no-restricted-syntax
typeof args[0] === 'string' &&
args[0].includes('was not wrapped in act')
) {
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 @@ -505,7 +505,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
1 change: 1 addition & 0 deletions packages/cli/src/ui/utils/textUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ describe('textUtils', () => {
const b = sanitized.b as { c: string; d: Array<string | object> };
expect(b.c).toBe('\\u001b[32mgreen\\u001b[0m');
expect(b.d[0]).toBe('\\u001b[33myellow\\u001b[0m');
// eslint-disable-next-line no-restricted-syntax
if (typeof b.d[1] === 'object' && b.d[1] !== null) {
const e = b.d[1] as { e: string };
expect(e.e).toBe('\\u001b[34mblue\\u001b[0m');
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/utils/cleanup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ describe('signal and TTY handling', () => {

const sigtermHandlers = processOnHandlers.get('SIGTERM') || [];
expect(sigtermHandlers.length).toBeGreaterThan(0);
// eslint-disable-next-line no-restricted-syntax
expect(typeof sigtermHandlers[0]).toBe('function');
});
});
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/utils/sessions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ describe('listSessions', () => {
// Get all the session log calls (skip the header)
const sessionCalls = mocks.writeToStdout.mock.calls.filter(
(call): call is [string] =>
// eslint-disable-next-line no-restricted-syntax
typeof call[0] === 'string' &&
call[0].includes('[session-') &&
!call[0].includes('Available sessions'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export class FolderTrustDiscoveryService {
for (const event of Object.values(hooksConfig)) {
if (!Array.isArray(event)) continue;
for (const hook of event) {
// eslint-disable-next-line no-restricted-syntax
if (this.isRecord(hook) && typeof hook['command'] === 'string') {
hooks.add(hook['command']);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/telemetry/sanitize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ describe('Telemetry Sanitization', () => {
const attributes = event.toOpenTelemetryAttributes(config);

// Should be JSON stringified
// eslint-disable-next-line no-restricted-syntax
expect(typeof attributes['hook_input']).toBe('string');
// eslint-disable-next-line no-restricted-syntax
expect(typeof attributes['hook_output']).toBe('string');

const parsedInput = JSON.parse(attributes['hook_input'] as string);
Expand Down
4 changes: 0 additions & 4 deletions packages/core/src/test-utils/mock-message-bus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export class MockMessageBus {
if (!this.subscriptions.has(type)) {
this.subscriptions.set(type, new Set());
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
this.subscriptions.get(type)!.add(listener as (message: Message) => void);
},
);
Expand All @@ -74,7 +73,6 @@ export class MockMessageBus {
<T extends Message>(type: T['type'], listener: (message: T) => void) => {
const listeners = this.subscriptions.get(type);
if (listeners) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
listeners.delete(listener as (message: Message) => void);
}
},
Expand Down Expand Up @@ -103,7 +101,6 @@ export class MockMessageBus {
* Create a mock MessageBus for testing
*/
export function createMockMessageBus(): MessageBus {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return new MockMessageBus() as unknown as MessageBus;
}

Expand All @@ -113,6 +110,5 @@ export function createMockMessageBus(): MessageBus {
export function getMockMessageBusInstance(
messageBus: MessageBus,
): MockMessageBus {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return messageBus as unknown as MockMessageBus;
}
1 change: 0 additions & 1 deletion packages/core/src/test-utils/mockWorkspaceContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export function createMockWorkspaceContext(
): WorkspaceContext {
const allDirs = [rootDir, ...additionalDirs];

// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const mockWorkspaceContext = {
addDirectory: vi.fn(),
getDirectories: vi.fn().mockReturnValue(allDirs),
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/tools/read-file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,7 @@ describe('ReadFileTool', () => {
const parts = result.llmContent as Array<Record<string, unknown>>;
const jitTextPart = parts.find(
(p) =>
// eslint-disable-next-line no-restricted-syntax
typeof p['text'] === 'string' && p['text'].includes('Auth rules'),
);
expect(jitTextPart).toBeDefined();
Expand Down
Loading