Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | 1x 2x 2x 2x 2x 2x 2x 2x 2x 53x 2x 2x 53x 53x 2x 23x 23x 1x 1x 1x 23x 1x 1x 1x 21x 21x 21x 21x 23x 1x 1x 1x 1x 18x 18x 18x 18x 18x 18x 18x 23x 2x 2x 2x 2x 23x 2x 35x 35x 35x 2x 6x 6x 2x 3x 3x 3x 1x 1x 2x 2x 3x 2x 4x 4x 4x 2x 1x 1x 1x 1x 1x 2x 5x 5x 5x 5x 2x 1x 1x 2x | /**
* SynonymResolver provides synonym matching capabilities using the DataMuse API.
*
* This is the basic version that includes:
* - Singleton pattern
* - Basic synonym fetching from DataMuse API
* - Simple in-memory caching
* - Error handling
*
* @example
* ```ts
* const resolver = SynonymResolver.getInstance();
* const synonyms = await resolver.getSynonyms('jump');
* // Returns: ['leap', 'hop', 'spring', 'bound', ...]
* ```
*/
export class SynonymResolver {
/** Cache to store synonym results and avoid repeated API calls */
private synonymCache: Map<string, string[]>;
/** The single global instance of SynonymResolver */
private static instance: SynonymResolver;
/** Base URL for the DataMuse API */
private readonly API_URL = 'https://api.datamuse.com/words';
/** Maximum number of synonyms to fetch per word */
private MAX_RESULTS = 3;
/** Private constructor prevents direct instantiation - use getInstance() */
private constructor() {
this.synonymCache = new Map<string, string[]>();
}
/**
* Returns the singleton instance of SynonymResolver.
*
* @returns {SynonymResolver} The single shared instance
*/
public static getInstance(): SynonymResolver {
if (!SynonymResolver.instance) {
SynonymResolver.instance = new SynonymResolver();
}
return SynonymResolver.instance;
}
/**
* Fetches synonyms for a given word from the DataMuse API.
* Results are cached in memory to avoid repeated API calls for the same word.
*
* The DataMuse API parameter 'ml' means "means like" which returns synonyms.
* API is free and doesn't require authentication.
*
* @param {string} word - The word to find synonyms for
* @returns {Promise<string[]>} Array of synonym words (lowercase), empty array on error
*
* @example
* ```ts
* const resolver = SynonymResolver.getInstance();
* const synonyms = await resolver.getSynonyms('jump');
* console.log(synonyms); // ['leap', 'hop', 'spring', 'bound', ...]
* ```
*/
public async getSynonyms(word: string): Promise<string[]> {
const normalized = word.toLowerCase().trim();
// Return empty array for invalid input
if (!normalized) {
console.warn('Cannot fetch synonyms for empty word');
return [];
}
// Check cache first to avoid unnecessary API calls
if (this.synonymCache.has(normalized)) {
console.log(`Cache hit for "${normalized}"`);
return this.synonymCache.get(normalized)!;
}
try {
// Build API URL with query parameters
// ml= means "means like" (synonyms)
// max= limits the number of results
const url = `${this.API_URL}?ml=${encodeURIComponent(normalized)}&max=${this.MAX_RESULTS}`;
console.log(`Fetching synonyms for "${normalized}" from DataMuse API...`);
const response = await fetch(url);
if (!response.ok) {
console.warn(`DataMuse API returned status ${response.status} for "${word}"`);
// Cache empty array to avoid repeated failed requests
this.synonymCache.set(normalized, []);
return [];
}
// Parse JSON response
const data = await response.json();
// DataMuse returns array of objects like: [{word: "leap", score: 1234}, ...]
// Extract just the words and normalize to lowercase
const synonyms = data
.map((item: { word: string }) => item.word.toLowerCase().trim())
.filter((synonym: string) => synonym !== normalized); // Exclude the original word
console.log(`Found ${synonyms.length} synonyms for "${normalized}"`);
// Cache the results for future use
this.synonymCache.set(normalized, synonyms);
return synonyms;
} catch (error) {
console.error(`Error fetching synonyms for "${word}":`, error);
// Cache empty array to prevent repeated failures
this.synonymCache.set(normalized, []);
return [];
}
}
/**
* Clears the entire synonym cache.
* Useful for testing or if you want to force fresh API calls.
*
* @returns {void}
*/
public clearCache(): void {
this.synonymCache.clear();
console.log('Synonym cache cleared');
}
/**
* Returns the number of words currently cached.
*
* @returns {number} Number of words in the cache
*/
public getCacheSize(): number {
return this.synonymCache.size;
}
/**
* Checks if two words are synonyms of each other.
*
* This method checks if word2 appears in word1's synonym list.
*
* @param {string} word1 - First word to compare
* @param {string} word2 - Second word to compare
* @returns {Promise<boolean>} True if the words are synonyms, false otherwise
*
* @example
* ```ts
* const resolver = SynonymResolver.getInstance();
* const areSynonyms = await resolver.areSynonyms('jump', 'leap');
* console.log(areSynonyms); // true
* ```
*/
public async areSynonyms(word1: string, word2: string): Promise<boolean> {
const normalized1 = word1.toLowerCase().trim();
const normalized2 = word2.toLowerCase().trim();
// Same word is obviously a match
if (normalized1 === normalized2) {
return true;
}
// Check if word2 is in word1's synonyms
const synonyms1 = await this.getSynonyms(normalized1);
return synonyms1.includes(normalized2);
}
/**
* Checks if synonyms for a specific word are already cached.
*
* @param {string} word - The word to check
* @returns {boolean} True if synonyms are cached, false otherwise
*
* @example
* ```ts
* const resolver = SynonymResolver.getInstance();
* if (resolver.isCached('jump')) {
* console.log('Synonyms for "jump" are already cached');
* }
* ```
*/
public isCached(word: string): boolean {
const normalized = word.toLowerCase().trim();
return this.synonymCache.has(normalized);
}
/**
* Pre-fetches and caches synonyms for multiple words at once.
* Useful for initializing the cache with commonly used words.
*
* @param {string[]} words - Array of words to pre-fetch synonyms for
* @returns {Promise<void>} Resolves when all synonyms are fetched
*
* @example
* ```ts
* const resolver = SynonymResolver.getInstance();
* await resolver.prefetchSynonyms(['jump', 'run', 'walk']);
* // All synonyms are now cached and ready for instant lookup
* ```
*/
public async prefetchSynonyms(words: string[]): Promise<void> {
console.log(`Pre-fetching synonyms for ${words.length} words...`);
// Fetch all synonyms in parallel for better performance
const promises = words.map(word => this.getSynonyms(word));
await Promise.all(promises);
console.log(`Pre-fetch complete. Cache now contains ${this.getCacheSize()} words`);
}
public setMAX_RESULTS(numberOfSynonyms: number):void{
if(!numberOfSynonyms){
numberOfSynonyms = 3;
}
if(numberOfSynonyms <1){
numberOfSynonyms = 1;
}
this.MAX_RESULTS = numberOfSynonyms;
}
public getMax_Results():number{
return this.MAX_RESULTS;
}
} |