summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/hooks/atCommandProcessor.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli/src/ui/hooks/atCommandProcessor.test.ts')
-rw-r--r--packages/cli/src/ui/hooks/atCommandProcessor.test.ts394
1 files changed, 393 insertions, 1 deletions
diff --git a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts
index 2b4c81a3..583c0b2e 100644
--- a/packages/cli/src/ui/hooks/atCommandProcessor.test.ts
+++ b/packages/cli/src/ui/hooks/atCommandProcessor.test.ts
@@ -689,5 +689,397 @@ describe('handleAtCommand', () => {
`Ignored 1 files:\nGemini-ignored: ${geminiIgnoredFile}`,
);
});
- // });
+
+ describe('punctuation termination in @ commands', () => {
+ const punctuationTestCases = [
+ {
+ name: 'comma',
+ fileName: 'test.txt',
+ fileContent: 'File content here',
+ queryTemplate: (filePath: string) =>
+ `Look at @${filePath}, then explain it.`,
+ messageId: 400,
+ },
+ {
+ name: 'period',
+ fileName: 'readme.md',
+ fileContent: 'File content here',
+ queryTemplate: (filePath: string) =>
+ `Check @${filePath}. What does it say?`,
+ messageId: 401,
+ },
+ {
+ name: 'semicolon',
+ fileName: 'example.js',
+ fileContent: 'Code example',
+ queryTemplate: (filePath: string) =>
+ `Review @${filePath}; check for bugs.`,
+ messageId: 402,
+ },
+ {
+ name: 'exclamation mark',
+ fileName: 'important.txt',
+ fileContent: 'Important content',
+ queryTemplate: (filePath: string) =>
+ `Look at @${filePath}! This is critical.`,
+ messageId: 403,
+ },
+ {
+ name: 'question mark',
+ fileName: 'config.json',
+ fileContent: 'Config settings',
+ queryTemplate: (filePath: string) =>
+ `What is in @${filePath}? Please explain.`,
+ messageId: 404,
+ },
+ {
+ name: 'opening parenthesis',
+ fileName: 'func.ts',
+ fileContent: 'Function definition',
+ queryTemplate: (filePath: string) =>
+ `Analyze @${filePath}(the main function).`,
+ messageId: 405,
+ },
+ {
+ name: 'closing parenthesis',
+ fileName: 'data.json',
+ fileContent: 'Test data',
+ queryTemplate: (filePath: string) =>
+ `Use data from @${filePath}) for testing.`,
+ messageId: 406,
+ },
+ {
+ name: 'opening square bracket',
+ fileName: 'array.js',
+ fileContent: 'Array data',
+ queryTemplate: (filePath: string) =>
+ `Check @${filePath}[0] for the first element.`,
+ messageId: 407,
+ },
+ {
+ name: 'closing square bracket',
+ fileName: 'list.md',
+ fileContent: 'List content',
+ queryTemplate: (filePath: string) =>
+ `Review item @${filePath}] from the list.`,
+ messageId: 408,
+ },
+ {
+ name: 'opening curly brace',
+ fileName: 'object.ts',
+ fileContent: 'Object definition',
+ queryTemplate: (filePath: string) =>
+ `Parse @${filePath}{prop1: value1}.`,
+ messageId: 409,
+ },
+ {
+ name: 'closing curly brace',
+ fileName: 'config.yaml',
+ fileContent: 'Configuration',
+ queryTemplate: (filePath: string) =>
+ `Use settings from @${filePath}} for deployment.`,
+ messageId: 410,
+ },
+ ];
+
+ it.each(punctuationTestCases)(
+ 'should terminate @path at $name',
+ async ({ fileName, fileContent, queryTemplate, messageId }) => {
+ const filePath = await createTestFile(
+ path.join(testRootDir, fileName),
+ fileContent,
+ );
+ const query = queryTemplate(filePath);
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: query },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${filePath}:\n` },
+ { text: fileContent },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ },
+ );
+
+ it('should handle multiple @paths terminated by different punctuation', async () => {
+ const content1 = 'First file';
+ const file1Path = await createTestFile(
+ path.join(testRootDir, 'first.txt'),
+ content1,
+ );
+ const content2 = 'Second file';
+ const file2Path = await createTestFile(
+ path.join(testRootDir, 'second.txt'),
+ content2,
+ );
+ const query = `Compare @${file1Path}, @${file2Path}; what's different?`;
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId: 411,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: `Compare @${file1Path}, @${file2Path}; what's different?` },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${file1Path}:\n` },
+ { text: content1 },
+ { text: `\nContent from @${file2Path}:\n` },
+ { text: content2 },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ });
+
+ it('should still handle escaped spaces in paths before punctuation', async () => {
+ const fileContent = 'Spaced file content';
+ const filePath = await createTestFile(
+ path.join(testRootDir, 'spaced file.txt'),
+ fileContent,
+ );
+ const escapedPath = path.join(testRootDir, 'spaced\\ file.txt');
+ const query = `Check @${escapedPath}, it has spaces.`;
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId: 412,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: `Check @${filePath}, it has spaces.` },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${filePath}:\n` },
+ { text: fileContent },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ });
+
+ it('should not break file paths with periods in extensions', async () => {
+ const fileContent = 'TypeScript content';
+ const filePath = await createTestFile(
+ path.join(testRootDir, 'example.d.ts'),
+ fileContent,
+ );
+ const query = `Analyze @${filePath} for type definitions.`;
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId: 413,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: `Analyze @${filePath} for type definitions.` },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${filePath}:\n` },
+ { text: fileContent },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ });
+
+ it('should handle file paths ending with period followed by space', async () => {
+ const fileContent = 'Config content';
+ const filePath = await createTestFile(
+ path.join(testRootDir, 'config.json'),
+ fileContent,
+ );
+ const query = `Check @${filePath}. This file contains settings.`;
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId: 414,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: `Check @${filePath}. This file contains settings.` },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${filePath}:\n` },
+ { text: fileContent },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ });
+
+ it('should handle comma termination with complex file paths', async () => {
+ const fileContent = 'Package info';
+ const filePath = await createTestFile(
+ path.join(testRootDir, 'package.json'),
+ fileContent,
+ );
+ const query = `Review @${filePath}, then check dependencies.`;
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId: 415,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: `Review @${filePath}, then check dependencies.` },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${filePath}:\n` },
+ { text: fileContent },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ });
+
+ it('should not terminate at period within file name', async () => {
+ const fileContent = 'Version info';
+ const filePath = await createTestFile(
+ path.join(testRootDir, 'version.1.2.3.txt'),
+ fileContent,
+ );
+ const query = `Check @${filePath} contains version information.`;
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId: 416,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: `Check @${filePath} contains version information.` },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${filePath}:\n` },
+ { text: fileContent },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ });
+
+ it('should handle end of string termination for period and comma', async () => {
+ const fileContent = 'End file content';
+ const filePath = await createTestFile(
+ path.join(testRootDir, 'end.txt'),
+ fileContent,
+ );
+ const query = `Show me @${filePath}.`;
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId: 417,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: `Show me @${filePath}.` },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${filePath}:\n` },
+ { text: fileContent },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ });
+
+ it('should handle files with special characters in names', async () => {
+ const fileContent = 'File with special chars content';
+ const filePath = await createTestFile(
+ path.join(testRootDir, 'file$with&special#chars.txt'),
+ fileContent,
+ );
+ const query = `Check @${filePath} for content.`;
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId: 418,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: `Check @${filePath} for content.` },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${filePath}:\n` },
+ { text: fileContent },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ });
+
+ it('should handle basic file names without special characters', async () => {
+ const fileContent = 'Basic file content';
+ const filePath = await createTestFile(
+ path.join(testRootDir, 'basicfile.txt'),
+ fileContent,
+ );
+ const query = `Check @${filePath} please.`;
+
+ const result = await handleAtCommand({
+ query,
+ config: mockConfig,
+ addItem: mockAddItem,
+ onDebugMessage: mockOnDebugMessage,
+ messageId: 421,
+ signal: abortController.signal,
+ });
+
+ expect(result).toEqual({
+ processedQuery: [
+ { text: `Check @${filePath} please.` },
+ { text: '\n--- Content from referenced files ---' },
+ { text: `\nContent from @${filePath}:\n` },
+ { text: fileContent },
+ { text: '\n--- End of content ---' },
+ ],
+ shouldProceed: true,
+ });
+ });
+ });
});