-
Notifications
You must be signed in to change notification settings - Fork 310
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
base: develop
Are you sure you want to change the base?
Changes from 6 commits
cc466d5
feee44f
e013017
2b7ce07
f8c85c9
03fe1e8
3792bdc
8bb960e
330a687
68df7eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,5 +12,8 @@ | |
"env": { | ||
"node": true | ||
}, | ||
"parserOptions": { | ||
"ecmaVersion": 8 | ||
}, | ||
"extends": "eslint:recommended" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,74 @@ | ||
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} | ||
* @param {object} hash Result hash. | ||
* @return {object} hash Result hash. | ||
*/ | ||
function processEmoji(hash, callback) { | ||
const processEmoji = async hash => { | ||
// Read file | ||
fs.readFile(EMOJI_PATH, 'utf8', function (err, data) { | ||
if (err) return callback(err); | ||
|
||
try { | ||
const data = await fs.readFileSync(EMOJI_PATH, 'utf8'); | ||
// Split data by new line | ||
data = data.split(/\n/); | ||
|
||
const lines = data.split(/\n/); | ||
// Iterate over dataset and add to hash | ||
for (var i in data) { | ||
var line = data[i].split(','); | ||
|
||
for (const i in lines) { | ||
const line = lines[i].split(','); | ||
// Validate line | ||
if (i == 0) continue; // Label | ||
if (line.length !== 9) continue; // Invalid | ||
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); | ||
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; | ||
if (Number.isNaN(sentiment) || sentiment === 0) continue; | ||
|
||
// Add to hash | ||
hash[emoji] = sentiment; | ||
} | ||
|
||
callback(null, hash); | ||
}); | ||
} | ||
return hash; | ||
} catch (e) { | ||
throw new Error(e); | ||
} | ||
}; | ||
|
||
/** | ||
* Write 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 finish = async hash => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggest we rename function to something like |
||
const result = JSON.stringify(hash, null, 4); | ||
try { | ||
await fs.writeFileSync(RESULT_PATH, result); | ||
return hash; | ||
} catch (e) { | ||
throw new Error(e); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove try catch block. |
||
} | ||
}; | ||
|
||
// 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' | ||
); | ||
}); | ||
const build = async () => { | ||
try { | ||
let hash = {}; | ||
hash = await processEmoji(hash); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like you don't really need to pass hash into the processEmoji function. Suggest something like:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You right, I didn't realize this. |
||
hash = await finish(hash); | ||
process.stderr.write( | ||
`Complete: ${Object.keys(hash).length} entries.\n` | ||
); | ||
} catch (e) { | ||
throw new Error(e); | ||
} | ||
}; | ||
build(); |
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 | ||
}; |
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 | ||
}; |
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you remove the try catch blocks? I think you can simplify the nesting here and right now you are just throwing the error you just caught. Also, the nested catch, throw prepends an
Error:
in the message.