UNPKG

simple-spellchecker

Version:

A simple spellchecker compatible with Electron

233 lines (215 loc) 10.4 kB
/* * Copyright (c) 2016 José F. Maldonado * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. * If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // Load dependencies. const fs = require('fs'); const path = require('path'); const tmp = require('tmp'); const Zip = require('adm-zip'); const stripBOM = require('strip-bom'); const Dictionary = require('./dictionary.js'); const FOLDER_PATH = __dirname + '/dict'; // Define module. var SpellChecker = { /** * Create a dictionary from a file, which might be either a .dic or a .zip file. * * @param {String} fileName The name of the file from which read the word list. * @param {String} folderPath The path to the directory in which the file is located (optional). * @param {Callback} callback A function to invoke when either the dictionary was created or an error was found. */ getDictionary: function(fileName, folderPath /*, callback*/) { try{ // Initialize variables. var folder = (!folderPath || typeof folderPath != 'string')? FOLDER_PATH : folderPath; var callback = arguments[arguments.length - 1]; var dic_path = folder + '/' + fileName + '.dic'; var zip_path = folder + '/' + fileName + '.zip'; // Verify if the dictionary file exists. fs.exists(dic_path, function(exists) { if(exists) { // The file exists, read it. SpellChecker._readFile(dic_path, callback); } else { // The file do not exists, verify if the ZIP file exists. fs.exists(zip_path, function(exists) { if(exists) { try{ // The file ZIP exists, unzip it. SpellChecker._unzipSync(zip_path, folder); SpellChecker._readFile(dic_path, callback); } catch(errZip) { // Return error. if(callback) callback('An unexpected error ocurred: ' + errZip, null); } } else { // The ZIP file also doesn't exists, return an error. callback('The dictionary could not be read, no file with the name "' + fileName + '" could be found', null); } }); } }); } catch(err) { // Return error. if(callback) callback('An unexpected error ocurred: ' + err, null); } }, /** * Create a dictionary from a .dic file. * * @param {String} file_path The path of the file. * @param {Callback} callback A function to invoke when either the dictionary was created or an error was found. */ _readFile: function(file_path, callback) { fs.readFile(file_path, 'utf8', function(err, text) { // Check for errors. if (!err) { // Create dictionary and return it. var dictionary = new Dictionary(text.split('\n')); callback(null, dictionary); } else { // Return an error. callback("The dictionary file could not be read: " + err, null); } }); }, /** * Create a dictionary from a .dic file synchronously. * * @param {String} file_path The path of the file. * @returns The created dictionary * @throws An error if the file couldn't be opened */ _readFileSync: function(file_path) { try { var text = fs.readFileSync(file_path, 'utf8') // Create dictionary and return it. var dictionary = new Dictionary(text.split('\n')); return dictionary; } catch(err) { // Return an error. throw new Error("The dictionary file could not be read: " + file_path + ". Error: " + err); } }, /** * Unzip a zip file. * * Each entry in the zip file will be extracted atomically. From the perspective of another * process, the unzipped file will either not exist or will be fully unzipped. * * @param {String} zipPath The path of the zip file. * @param {String} destinationDir The directory to unzip into. * @throws An error if the file couldn't be unzipped. */ _unzipSync: function(zipPath, destinationDir) { // Unzip into a tmp directory. var tmpDir = tmp.dirSync({ dir: destinationDir }); var zip = new Zip(zipPath); zip.extractAllTo(tmpDir.name); // Move the unzipped files out of the tmp directory and into the destination directory. zip.getEntries().forEach(({ entryName }) => { var from = path.join(tmpDir.name, entryName); var to = path.join(destinationDir, entryName); fs.renameSync(from, to); }); // Clean up the tmp directory tmpDir.removeCallback(); }, /** * Create a dictionary from a .dic file . * * @param {String} fileName The name of the file from which read the word list. * @param {String} folderPath The path to the directory in which the file is located (optional). * @return {Object} An instance of the Dictionary class. * @throws {Exception} If the dictionary's file can't be found or is invalid. */ getDictionarySync: function(fileName, folderPath) { try{ // Initialize variables. var folder = (!folderPath || typeof folderPath != 'string')? FOLDER_PATH : folderPath; var dic_path = folder + '/' + fileName + '.dic'; var zip_path = folder + '/' + fileName + '.zip'; // Verify if the dictionary file exists. if(fs.existsSync(dic_path)) { // The file exists, read it. var dictionary = SpellChecker._readFileSync(dic_path); return dictionary; } else { // The file do not exists, verify if the ZIP file exists. var exists = fs.existsSync(zip_path); if(exists) { // The file ZIP exists, unzip it. SpellChecker._unzipSync(zip_path, folder); var dictionary = SpellChecker._readFileSync(dic_path); return dictionary; } else { // The ZIP file also doesn't exists, return an error. throw new Error('The dictionary could not be read, no file with the name "' + fileName + '" could be found'); } } } catch(err) { // Throw an error. throw new Error('An unexpected error ocurred: ' + err); } }, /** * Reads a UTF8 dictionary file, removes the BOM and \r characters and sorts the list of words. * * @param {String} inputPath The path for the input file. * @param {String} outputPath The path to output (optional, by default is equals to the input file). * @param {Callback} callback A function to invoke after finishing. */ normalizeDictionary: function(inputPath, outputPath /*, callback*/) { try{ // Parses arguments if(!outputPath || typeof outputPath != 'string') outputPath = inputPath; var callback = arguments.length > 0? arguments[arguments.length - 1] : function() {}; // Verify if the dictionary file exists. fs.exists(inputPath, function(exists) { if(exists) { // The file exists, read it. fs.readFile(inputPath, 'utf8', function(err, content) { // Check for errors. if (!err) { // Remove BOM and \r characters. content = stripBOM(content); content = content.replace(/\r/g, ''); // Sort words. var lines = content.split('\n'); var collator = new Intl.Collator(); // Use this comparator for consider accents and special characters. lines = lines.sort(collator.compare); // Generate output content. var newContent = ''; var first = true; for(var i=0; i<lines.length; i++) { if(lines[i] != '' && lines[i] != '\n') { if(!first) newContent += '\n'; newContent += lines[i]; first = false; } } // Write output file. fs.writeFile(outputPath, newContent, 'utf8', function(err) { // Return result. callback(err? ("The output file could not be writted: " + err) : null, !err); }); } else { // Return an error. callback("The input file could not be read: " + err, false); } }); } else { // Return an error indicating that the file doens't exists. callback("The input file does not exists", false); } }); } catch(err) { // Return an error. callback('An unexpected error ocurred: ' + err, false); } } } // Export module. module.exports = SpellChecker;