Skip to main content
Glama
minifier.test.ts13.7 kB
/// <reference types="vitest/globals" /> import { describe, it, expect, vi, beforeEach } from 'vitest'; import { minifyContent, isJavaScriptFileV2, isIndentationSensitiveV2, MINIFY_CONFIG, } from '../src/minifier.js'; // Mock terser const mockMinify = vi.hoisted(() => vi.fn()); vi.mock('terser', () => ({ minify: mockMinify, })); describe('MinifierV2', () => { beforeEach(() => { mockMinify.mockReset(); }); describe('Configuration', () => { it('should have proper comment patterns defined', () => { expect(MINIFY_CONFIG.commentPatterns['c-style']).toHaveLength(3); // Block, line, and inline comments expect(MINIFY_CONFIG.commentPatterns.hash).toHaveLength(2); // Start of line and inline hash comments expect(MINIFY_CONFIG.commentPatterns.html).toHaveLength(1); }); it('should map file extensions to correct strategies', () => { expect(MINIFY_CONFIG.fileTypes.js!.strategy).toBe('terser'); expect(MINIFY_CONFIG.fileTypes.py!.strategy).toBe('conservative'); expect(MINIFY_CONFIG.fileTypes.html!.strategy).toBe('aggressive'); expect(MINIFY_CONFIG.fileTypes.json!.strategy).toBe('json'); }); }); describe('Utility Functions', () => { describe('isJavaScriptFileV2', () => { it('should identify JavaScript files correctly', () => { expect(isJavaScriptFileV2('file.js')).toBe(true); expect(isJavaScriptFileV2('file.ts')).toBe(true); expect(isJavaScriptFileV2('file.jsx')).toBe(true); expect(isJavaScriptFileV2('file.tsx')).toBe(true); expect(isJavaScriptFileV2('file.mjs')).toBe(true); expect(isJavaScriptFileV2('file.cjs')).toBe(true); expect(isJavaScriptFileV2('file.py')).toBe(false); expect(isJavaScriptFileV2('file.html')).toBe(false); }); }); describe('isIndentationSensitiveV2', () => { it('should identify indentation-sensitive languages', () => { expect(isIndentationSensitiveV2('file.py')).toBe(true); expect(isIndentationSensitiveV2('file.yaml')).toBe(true); expect(isIndentationSensitiveV2('file.yml')).toBe(true); expect(isIndentationSensitiveV2('file.coffee')).toBe(true); expect(isIndentationSensitiveV2('file.haml')).toBe(true); expect(isIndentationSensitiveV2('file.sass')).toBe(true); expect(isIndentationSensitiveV2('file.js')).toBe(false); expect(isIndentationSensitiveV2('file.html')).toBe(false); expect(isIndentationSensitiveV2('file.css')).toBe(false); }); }); }); describe('Terser Strategy', () => { it('should use terser for JavaScript files', async () => { const jsCode = 'function test() { return true; }'; mockMinify.mockResolvedValue({ code: 'function test(){return true;}', }); const result = await minifyContent(jsCode, 'test.js'); expect(result.type).toBe('terser'); expect(result.failed).toBe(false); expect(result.content).toBe('function test(){return true;}'); expect(mockMinify).toHaveBeenCalledWith(jsCode, expect.any(Object)); }); it('should handle terser failures gracefully', async () => { const jsCode = 'invalid js {{{'; mockMinify.mockRejectedValue(new Error('Parse error')); const result = await minifyContent(jsCode, 'test.js'); expect(result.type).toBe('failed'); expect(result.failed).toBe(true); expect(result.content).toBe(jsCode); // Returns original content }); }); describe('Conservative Strategy (Indentation-Sensitive)', () => { it('should preserve Python indentation structure', async () => { const pythonCode = `def hello(): # This is a comment if True: print("Hello") # Another comment return True # Top level comment class MyClass: pass`; const result = await minifyContent(pythonCode, 'test.py'); expect(result.type).toBe('conservative'); expect(result.failed).toBe(false); // Should remove comments but preserve indentation and line structure expect(result.content).not.toContain('# This is a comment'); expect(result.content).not.toContain('# Another comment'); expect(result.content).not.toContain('# Top level comment'); // Should preserve indentation expect(result.content).toContain('def hello():'); expect(result.content).toContain(' if True:'); expect(result.content).toContain(' print("Hello")'); expect(result.content).toContain(' return True'); }); it('should handle YAML conservatively', async () => { const yamlCode = `# YAML configuration version: '3.8' services: web: # Web service config image: nginx:latest ports: - "80:80" # Database service db: image: postgres:13`; const result = await minifyContent(yamlCode, 'docker-compose.yml'); expect(result.type).toBe('conservative'); expect(result.failed).toBe(false); // Should remove comments but preserve YAML structure expect(result.content).not.toContain('# YAML configuration'); expect(result.content).not.toContain('# Web service config'); expect(result.content).not.toContain('# Database service'); // Should preserve YAML indentation expect(result.content).toContain("version: '3.8'"); expect(result.content).toContain('services:'); expect(result.content).toContain(' web:'); expect(result.content).toContain(' image: nginx:latest'); }); }); describe('Aggressive Strategy', () => { it('should aggressively minify HTML', async () => { const htmlCode = `<!DOCTYPE html> <!-- This is a comment --> <html> <head> <title>Test</title> </head> <body> <h1>Hello World</h1> <p>This is a paragraph</p> </body> </html>`; const result = await minifyContent(htmlCode, 'test.html'); expect(result.type).toBe('aggressive'); expect(result.failed).toBe(false); // Should remove comments and excessive whitespace expect(result.content).not.toContain('<!-- This is a comment -->'); expect(result.content).toBe( '<!DOCTYPE html><html><head><title>Test</title></head><body><h1>Hello World</h1><p>This is a paragraph</p></body></html>' ); }); it('should aggressively minify CSS', async () => { const cssCode = `/* Main styles */ .container { /* Container styles */ padding: 20px; margin: 0 auto; max-width: 1200px; } .button { background-color: blue; color: white; /* Button styles */ border: none; }`; const result = await minifyContent(cssCode, 'styles.css'); expect(result.type).toBe('aggressive'); expect(result.failed).toBe(false); // Should remove comments and excessive whitespace expect(result.content).not.toContain('/* Main styles */'); expect(result.content).not.toContain('/* Container styles */'); expect(result.content).not.toContain('/* Button styles */'); // clean-css produces superior minification: optimizes colors, removes trailing semicolons expect(result.content).toContain( '.container{padding:20px;margin:0 auto;max-width:1200px}' ); expect(result.content).toContain( '.button{background-color:#00f;color:#fff;border:none}' ); }); it('should handle Go code aggressively', async () => { const goCode = `package main import "fmt" // Main function func main() { /* * Print hello world */ fmt.Println("Hello, World!") // Another comment var x = 42 }`; const result = await minifyContent(goCode, 'main.go'); expect(result.type).toBe('aggressive'); expect(result.failed).toBe(false); // Should remove both types of comments expect(result.content).not.toContain('// Main function'); expect(result.content).not.toContain('/* * Print hello world */'); expect(result.content).not.toContain('// Another comment'); // Should compress whitespace expect(result.content).toContain('package main import "fmt" func main()'); }); }); describe('JSON Strategy', () => { it('should minify valid JSON', async () => { const jsonCode = `{ "name": "test-package", "version": "1.0.0", "dependencies": { "lodash": "^4.17.21" } }`; const result = await minifyContent(jsonCode, 'package.json'); expect(result.type).toBe('json'); expect(result.failed).toBe(false); expect(result.content).toBe( '{"name":"test-package","version":"1.0.0","dependencies":{"lodash":"^4.17.21"}}' ); }); it('should fallback to basic minification for invalid JSON', async () => { const invalidJson = `{ "name": "test", // This comment makes it invalid JSON "version": "1.0.0" }`; const result = await minifyContent(invalidJson, 'invalid.json'); expect(result.type).toBe('json'); expect(result.failed).toBe(false); // Should fallback to basic whitespace removal expect(result.content).toContain('"name": "test",'); }); }); describe('Multi-language Comment Support', () => { it('should handle PHP with multiple comment types', async () => { const phpCode = `<?php // Single line comment /* Multi-line comment */ # Hash comment function test() { return true; // Inline comment } ?>`; const result = await minifyContent(phpCode, 'test.php'); expect(result.type).toBe('aggressive'); expect(result.failed).toBe(false); // Should remove all comment types expect(result.content).not.toContain('// Single line comment'); expect(result.content).not.toContain('/* Multi-line comment */'); expect(result.content).not.toContain('# Hash comment'); expect(result.content).not.toContain('// Inline comment'); }); it('should handle SQL comments', async () => { const sqlCode = `-- This is a SQL comment SELECT * FROM users /* Multi-line SQL comment spanning multiple lines */ WHERE active = 1; -- Another comment`; const result = await minifyContent(sqlCode, 'query.sql'); expect(result.type).toBe('aggressive'); expect(result.failed).toBe(false); // Should remove both types of SQL comments expect(result.content).not.toContain('-- This is a SQL comment'); expect(result.content).not.toContain('/* Multi-line SQL comment'); expect(result.content).not.toContain('-- Another comment'); // Should preserve SQL structure expect(result.content).toContain('SELECT * FROM users WHERE active = 1;'); }); }); describe('Unknown File Types', () => { it('should fallback to general strategy for unknown extensions', async () => { const unknownContent = `# Some config file setting1=value1 setting2=value2 # Another section setting3=value3 `; const result = await minifyContent(unknownContent, 'unknown.xyz'); expect(result.type).toBe('general'); expect(result.failed).toBe(false); // Should clean up general whitespace issues expect(result.content).toContain('setting1=value1'); expect(result.content).toContain('setting2=value2'); expect(result.content).toContain('setting3=value3'); // Should remove excessive whitespace expect(result.content).not.toMatch(/[ \t]+$/m); // No trailing whitespace expect(result.content).not.toMatch(/\n\n\n+/); // No triple newlines }); it('should treat indentation-sensitive filenames conservatively (no extension)', async () => { const makefile = `# Simple Makefile build: @echo "Building" test: @echo "Testing"`; const result = await minifyContent(makefile, 'Makefile'); expect(result.type).toBe('conservative'); expect(result.failed).toBe(false); // Tabs should be preserved for Makefile recipes expect(result.content).toContain('\t@echo "Building"'); expect(result.content).toContain('\t@echo "Testing"'); }); }); describe('Edge Cases', () => { it('should handle empty content', async () => { const result = await minifyContent('', 'empty.js'); expect(result.content).toBe(''); expect(result.failed).toBe(false); }); it('should handle content with only whitespace', async () => { const result = await minifyContent(' \n\n\t \n ', 'whitespace.txt'); expect(result.content).toBe(''); expect(result.failed).toBe(false); }); it('should handle content with only comments', async () => { const result = await minifyContent( '# Comment 1\n# Comment 2\n# Comment 3', 'comments.sh' ); expect(result.content).toBe(''); expect(result.failed).toBe(false); }); }); describe('Size Limit Tests', () => { it('should reject content larger than 1MB', async () => { // Create content just over 1MB (1MB + 100 bytes) const oneMB = 1024 * 1024; const largeContent = 'x'.repeat(oneMB + 100); const result = await minifyContent(largeContent, 'large.js'); expect(result.failed).toBe(true); expect(result.type).toBe('failed'); expect(result.content).toBe(largeContent); // Should return original content }); it('should accept content exactly at 1MB limit', async () => { // Create content exactly 1MB const oneMB = 1024 * 1024; const limitContent = 'a'.repeat(oneMB); const result = await minifyContent(limitContent, 'limit.txt'); expect(result.failed).toBe(false); expect(result.type).toBe('general'); // txt files use general strategy expect(result.content.length).toBeLessThanOrEqual(limitContent.length); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bgauryy/octocode-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server