@amirdaraee/namewise 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/index.js +0 -0
- package/package.json +2 -2
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -82
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -61
- package/.github/workflows/auto-release.yml +0 -78
- package/.github/workflows/build.yml +0 -55
- package/.github/workflows/publish.yml +0 -134
- package/.github/workflows/test.yml +0 -47
- package/eng.traineddata +0 -0
- package/src/cli/commands.ts +0 -64
- package/src/cli/rename.ts +0 -171
- package/src/index.ts +0 -54
- package/src/parsers/excel-parser.ts +0 -66
- package/src/parsers/factory.ts +0 -38
- package/src/parsers/pdf-parser.ts +0 -99
- package/src/parsers/text-parser.ts +0 -43
- package/src/parsers/word-parser.ts +0 -50
- package/src/services/ai-factory.ts +0 -39
- package/src/services/claude-service.ts +0 -119
- package/src/services/file-renamer.ts +0 -141
- package/src/services/lmstudio-service.ts +0 -161
- package/src/services/ollama-service.ts +0 -191
- package/src/services/openai-service.ts +0 -117
- package/src/types/index.ts +0 -76
- package/src/types/pdf-extraction.d.ts +0 -7
- package/src/utils/ai-prompts.ts +0 -76
- package/src/utils/file-templates.ts +0 -275
- package/src/utils/naming-conventions.ts +0 -67
- package/src/utils/pdf-to-image.ts +0 -137
- package/tests/data/console-test-1.txt +0 -1
- package/tests/data/console-test-2.txt +0 -1
- package/tests/data/console-test-long-filename-for-display-testing.txt +0 -1
- package/tests/data/empty-file.txt +0 -0
- package/tests/data/failure.txt +0 -1
- package/tests/data/file1.txt +0 -1
- package/tests/data/file2.txt +0 -1
- package/tests/data/much-longer-filename-to-test-clearing.txt +0 -1
- package/tests/data/sample-markdown.md +0 -9
- package/tests/data/sample-pdf.pdf +0 -0
- package/tests/data/sample-text.txt +0 -25
- package/tests/data/short.txt +0 -1
- package/tests/data/single-file.txt +0 -1
- package/tests/data/success.txt +0 -1
- package/tests/data/this-is-a-very-long-filename-that-should-be-truncated-for-better-display-purposes.txt +0 -1
- package/tests/data/very-long-filename-that-should-be-cleared-properly.txt +0 -1
- package/tests/data/x.txt +0 -1
- package/tests/integration/ai-prompting.test.ts +0 -386
- package/tests/integration/end-to-end.test.ts +0 -209
- package/tests/integration/person-name-extraction.test.ts +0 -440
- package/tests/integration/workflow.test.ts +0 -336
- package/tests/mocks/mock-ai-service.ts +0 -58
- package/tests/unit/cli/commands.test.ts +0 -169
- package/tests/unit/parsers/factory.test.ts +0 -100
- package/tests/unit/parsers/pdf-parser.test.ts +0 -63
- package/tests/unit/parsers/text-parser.test.ts +0 -85
- package/tests/unit/services/ai-factory.test.ts +0 -85
- package/tests/unit/services/claude-service.test.ts +0 -188
- package/tests/unit/services/file-renamer.test.ts +0 -514
- package/tests/unit/services/lmstudio-service.test.ts +0 -326
- package/tests/unit/services/ollama-service.test.ts +0 -264
- package/tests/unit/services/openai-service.test.ts +0 -196
- package/tests/unit/utils/ai-prompts.test.ts +0 -213
- package/tests/unit/utils/file-templates.test.ts +0 -199
- package/tests/unit/utils/naming-conventions.test.ts +0 -88
- package/tests/unit/utils/pdf-to-image.test.ts +0 -127
- package/tsconfig.json +0 -20
- package/vitest.config.ts +0 -30
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { PDFParser } from '../../../src/parsers/pdf-parser.js';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
|
|
5
|
-
describe('PDFParser', () => {
|
|
6
|
-
let parser: PDFParser;
|
|
7
|
-
const testDataDir = path.join(process.cwd(), 'tests/data');
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
parser = new PDFParser();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe('supports()', () => {
|
|
14
|
-
it('should support .pdf files', () => {
|
|
15
|
-
expect(parser.supports('test.pdf')).toBe(true);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should not support other file types', () => {
|
|
19
|
-
expect(parser.supports('test.txt')).toBe(false);
|
|
20
|
-
expect(parser.supports('test.docx')).toBe(false);
|
|
21
|
-
expect(parser.supports('test.xlsx')).toBe(false);
|
|
22
|
-
expect(parser.supports('test.md')).toBe(false);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should be case insensitive', () => {
|
|
26
|
-
expect(parser.supports('test.PDF')).toBe(true);
|
|
27
|
-
expect(parser.supports('test.Pdf')).toBe(true);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('parse()', () => {
|
|
32
|
-
it('should parse PDF file content correctly', async () => {
|
|
33
|
-
const filePath = path.join(testDataDir, 'sample-pdf.pdf');
|
|
34
|
-
const result = await parser.parse(filePath);
|
|
35
|
-
|
|
36
|
-
expect(result.content.length).toBeGreaterThan(0);
|
|
37
|
-
expect(typeof result.content).toBe('string');
|
|
38
|
-
expect(result.metadata).toBeDefined();
|
|
39
|
-
// Check for some expected content from the test PDF
|
|
40
|
-
expect(result.content.toLowerCase()).toMatch(/trace|type|specialization|dynamic|languages/);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should throw error for non-existent files', async () => {
|
|
44
|
-
const filePath = path.join(testDataDir, 'non-existent.pdf');
|
|
45
|
-
|
|
46
|
-
await expect(parser.parse(filePath)).rejects.toThrow('Failed to parse PDF file');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should throw error for invalid PDF files', async () => {
|
|
50
|
-
const filePath = path.join(testDataDir, 'sample-text.txt'); // Not a PDF
|
|
51
|
-
|
|
52
|
-
await expect(parser.parse(filePath)).rejects.toThrow('Failed to parse PDF file');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should trim whitespace from extracted content', async () => {
|
|
56
|
-
const filePath = path.join(testDataDir, 'sample-pdf.pdf');
|
|
57
|
-
const result = await parser.parse(filePath);
|
|
58
|
-
|
|
59
|
-
expect(result.content).not.toMatch(/^\s/);
|
|
60
|
-
expect(result.content).not.toMatch(/\s$/);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
});
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { TextParser } from '../../../src/parsers/text-parser.js';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
|
|
5
|
-
describe('TextParser', () => {
|
|
6
|
-
let parser: TextParser;
|
|
7
|
-
const testDataDir = path.join(process.cwd(), 'tests/data');
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
parser = new TextParser();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe('supports()', () => {
|
|
14
|
-
it('should support .txt files', () => {
|
|
15
|
-
expect(parser.supports('test.txt')).toBe(true);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should support .md files', () => {
|
|
19
|
-
expect(parser.supports('test.md')).toBe(true);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should support .rtf files', () => {
|
|
23
|
-
expect(parser.supports('test.rtf')).toBe(true);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should not support other file types', () => {
|
|
27
|
-
expect(parser.supports('test.pdf')).toBe(false);
|
|
28
|
-
expect(parser.supports('test.docx')).toBe(false);
|
|
29
|
-
expect(parser.supports('test.xlsx')).toBe(false);
|
|
30
|
-
expect(parser.supports('test.png')).toBe(false);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should be case insensitive', () => {
|
|
34
|
-
expect(parser.supports('test.TXT')).toBe(true);
|
|
35
|
-
expect(parser.supports('test.MD')).toBe(true);
|
|
36
|
-
expect(parser.supports('test.RTF')).toBe(true);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
describe('parse()', () => {
|
|
41
|
-
it('should parse text file content correctly', async () => {
|
|
42
|
-
const filePath = path.join(testDataDir, 'sample-text.txt');
|
|
43
|
-
const result = await parser.parse(filePath);
|
|
44
|
-
|
|
45
|
-
expect(result.content).toContain('Project Requirements Document');
|
|
46
|
-
expect(result.content).toContain('customer management system');
|
|
47
|
-
expect(result.content).toContain('React.js');
|
|
48
|
-
expect(result.content.length).toBeGreaterThan(0);
|
|
49
|
-
expect(result.metadata).toBeDefined();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should parse markdown file content correctly', async () => {
|
|
53
|
-
const filePath = path.join(testDataDir, 'sample-markdown.md');
|
|
54
|
-
const result = await parser.parse(filePath);
|
|
55
|
-
|
|
56
|
-
expect(result.content).toContain('Meeting Notes');
|
|
57
|
-
expect(result.content).toContain('Action Items');
|
|
58
|
-
expect(result.content).toContain('John, Sarah, Mike');
|
|
59
|
-
expect(result.content.length).toBeGreaterThan(0);
|
|
60
|
-
expect(result.metadata).toBeDefined();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should handle empty files', async () => {
|
|
64
|
-
const filePath = path.join(testDataDir, 'empty-file.txt');
|
|
65
|
-
const result = await parser.parse(filePath);
|
|
66
|
-
|
|
67
|
-
expect(result.content).toBe('');
|
|
68
|
-
expect(result.metadata).toBeDefined();
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should throw error for non-existent files', async () => {
|
|
72
|
-
const filePath = path.join(testDataDir, 'non-existent.txt');
|
|
73
|
-
|
|
74
|
-
await expect(parser.parse(filePath)).rejects.toThrow('Failed to parse text file');
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should trim whitespace from content', async () => {
|
|
78
|
-
const filePath = path.join(testDataDir, 'sample-text.txt');
|
|
79
|
-
const result = await parser.parse(filePath);
|
|
80
|
-
|
|
81
|
-
expect(result.content).not.toMatch(/^\s/);
|
|
82
|
-
expect(result.content).not.toMatch(/\s$/);
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
});
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { AIServiceFactory } from '../../../src/services/ai-factory.js';
|
|
3
|
-
|
|
4
|
-
describe('AIServiceFactory', () => {
|
|
5
|
-
describe('create()', () => {
|
|
6
|
-
it('should create ClaudeService for claude provider', () => {
|
|
7
|
-
const service = AIServiceFactory.create('claude', 'test-api-key');
|
|
8
|
-
|
|
9
|
-
expect(service).toBeDefined();
|
|
10
|
-
expect(service.name).toBe('Claude');
|
|
11
|
-
expect(typeof service.generateFileName).toBe('function');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
it('should create OpenAIService for openai provider', () => {
|
|
15
|
-
const service = AIServiceFactory.create('openai', 'test-api-key');
|
|
16
|
-
|
|
17
|
-
expect(service).toBeDefined();
|
|
18
|
-
expect(service.name).toBe('OpenAI');
|
|
19
|
-
expect(typeof service.generateFileName).toBe('function');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('should create OllamaService for ollama provider', () => {
|
|
23
|
-
const service = AIServiceFactory.create('ollama');
|
|
24
|
-
|
|
25
|
-
expect(service).toBeDefined();
|
|
26
|
-
expect(service.name).toBe('Ollama');
|
|
27
|
-
expect(typeof service.generateFileName).toBe('function');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should create LMStudioService for lmstudio provider', () => {
|
|
31
|
-
const service = AIServiceFactory.create('lmstudio');
|
|
32
|
-
|
|
33
|
-
expect(service).toBeDefined();
|
|
34
|
-
expect(service.name).toBe('LMStudio');
|
|
35
|
-
expect(typeof service.generateFileName).toBe('function');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should create Ollama service with custom config', () => {
|
|
39
|
-
const service = AIServiceFactory.create('ollama', undefined, {
|
|
40
|
-
baseUrl: 'http://custom:8080',
|
|
41
|
-
model: 'custom-model'
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
expect(service).toBeDefined();
|
|
45
|
-
expect(service.name).toBe('Ollama');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('should create LMStudio service with custom config', () => {
|
|
49
|
-
const service = AIServiceFactory.create('lmstudio', undefined, {
|
|
50
|
-
baseUrl: 'http://custom:9000',
|
|
51
|
-
model: 'custom-model'
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
expect(service).toBeDefined();
|
|
55
|
-
expect(service.name).toBe('LMStudio');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should throw error for unsupported provider', () => {
|
|
59
|
-
expect(() => {
|
|
60
|
-
AIServiceFactory.create('unsupported' as any, 'test-api-key');
|
|
61
|
-
}).toThrow('Unsupported AI provider: unsupported');
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('should require API key for Claude provider', () => {
|
|
65
|
-
expect(() => {
|
|
66
|
-
AIServiceFactory.create('claude');
|
|
67
|
-
}).toThrow('API key is required for Claude provider');
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should require API key for OpenAI provider', () => {
|
|
71
|
-
expect(() => {
|
|
72
|
-
AIServiceFactory.create('openai');
|
|
73
|
-
}).toThrow('API key is required for OpenAI provider');
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('should pass API key to created cloud services', () => {
|
|
77
|
-
const claudeService = AIServiceFactory.create('claude', 'claude-key');
|
|
78
|
-
const openaiService = AIServiceFactory.create('openai', 'openai-key');
|
|
79
|
-
|
|
80
|
-
// Services should be created without throwing errors
|
|
81
|
-
expect(claudeService).toBeDefined();
|
|
82
|
-
expect(openaiService).toBeDefined();
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
});
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { ClaudeService } from '../../../src/services/claude-service.js';
|
|
3
|
-
|
|
4
|
-
// Mock the Anthropic SDK
|
|
5
|
-
vi.mock('@anthropic-ai/sdk', () => {
|
|
6
|
-
const MockAnthropic = vi.fn().mockImplementation(() => ({
|
|
7
|
-
messages: {
|
|
8
|
-
create: vi.fn()
|
|
9
|
-
}
|
|
10
|
-
}));
|
|
11
|
-
return {
|
|
12
|
-
default: MockAnthropic
|
|
13
|
-
};
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe('ClaudeService', () => {
|
|
17
|
-
let service: ClaudeService;
|
|
18
|
-
let mockClient: any;
|
|
19
|
-
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
service = new ClaudeService('test-api-key');
|
|
22
|
-
mockClient = (service as any).client;
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('Basic Properties', () => {
|
|
26
|
-
it('should have correct name', () => {
|
|
27
|
-
expect(service.name).toBe('Claude');
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should initialize with API key', () => {
|
|
31
|
-
expect(service).toBeDefined();
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe('generateFileName() with different naming conventions', () => {
|
|
36
|
-
const sampleContent = 'This is a project requirements document for Q4 2024 planning meeting.';
|
|
37
|
-
const originalName = 'document1.pdf';
|
|
38
|
-
|
|
39
|
-
beforeEach(() => {
|
|
40
|
-
mockClient.messages.create.mockResolvedValue({
|
|
41
|
-
content: [{ type: 'text', text: 'project requirements document q4 2024' }]
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should generate filename with kebab-case convention (default)', async () => {
|
|
46
|
-
const result = await service.generateFileName(sampleContent, originalName);
|
|
47
|
-
|
|
48
|
-
expect(mockClient.messages.create).toHaveBeenCalledWith(
|
|
49
|
-
expect.objectContaining({
|
|
50
|
-
model: 'claude-3-haiku-20240307',
|
|
51
|
-
messages: [expect.objectContaining({
|
|
52
|
-
role: 'user',
|
|
53
|
-
content: expect.stringContaining('Use lowercase with hyphens between words')
|
|
54
|
-
})]
|
|
55
|
-
})
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
expect(result).toBe('project-requirements-document-q4-2024');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should generate filename with snake_case convention', async () => {
|
|
62
|
-
const result = await service.generateFileName(sampleContent, originalName, 'snake_case');
|
|
63
|
-
|
|
64
|
-
expect(mockClient.messages.create).toHaveBeenCalledWith(
|
|
65
|
-
expect.objectContaining({
|
|
66
|
-
messages: [expect.objectContaining({
|
|
67
|
-
content: expect.stringContaining('Use lowercase with underscores between words')
|
|
68
|
-
})]
|
|
69
|
-
})
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
expect(result).toBe('project_requirements_document_q4_2024');
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
it('should generate filename with camelCase convention', async () => {
|
|
76
|
-
mockClient.messages.create.mockResolvedValue({
|
|
77
|
-
content: [{ type: 'text', text: 'project requirements document q4 2024' }]
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const result = await service.generateFileName(sampleContent, originalName, 'camelCase');
|
|
81
|
-
|
|
82
|
-
expect(mockClient.messages.create).toHaveBeenCalledWith(
|
|
83
|
-
expect.objectContaining({
|
|
84
|
-
messages: [expect.objectContaining({
|
|
85
|
-
content: expect.stringContaining('Use camelCase format starting with lowercase')
|
|
86
|
-
})]
|
|
87
|
-
})
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
expect(result).toBe('projectRequirementsDocumentQ42024');
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('should generate filename with PascalCase convention', async () => {
|
|
94
|
-
const result = await service.generateFileName(sampleContent, originalName, 'PascalCase');
|
|
95
|
-
|
|
96
|
-
expect(mockClient.messages.create).toHaveBeenCalledWith(
|
|
97
|
-
expect.objectContaining({
|
|
98
|
-
messages: [expect.objectContaining({
|
|
99
|
-
content: expect.stringContaining('Use PascalCase format starting with uppercase')
|
|
100
|
-
})]
|
|
101
|
-
})
|
|
102
|
-
);
|
|
103
|
-
|
|
104
|
-
expect(result).toBe('ProjectRequirementsDocumentQ42024');
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it('should include original filename and content in prompt', async () => {
|
|
108
|
-
await service.generateFileName(sampleContent, originalName, 'kebab-case');
|
|
109
|
-
|
|
110
|
-
const call = mockClient.messages.create.mock.calls[0][0];
|
|
111
|
-
expect(call.messages[0].content).toContain(sampleContent.substring(0, 2000));
|
|
112
|
-
expect(call.messages[0].content).toContain('Document content (first 2000 characters)');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('should truncate long content to 2000 characters', async () => {
|
|
116
|
-
const longContent = 'a'.repeat(3000);
|
|
117
|
-
await service.generateFileName(longContent, originalName);
|
|
118
|
-
|
|
119
|
-
const call = mockClient.messages.create.mock.calls[0][0];
|
|
120
|
-
const contentInPrompt = call.messages[0].content;
|
|
121
|
-
// Should only contain first 2000 characters
|
|
122
|
-
expect(contentInPrompt).toContain('a'.repeat(2000));
|
|
123
|
-
expect(contentInPrompt).not.toContain('a'.repeat(2001));
|
|
124
|
-
});
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
describe('Error Handling', () => {
|
|
128
|
-
it('should handle API errors gracefully', async () => {
|
|
129
|
-
mockClient.messages.create.mockRejectedValue(new Error('API Error'));
|
|
130
|
-
|
|
131
|
-
await expect(service.generateFileName('content', 'file.txt')).rejects.toThrow(
|
|
132
|
-
'Failed to generate filename with Claude: API Error'
|
|
133
|
-
);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('should handle non-text response content', async () => {
|
|
137
|
-
mockClient.messages.create.mockResolvedValue({
|
|
138
|
-
content: [{ type: 'image', text: null }]
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const result = await service.generateFileName('content', 'file.txt');
|
|
142
|
-
expect(result).toBe('untitled-document');
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should handle empty response', async () => {
|
|
146
|
-
mockClient.messages.create.mockResolvedValue({
|
|
147
|
-
content: [{ type: 'text', text: ' ' }]
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
const result = await service.generateFileName('content', 'file.txt');
|
|
151
|
-
expect(result).toBe('untitled-document');
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
describe('Filename Sanitization', () => {
|
|
156
|
-
beforeEach(() => {
|
|
157
|
-
mockClient.messages.create.mockResolvedValue({
|
|
158
|
-
content: [{ type: 'text', text: 'Test File@#$ Name.pdf' }]
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
it('should remove file extensions from AI suggestions', async () => {
|
|
163
|
-
const result = await service.generateFileName('content', 'original.txt', 'kebab-case');
|
|
164
|
-
expect(result).toBe('test-file-name');
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it('should handle very long filenames', async () => {
|
|
168
|
-
mockClient.messages.create.mockResolvedValue({
|
|
169
|
-
content: [{ type: 'text', text: 'a'.repeat(150) }]
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
const result = await service.generateFileName('content', 'file.txt', 'kebab-case');
|
|
173
|
-
expect(result.length).toBeLessThanOrEqual(100);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('should preserve naming convention when truncating', async () => {
|
|
177
|
-
mockClient.messages.create.mockResolvedValue({
|
|
178
|
-
content: [{ type: 'text', text: 'very long filename that should be truncated properly' }]
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
const kebabResult = await service.generateFileName('content', 'file.txt', 'kebab-case');
|
|
182
|
-
expect(kebabResult).not.toMatch(/-$/); // Should not end with hyphen
|
|
183
|
-
|
|
184
|
-
const snakeResult = await service.generateFileName('content', 'file.txt', 'snake_case');
|
|
185
|
-
expect(snakeResult).not.toMatch(/_$/); // Should not end with underscore
|
|
186
|
-
});
|
|
187
|
-
});
|
|
188
|
-
});
|