UNPKG

ts-comment-remover

Version:

TypeScript file compression tool that removes comments and unnecessary whitespace using AST

84 lines 3.78 kB
import { createSourceFile, ScriptTarget, createPrinter } from 'typescript'; import { readFile } from 'node:fs/promises'; import { getTypeScriptFiles, calculateStats, getRelativePath, pipe, } from './utils.js'; export const removeCommentsWithAST = (content) => { const sourceFile = createSourceFile('temp.ts', content, ScriptTarget.Latest, true); const printer = createPrinter({ removeComments: true, omitTrailingSemicolon: false, }); return printer.printFile(sourceFile); }; const compressionRules = [ [/\n\s*\n/g, '\n'], [/^\s+/gm, ''], [/\s+$/gm, ''], [/\s*([{}:;,=()[\]<>])\s*/g, '$1'], [/import\s*{/g, 'import{'], [/}\s*from/g, '}from'], [/export\s*{/g, 'export{'], [/export\s+type/g, 'export type'], [/export\s+const/g, 'export const'], [/export\s+enum/g, 'export enum'], [/export\s+interface/g, 'export interface'], [/type\s+(\w+)\s*=/g, 'type $1='], [/:\s*([A-Za-z])/g, ':$1'], ]; const applyRule = (content, [pattern, replacement]) => content.replace(pattern, replacement); const processLines = (content) => content .split('\n') .map(line => line.trim()) .filter(line => line.length > 0) .join(''); export const advancedCompress = (content) => { const afterRules = compressionRules.reduce(applyRule, content); return processLines(afterRules); }; export const createCompressionPipeline = (...functions) => functions.reduce((acc, fn) => pipe(acc, fn)); export const defaultCompressionPipeline = createCompressionPipeline(removeCommentsWithAST, advancedCompress); const readFileContent = (filePath) => async () => readFile(filePath, 'utf-8'); export const processFile = (filePath, compress = defaultCompressionPipeline) => async () => { const originalContent = await readFileContent(filePath)(); const compressedContent = compress(originalContent); const stats = calculateStats(originalContent.length, compressedContent.length); return { path: filePath, originalContent, compressedContent, stats, }; }; export const formatFileOutput = (file, baseDir, preserveStructure) => { const relativePath = getRelativePath(file.path, baseDir); return preserveStructure ? `\n/*=== ${relativePath} ===*/\n${file.compressedContent}\n` : `/*${relativePath}*/${file.compressedContent}`; }; export const aggregateStats = (files) => files.reduce((acc, file) => ({ totalOriginalSize: acc.totalOriginalSize + file.stats.originalSize, totalCompressedSize: acc.totalCompressedSize + file.stats.compressedSize, }), { totalOriginalSize: 0, totalCompressedSize: 0 }); export const generateOutput = (files, baseDir, preserveStructure) => files .map(file => formatFileOutput(file, baseDir, preserveStructure)) .join(preserveStructure ? '\n' : ''); export const compressTypeScriptFiles = (options) => async () => { const { targetDir, includePatterns, excludePatterns, preserveStructure = false, verbose = false, } = options; const files = await getTypeScriptFiles(targetDir, includePatterns, excludePatterns)(); if (files.length === 0) { throw new Error(`No TypeScript files found in ${targetDir}`); } if (verbose) { console.log(`Found ${files.length} TypeScript files`); } const processedFiles = await Promise.all(files.map(file => processFile(file)())); const output = generateOutput(processedFiles, targetDir, preserveStructure); const { totalOriginalSize } = aggregateStats(processedFiles); const totalCompressedSize = output.length; const totalStats = calculateStats(totalOriginalSize, totalCompressedSize); return { files: processedFiles, totalStats, output, }; }; //# sourceMappingURL=compressor.js.map