UNPKG

gitcleancommit

Version:

A beautiful CLI tool for creating clean, conventional git commits with advanced spell checking and automatic integration

543 lines 13.1 kB
import Typo from "typo-js"; export class GitCleanSpellChecker { static async initialize() { if (this.isInitialized) return; try { // Initialize with built-in English dictionary // typo-js comes with en_US dictionary built-in this.dictionary = new Typo("en_US"); this.isInitialized = true; console.log("✅ Spell checker initialized successfully"); } catch (error) { console.warn("⚠️ Warning: Could not initialize full dictionary. Using fallback mode."); this.isInitialized = true; // Continue with typo detection only } } static async checkSpelling(message) { await this.initialize(); const results = []; const words = this.extractWords(message); for (const { word, start, end } of words) { const lowerWord = word.toLowerCase(); // Skip very short words (1-2 chars), numbers, and single letters if (word.length <= 2 || /^\d+$/.test(word) || /^[a-z]$/i.test(word)) { continue; } // Skip technical terms and common abbreviations if (this.TECHNICAL_WORDS.has(lowerWord)) { continue; } // Check if it's a common typo first (highest priority) if (this.COMMON_TYPOS.has(lowerWord)) { results.push({ word, suggestions: [this.COMMON_TYPOS.get(lowerWord)], isCorrect: false, position: { start, end }, }); continue; } // Use typo-js dictionary if available if (this.dictionary) { const isCorrect = this.dictionary.check(word); if (!isCorrect) { const suggestions = this.dictionary.suggest(word).slice(0, 3); results.push({ word, suggestions: suggestions || [], isCorrect: false, position: { start, end }, }); } } } return results; } static extractWords(text) { const words = []; const wordRegex = /\b[a-zA-Z]+\b/g; let match; while ((match = wordRegex.exec(text)) !== null) { words.push({ word: match[0], start: match.index, end: match.index + match[0].length, }); } return words; } static createSquigglyUnderline(text, errors) { if (errors.length === 0) return text; let result = text; // Sort errors by position (descending) to avoid index shifting issues const sortedErrors = errors.sort((a, b) => b.position.start - a.position.start); for (const error of sortedErrors) { const { word, position } = error; const beforeWord = result.substring(0, position.start); const afterWord = result.substring(position.end); // Create red text with underline using ANSI codes const squigglyWord = `\x1b[31m\x1b[4m${word}\x1b[0m`; result = beforeWord + squigglyWord + afterWord; } return result; } static getAutoCorrection(word) { const lowerWord = word.toLowerCase(); // Check common typos first (fastest and most accurate) if (this.COMMON_TYPOS.has(lowerWord)) { return this.COMMON_TYPOS.get(lowerWord); } // Use typo-js dictionary if available if (this.dictionary) { const suggestions = this.dictionary.suggest(word); return suggestions && suggestions.length > 0 ? suggestions[0] : null; } return null; } static async autoCorrectText(text) { const errors = await this.checkSpelling(text); let correctedText = text; // Sort errors by position (descending) to avoid index shifting issues const sortedErrors = errors.sort((a, b) => b.position.start - a.position.start); for (const error of sortedErrors) { if (error.suggestions.length > 0) { const { position } = error; const beforeWord = correctedText.substring(0, position.start); const afterWord = correctedText.substring(position.end); correctedText = beforeWord + error.suggestions[0] + afterWord; } } return correctedText; } static getSpellCheckStats() { return { isInitialized: this.isInitialized, hasDictionary: this.dictionary !== null, technicalWordsCount: this.TECHNICAL_WORDS.size, typoRulesCount: this.COMMON_TYPOS.size, }; } } GitCleanSpellChecker.dictionary = null; GitCleanSpellChecker.isInitialized = false; GitCleanSpellChecker.TECHNICAL_WORDS = new Set([ // Programming languages & frameworks "api", "cli", "ui", "ux", "dom", "json", "xml", "html", "css", "js", "ts", "npm", "yarn", "pnpm", "webpack", "vite", "rollup", "babel", "eslint", "prettier", "typescript", "javascript", "node", "nodejs", "react", "vue", "angular", "svelte", "scss", "sass", "less", "tailwind", "bootstrap", "css3", "html5", "jsx", "tsx", // Git & Version Control "git", "github", "gitlab", "bitbucket", "commit", "push", "pull", "merge", "rebase", "checkout", "branch", "tag", "stash", "clone", "fork", "upstream", "origin", "remote", "gitignore", "gitconfig", "gitflow", "pr", "mr", "repo", "repository", "submodule", "workflow", "actions", "hooks", "changelog", "semver", // DevOps & Cloud "docker", "kubernetes", "k8s", "aws", "azure", "gcp", "vercel", "netlify", "heroku", "ci", "cd", "devops", "oauth", "jwt", "cors", "csrf", "ssl", "tls", "nginx", "apache", "kubernetes", "helm", "terraform", "ansible", "jenkins", // Protocols & Networks "http", "https", "tcp", "udp", "ssh", "ftp", "smtp", "pop3", "imap", "dns", "url", "uri", "uuid", "regex", "websocket", "graphql", "rest", "soap", "grpc", // Databases "sql", "nosql", "mongodb", "mysql", "postgresql", "sqlite", "redis", "elasticsearch", "firebase", "supabase", "prisma", "orm", "crud", "db", // Architecture & Patterns "microservices", "monolith", "serverless", "jamstack", "spa", "ssr", "ssg", "pwa", "mvc", "mvp", "mvvm", "api", "sdk", "cli", "gui", "microservice", // Tech concepts "blockchain", "cryptocurrency", "ai", "ml", "nlp", "iot", "ar", "vr", "refactor", "refactoring", "optimization", "minification", "bundling", "transpilation", "polyfill", "shim", "middleware", "plugin", "addon", // File formats & configs "md", "txt", "log", "yml", "yaml", "toml", "ini", "cfg", "conf", "env", "dockerfile", "makefile", "rakefile", "gemfile", "procfile", "lockfile", // Development terms "config", "env", "prod", "dev", "staging", "localhost", "async", "await", "promise", "callback", "event", "listener", "handler", "component", "module", "package", "library", "framework", "boilerplate", "template", "scaffold", "generator", "linter", "formatter", "transpiler", "compiler", // Common abbreviations "app", "db", "auth", "util", "utils", "lib", "libs", "src", "dist", "build", "bin", "test", "spec", "mock", "stub", "tmp", "temp", "www", "admin", "user", "users", "client", "server", "backend", "frontend", "fullstack", "deployment", "infrastructure", "monitoring", "logging", "analytics", "metrics", "dashboard", "sidebar", "navbar", "footer", "header", "modal", "popup", "tooltip", "dropdown", "carousel", "accordion", "tabs", "pagination", "breadcrumb", "stepper", "wizard", // Package managers & tools "homebrew", "chocolatey", "apt", "yum", "pacman", "conda", "pip", "gem", "composer", "maven", "gradle", "nuget", "cargo", "go", // Testing "jest", "mocha", "chai", "cypress", "selenium", "puppeteer", "playwright", "vitest", "karma", "jasmine", "enzyme", "testing", "unittest", "e2e", ]); GitCleanSpellChecker.COMMON_TYPOS = new Map([ // Basic typos ["teh", "the"], ["hte", "the"], ["adn", "and"], ["nad", "and"], ["recieve", "receive"], ["recieved", "received"], ["recieving", "receiving"], ["seperate", "separate"], ["seperated", "separated"], ["seperately", "separately"], ["definately", "definitely"], ["occured", "occurred"], ["occuring", "occurring"], ["perfomance", "performance"], ["perfom", "perform"], ["sucessful", "successful"], ["sucessfully", "successfully"], ["acording", "according"], ["adress", "address"], ["begining", "beginning"], ["beleive", "believe"], ["buiness", "business"], ["diference", "difference"], ["enviroment", "environment"], ["existance", "existence"], ["finaly", "finally"], ["foriegn", "foreign"], ["goverment", "government"], ["gaurd", "guard"], ["happend", "happened"], ["immediatly", "immediately"], ["independant", "independent"], ["intrested", "interested"], ["libary", "library"], ["maintainance", "maintenance"], ["occassion", "occasion"], ["prefered", "preferred"], ["reccomend", "recommend"], ["thier", "their"], ["truely", "truly"], ["usualy", "usually"], ["wierd", "weird"], ["calender", "calendar"], ["accomodate", "accommodate"], ["achive", "achieve"], ["achived", "achieved"], // Programming-specific typos ["commited", "committed"], ["commiting", "committing"], ["committ", "commit"], ["implmentation", "implementation"], ["implimentation", "implementation"], ["documention", "documentation"], ["confguration", "configuration"], ["configuraton", "configuration"], ["functionallity", "functionality"], ["conditon", "condition"], ["lenght", "length"], ["widht", "width"], ["heigth", "height"], ["compatability", "compatibility"], ["dependancy", "dependency"], ["optmize", "optimize"], ["optmized", "optimized"], ["optmization", "optimization"], ["intialize", "initialize"], ["intializing", "initializing"], ["intial", "initial"], ["retrun", "return"], ["reutrn", "return"], ["funciton", "function"], ["fucntion", "function"], ["fucntions", "functions"], ["valriable", "variable"], ["varaible", "variable"], ["varibles", "variables"], ["methdo", "method"], ["methos", "method"], ["classs", "class"], ["clases", "classes"], ["contructor", "constructor"], ["contsructor", "constructor"], ["compnent", "component"], ["componnet", "component"], ["compoent", "component"], ["reponse", "response"], ["respone", "response"], ["reqeust", "request"], ["requst", "request"], ["databse", "database"], ["datbase", "database"], ["serivce", "service"], ["servie", "service"], ["handlr", "handler"], ["handleer", "handler"], ["listner", "listener"], ["lsitener", "listener"], ["connecton", "connection"], ["conection", "connection"], ["authetication", "authentication"], ["athentication", "authentication"], ["validaton", "validation"], ["valiation", "validation"], ["authentification", "authentication"], ["authroization", "authorization"], ["bugfixes", "bug fixes"], ["hotfixes", "hot fixes"], ["updat", "update"], ["updte", "update"], ["udpate", "update"], ["tsting", "testing"], ["tesitng", "testing"], ["testig", "testing"], ]); // Legacy functions for backward compatibility export async function checkSpelling(message) { const results = await GitCleanSpellChecker.checkSpelling(message); return results.map((result) => result.word); } export function getSuggestion(word) { return GitCleanSpellChecker.getAutoCorrection(word); } //# sourceMappingURL=spellcheck.js.map