UNPKG

ts-minifer

Version:

Advanced TypeScript code minification and compression tool

189 lines 8.59 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.TypeScriptCompressor = void 0; const ts = __importStar(require("typescript")); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const glob = __importStar(require("glob")); const source_map_1 = require("source-map"); const types_1 = require("./types"); const logger_1 = require("./logger"); class TypeScriptCompressor { constructor(verbose = false) { this.logger = new logger_1.Logger(verbose); } compressFiles(inputPaths, options) { this.logger.info(`Starting compression with level: ${options.level}`); // Resolve input files using glob const inputFiles = this.resolveInputFiles(inputPaths, options.excludePatterns); this.logger.info(`Found ${inputFiles.length} files to compress`); // Parse and transform TypeScript files const transformedFiles = inputFiles.map((file, index) => this.compressFile(file, options, index, inputFiles.length)); // Combine or output files based on configuration const outputResult = this.generateOutput(transformedFiles, options); this.logger.info('Compression completed'); return outputResult; } resolveInputFiles(inputPaths, excludePatterns) { let files = []; inputPaths.forEach(inputPath => { const stats = fs.statSync(inputPath); if (stats.isDirectory()) { const dirFiles = glob.sync(`${inputPath}/**/*.ts`, { ignore: excludePatterns || [] }); files = [...files, ...dirFiles]; } else if (stats.isFile() && path.extname(inputPath) === '.ts') { files.push(inputPath); } }); return files; } compressFile(filePath, options, currentIndex, totalFiles) { this.logger.progress(currentIndex + 1, totalFiles, `Compressing ${path.basename(filePath)}`); const sourceCode = fs.readFileSync(filePath, 'utf-8'); const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true); // Create source map generator const sourceMapGenerator = new source_map_1.SourceMapGenerator({ file: path.basename(filePath) }); // Transform based on compression level const transformedContent = this.transformSourceFile(sourceFile, options, sourceMapGenerator); return { originalContent: sourceCode, transformedContent, sourceMap: options.generateSourceMaps ? sourceMapGenerator.toString() : undefined, originalPath: filePath }; } transformSourceFile(sourceFile, options, sourceMapGenerator) { const transformer = this.createTransformer(options, sourceMapGenerator); const result = ts.transform(sourceFile, [transformer]); const printer = ts.createPrinter({ removeComments: options.level !== types_1.CompressionLevel.NONE }); return printer.printFile(result.transformed[0]); } createTransformer(options, sourceMapGenerator) { return (context) => { return (sourceFile) => { const visitor = (node) => { // Implement compression logic based on compression level switch (options.level) { case types_1.CompressionLevel.MINIMAL: // Remove comments, minimal transformations return this.minimalCompression(node, context); case types_1.CompressionLevel.AGGRESSIVE: // Aggressive name shortening, more aggressive removals return this.aggressiveCompression(node, context); default: return ts.visitEachChild(node, visitor, context); } }; return ts.visitNode(sourceFile, visitor); }; }; } minimalCompression(node, context) { if (ts.isJSDocCommentContainingNode(node) || node.kind === ts.SyntaxKind.JSDoc) { return node; } return ts.visitEachChild(node, child => this.minimalCompression(child, context), context); } aggressiveCompression(node, context) { if (ts.isIdentifier(node) && ts.isVariableDeclaration(node.parent)) { // Implement variable name shortening logic return ts.factory.createIdentifier(this.shortenName(node.text)); } return ts.visitEachChild(node, child => this.aggressiveCompression(child, context), context); } shortenName(name) { // Simple implementation - could be made more sophisticated return `_${name.length}`; } generateOutput(transformedFiles, options) { const outputFiles = []; const sourceMapFiles = []; const totalOriginalSize = transformedFiles.reduce((sum, file) => sum + file.originalContent.length, 0); const totalCompressedSize = transformedFiles.reduce((sum, file) => sum + file.transformedContent.length, 0); const outputDir = path.join(process.cwd(), 'dist'); fs.mkdirSync(outputDir, { recursive: true }); if (options.outputFormat === 'single') { // Combine all files into one const combinedContent = transformedFiles .map(file => file.transformedContent) .join('\n'); const outputPath = path.join(outputDir, 'compressed.ts'); fs.writeFileSync(outputPath, combinedContent); outputFiles.push(outputPath); if (options.generateSourceMaps) { const sourceMapPath = `${outputPath}.map`; fs.writeFileSync(sourceMapPath, transformedFiles .map(file => file.sourceMap) .filter(Boolean) .join('\n')); sourceMapFiles.push(sourceMapPath); } } else { // Output multiple files with original names transformedFiles.forEach((file, index) => { const outputPath = path.join(outputDir, path.basename(file.originalPath || `compressed_${index}.ts`)); fs.writeFileSync(outputPath, file.transformedContent); outputFiles.push(outputPath); if (options.generateSourceMaps && file.sourceMap) { const sourceMapPath = `${outputPath}.map`; fs.writeFileSync(sourceMapPath, file.sourceMap); sourceMapFiles.push(sourceMapPath); } }); } return { outputFiles, sourceMapFiles: options.generateSourceMaps ? sourceMapFiles : undefined, stats: { originalSize: totalOriginalSize, compressedSize: totalCompressedSize, compressionRatio: 1 - (totalCompressedSize / totalOriginalSize) } }; } } exports.TypeScriptCompressor = TypeScriptCompressor; //# sourceMappingURL=compressor.js.map