Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite code to ES6 syntax #145

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@
"env": {
"node": true
},
"parserOptions": {
"ecmaVersion": 8
},
"extends": "eslint:recommended"
}
117 changes: 52 additions & 65 deletions build/build.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,66 @@
var async = require('async');
var fs = require('fs');
var path = require('path');
const fs = require('fs');
const path = require('path');

// File paths
var EMOJI_PATH = path.resolve(__dirname, 'Emoji_Sentiment_Data_v1.0.csv');
var RESULT_PATH = path.resolve(__dirname, 'emoji.json');
const EMOJI_PATH = path.resolve(__dirname, 'Emoji_Sentiment_Data_v1.0.csv');
const RESULT_PATH = path.resolve(__dirname, 'emoji.json');

/**
* Read emoji data from original format (CSV).
* @param {object} hash Result hash
* @param {Function} callback Callback
* @return {void}
* Reads emoji data from original format (CSV).
* @param {object} hash Result hash.
* @return {object} hash Result hash.
*/
function processEmoji(hash, callback) {
const processEmoji = async () => {
let hash = {};
// Read file
fs.readFile(EMOJI_PATH, 'utf8', function (err, data) {
if (err) return callback(err);

// Split data by new line
data = data.split(/\n/);

// Iterate over dataset and add to hash
for (var i in data) {
var line = data[i].split(',');

// Validate line
if (i == 0) continue; // Label
if (line.length !== 9) continue; // Invalid
const data = await fs.readFileSync(EMOJI_PATH, 'utf8');
// Split data by new line
const lines = data.split(/\n/);
// Iterate over dataset and add to hash
for (const i in lines) {
const line = lines[i].split(',');
// Validate line
if (i === '0' || i === 0 || line.length !== 9) continue;
// ^ Label ^ Label ^ Invalid

// Establish sentiment value
var emoji = String.fromCodePoint(line[1]);
var occurences = line[2];
var negCount = line[4];
var posCount = line[6];
var score = (posCount / occurences) - (negCount / occurences);
var sentiment = Math.floor(5 * score);
// Establish sentiment value
const emoji = String.fromCodePoint(line[1]);
const occurences = line[2];
const negCount = line[4];
const posCount = line[6];
const score = posCount / occurences - negCount / occurences;
const sentiment = Math.floor(5 * score);

// Validate score
if (Number.isNaN(sentiment)) continue;
if (sentiment === 0) continue;
// Validate score
if (Number.isNaN(sentiment) || sentiment === 0) continue;

// Add to hash
hash[emoji] = sentiment;
}

callback(null, hash);
});
}
// Add to hash
hash[emoji] = sentiment;
}
return hash;
};

/**
* Write sentiment score hash to disk.
* Writes sentiment score hash to disk.
* @param {object} hash Result hash
* @param {Function} callback Callback
* @return {void}
* @return {object} hash Result hash
*/
function finish(hash, callback) {
var result = JSON.stringify(hash, null, 4);
fs.writeFile(RESULT_PATH, result, function (err) {
if (err) return callback(err);
callback(null, hash);
});
}
const writeJSON = async hash => {
const result = JSON.stringify(hash, null, 4);
await fs.writeFileSync(RESULT_PATH, result);
process.stdout.write(`Complete: ${Object.keys(hash).length} entries.\n`);
};

// Execute build process
async.waterfall([
function (cb) {
cb(null, {});
},
processEmoji,
finish
], function(err, result) {
if (err) throw new Error(err);
process.stderr.write(
'Complete: ' +
Object.keys(result).length +
' entries.\n'
);
});
/**
* Executes build process.
* @return {undefined}
*/
const build = async () => {
try {
const hash = await processEmoji();
writeJSON(hash);
} catch (e) {
process.stderr.write(`${e.toString()}\n`);
}
};
build();
7 changes: 5 additions & 2 deletions languages/en/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
const labels = require('./labels.json');
const scoringStrategy = require('./scoring-strategy');

module.exports = {
labels: require('./labels.json'),
scoringStrategy: require('./scoring-strategy')
labels,
scoringStrategy
};
20 changes: 11 additions & 9 deletions languages/en/scoring-strategy.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
var negators = require('./negators.json');
const negators = require('./negators.json');

module.exports = {
apply: function(tokens, cursor, tokenScore) {
if (cursor > 0) {
var prevtoken = tokens[cursor - 1];
if (negators[prevtoken]) {
tokenScore = -tokenScore;
}
const apply = (tokens, cursor, tokenScore) => {
if (cursor > 0) {
const prevtoken = tokens[cursor - 1];
if (negators[prevtoken]) {
tokenScore = -tokenScore;
}
return tokenScore;
}
return tokenScore;
};

module.exports = {
apply
};
173 changes: 86 additions & 87 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,98 +1,97 @@
var tokenize = require('./tokenize');
var languageProcessor = require('./language-processor');
const tokenize = require('./tokenize');
const languageProcessor = require('./language-processor');

/**
* Constructor
* @param {Object} options - Instance options
*/
var Sentiment = function (options) {
this.options = options;
};

/**
* Registers the specified language
*
* @param {String} languageCode
* - Two-digit code for the language to register
* @param {Object} language
* - The language module to register
*/
Sentiment.prototype.registerLanguage = function (languageCode, language) {
languageProcessor.addLanguage(languageCode, language);
};

/**
* Performs sentiment analysis on the provided input 'phrase'.
*
* @param {String} phrase
* - Input phrase
* @param {Object} opts
* - Options
* @param {Object} opts.language
* - Input language code (2 digit code), defaults to 'en'
* @param {Object} opts.extras
* - Optional sentiment additions to AFINN (hash k/v pairs)
* @param {function} callback
* - Optional callback
* @return {Object}
*/
Sentiment.prototype.analyze = function (phrase, opts, callback) {
// Parse arguments
if (typeof phrase === 'undefined') phrase = '';
if (typeof opts === 'function') {
callback = opts;
opts = {};
class Sentiment {
/**
* Represents a Sentiment.
* @constructor
* @param {Object} options - Instance options.
*/
constructor(options) {
this.options = options;
}
opts = opts || {};

var languageCode = opts.language || 'en';
var labels = languageProcessor.getLabels(languageCode);

// Merge extra labels
if (typeof opts.extras === 'object') {
labels = Object.assign(labels, opts.extras);
/**
* Registers the specified language.
* @param {string} languageCode - Two-digit code for the language to
* register.
* @param {object} language - The language module to register.
*/
registerLanguage(languageCode, language) {
languageProcessor.addLanguage(languageCode, language);
}
/**
* Performs sentiment analysis on the provided input 'phrase'.
* @param {string} phrase - Input phrase
* @param {object} opts - Options
* @param {object} opts.language - Input language code (2 digit code),
* defaults to 'en'
* @param {object} opts.extras - Optional sentiment additions to AFINN
* (hash k/v pairs)
* @param {function} callback - Optional callback
* @return {object}
*/
analyze(phrase = '', opts = { language: 'en' }, callback) {
// Storage objects
const tokens = tokenize(phrase);
let score = 0;
let words = [];
let positive = [];
let negative = [];

// Storage objects
var tokens = tokenize(phrase),
score = 0,
words = [],
positive = [],
negative = [];
// Parse arguments
if (typeof opts === 'function') {
callback = opts;
opts = {};
}

// Iterate over tokens
var i = tokens.length;
while (i--) {
var obj = tokens[i];
if (!labels.hasOwnProperty(obj)) continue;
words.push(obj);
const languageCode = opts.language;
let labels = languageProcessor.getLabels(languageCode);

// Apply scoring strategy
var tokenScore = labels[obj];
// eslint-disable-next-line max-len
tokenScore = languageProcessor.applyScoringStrategy(languageCode, tokens, i, tokenScore);
if (tokenScore > 0) positive.push(obj);
if (tokenScore < 0) negative.push(obj);
score += tokenScore;
}
// Merge extra labels
if (typeof opts.extras === 'object') {
labels = Object.assign(labels, opts.extras);
}

// Iterate over tokens
let i = tokens.length;
while (i--) {
const obj = tokens[i];
if (!labels.hasOwnProperty(obj)) continue;
words = words.concat(obj);
// Apply scoring strategy
const tokenScore = languageProcessor.applyScoringStrategy(
languageCode,
tokens,
i,
labels[obj]
);
if (tokenScore > 0) {
positive = positive.concat(obj);
}
if (tokenScore < 0) {
negative = negative.concat(obj);
}
score += tokenScore;
}

var result = {
score: score,
comparative: tokens.length > 0 ? score / tokens.length : 0,
tokens: tokens,
words: words,
positive: positive,
negative: negative
};
const result = {
score,
comparative: tokens.length > 0 ? score / tokens.length : 0,
tokens,
words,
positive,
negative
};

// Handle optional async interface
if (typeof callback === 'function') {
process.nextTick(function () {
callback(null, result);
});
} else {
return result;
// Handle optional async interface
if (typeof callback === 'function') {
process.nextTick(() => {
callback(null, result);
});
} else {
return result;
}
}
};
}

module.exports = Sentiment;
Loading