@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.
Files changed (68) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/index.js +0 -0
  3. package/package.json +2 -2
  4. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -82
  5. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -61
  6. package/.github/workflows/auto-release.yml +0 -78
  7. package/.github/workflows/build.yml +0 -55
  8. package/.github/workflows/publish.yml +0 -134
  9. package/.github/workflows/test.yml +0 -47
  10. package/eng.traineddata +0 -0
  11. package/src/cli/commands.ts +0 -64
  12. package/src/cli/rename.ts +0 -171
  13. package/src/index.ts +0 -54
  14. package/src/parsers/excel-parser.ts +0 -66
  15. package/src/parsers/factory.ts +0 -38
  16. package/src/parsers/pdf-parser.ts +0 -99
  17. package/src/parsers/text-parser.ts +0 -43
  18. package/src/parsers/word-parser.ts +0 -50
  19. package/src/services/ai-factory.ts +0 -39
  20. package/src/services/claude-service.ts +0 -119
  21. package/src/services/file-renamer.ts +0 -141
  22. package/src/services/lmstudio-service.ts +0 -161
  23. package/src/services/ollama-service.ts +0 -191
  24. package/src/services/openai-service.ts +0 -117
  25. package/src/types/index.ts +0 -76
  26. package/src/types/pdf-extraction.d.ts +0 -7
  27. package/src/utils/ai-prompts.ts +0 -76
  28. package/src/utils/file-templates.ts +0 -275
  29. package/src/utils/naming-conventions.ts +0 -67
  30. package/src/utils/pdf-to-image.ts +0 -137
  31. package/tests/data/console-test-1.txt +0 -1
  32. package/tests/data/console-test-2.txt +0 -1
  33. package/tests/data/console-test-long-filename-for-display-testing.txt +0 -1
  34. package/tests/data/empty-file.txt +0 -0
  35. package/tests/data/failure.txt +0 -1
  36. package/tests/data/file1.txt +0 -1
  37. package/tests/data/file2.txt +0 -1
  38. package/tests/data/much-longer-filename-to-test-clearing.txt +0 -1
  39. package/tests/data/sample-markdown.md +0 -9
  40. package/tests/data/sample-pdf.pdf +0 -0
  41. package/tests/data/sample-text.txt +0 -25
  42. package/tests/data/short.txt +0 -1
  43. package/tests/data/single-file.txt +0 -1
  44. package/tests/data/success.txt +0 -1
  45. package/tests/data/this-is-a-very-long-filename-that-should-be-truncated-for-better-display-purposes.txt +0 -1
  46. package/tests/data/very-long-filename-that-should-be-cleared-properly.txt +0 -1
  47. package/tests/data/x.txt +0 -1
  48. package/tests/integration/ai-prompting.test.ts +0 -386
  49. package/tests/integration/end-to-end.test.ts +0 -209
  50. package/tests/integration/person-name-extraction.test.ts +0 -440
  51. package/tests/integration/workflow.test.ts +0 -336
  52. package/tests/mocks/mock-ai-service.ts +0 -58
  53. package/tests/unit/cli/commands.test.ts +0 -169
  54. package/tests/unit/parsers/factory.test.ts +0 -100
  55. package/tests/unit/parsers/pdf-parser.test.ts +0 -63
  56. package/tests/unit/parsers/text-parser.test.ts +0 -85
  57. package/tests/unit/services/ai-factory.test.ts +0 -85
  58. package/tests/unit/services/claude-service.test.ts +0 -188
  59. package/tests/unit/services/file-renamer.test.ts +0 -514
  60. package/tests/unit/services/lmstudio-service.test.ts +0 -326
  61. package/tests/unit/services/ollama-service.test.ts +0 -264
  62. package/tests/unit/services/openai-service.test.ts +0 -196
  63. package/tests/unit/utils/ai-prompts.test.ts +0 -213
  64. package/tests/unit/utils/file-templates.test.ts +0 -199
  65. package/tests/unit/utils/naming-conventions.test.ts +0 -88
  66. package/tests/unit/utils/pdf-to-image.test.ts +0 -127
  67. package/tsconfig.json +0 -20
  68. 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
- });