AFINN-based sentiment analysis for Node.js with multi-language support and custom scoring strategies
npx @tessl/cli install tessl/npm-sentiment@5.0.0Sentiment is a high-performance AFINN-based sentiment analysis library for Node.js that uses the AFINN-165 wordlist and Emoji Sentiment Ranking to analyze the emotional tone of text input. It provides comprehensive sentiment scoring with detailed breakdowns, supports multiple languages through a plugin system, and offers custom scoring strategies for handling negation and emphasis.
npm install sentimentconst Sentiment = require('sentiment');ES6 import (if using a transpiler):
import Sentiment from 'sentiment';const Sentiment = require('sentiment');
const sentiment = new Sentiment();
// Analyze sentiment of text
const result = sentiment.analyze('Cats are totally amazing!');
console.log(result);
// {
// score: 4,
// comparative: 1,
// calculation: [{ amazing: 4 }],
// tokens: ['cats', 'are', 'totally', 'amazing'],
// words: ['amazing'],
// positive: ['amazing'],
// negative: []
// }
// Override AFINN wordlist
const customResult = sentiment.analyze('Cats are stupid.', {
extras: { 'cats': 5, 'stupid': -1 }
});
console.log(customResult.score); // 4 (5 + -1)Sentiment analysis is built around several key components:
Analyzes the emotional tone of input text and returns detailed sentiment metrics.
/**
* Performs sentiment analysis on the provided input phrase
* @param {string} phrase - Input phrase to analyze
* @param {object} [opts] - Analysis options
* @param {string} [opts.language='en'] - Language code for analysis (defaults to 'en')
* @param {object} [opts.extras={}] - Additional word/score pairs to add or overwrite
* @param {function} [callback] - Optional callback function
* @returns {object} Sentiment analysis result
*/
analyze(phrase, opts, callback);Usage Examples:
const sentiment = new Sentiment();
// Basic analysis
const result = sentiment.analyze('I love sunny days!');
// With language specification
const frenchResult = sentiment.analyze('Je suis heureux', {
language: 'fr'
});
// With custom word overrides
const customResult = sentiment.analyze('This product is okay', {
extras: { 'okay': 2 }
});
// With callback (async)
sentiment.analyze('Hello world', (err, result) => {
console.log(result.score);
});Registers support for additional languages with custom word lists and scoring strategies.
/**
* Registers a new language for sentiment analysis
* @param {string} languageCode - Two-digit language code (e.g., 'fr', 'es')
* @param {object} language - Language configuration object
* @param {object} language.labels - Word-to-score mapping for the language
* @param {object} [language.scoringStrategy] - Custom scoring strategy for the language
*/
registerLanguage(languageCode, language);Usage Examples:
const sentiment = new Sentiment();
// Register French language
sentiment.registerLanguage('fr', {
labels: {
'bon': 3,
'mauvais': -3,
'excellent': 5,
'horrible': -5
}
});
// Register with custom scoring strategy
sentiment.registerLanguage('es', {
labels: {
'bueno': 3,
'malo': -3
},
scoringStrategy: {
apply: function(tokens, cursor, tokenScore) {
// Custom negation handling for Spanish
if (cursor > 0 && tokens[cursor - 1] === 'no') {
return -tokenScore;
}
return tokenScore;
}
}
});
// Use registered language
const result = sentiment.analyze('Très bon!', { language: 'fr' });/**
* Creates a new Sentiment analyzer instance
* @param {object} [options] - Configuration options (none currently supported)
*/
function Sentiment(options);interface AnalysisResult {
/** Total sentiment score calculated by summing individual word scores */
score: number;
/** Comparative score (score divided by number of tokens) */
comparative: number;
/** Array of objects showing which words contributed to the score */
calculation: Array<{[word: string]: number}>;
/** All tokens (words/emojis) found in the input text */
tokens: string[];
/** Words from input that were found in the sentiment wordlist */
words: string[];
/** Words with positive sentiment scores */
positive: string[];
/** Words with negative sentiment scores */
negative: string[];
}interface LanguageObject {
/** Word-to-score mapping where keys are words and values are sentiment scores (-5 to +5) */
labels: {[word: string]: number};
/** Optional custom scoring strategy for handling context and negation */
scoringStrategy?: ScoringStrategy;
}
interface ScoringStrategy {
/**
* Applies contextual scoring logic to individual tokens
* @param {string[]} tokens - All tokens in the phrase being analyzed
* @param {number} cursor - Index of the current token being scored
* @param {number} tokenScore - Base sentiment score for the current token
* @returns {number} Modified sentiment score for the token
*/
apply(tokens: string[], cursor: number, tokenScore: number): number;
}interface AnalysisOptions {
/** Two-digit language code for analysis (defaults to 'en') */
language?: string;
/** Additional word/score pairs to add or override in the wordlist */
extras?: {[word: string]: number};
}The sentiment library handles several error conditions:
Error: No language found: <code> when requesting an unregistered languageError: language.labels must be defined! when registering a language without required labelsExample:
const sentiment = new Sentiment();
try {
// This will throw an error
sentiment.analyze('Hello', { language: 'xx' });
} catch (error) {
console.log(error.message); // "No language found: xx"
}
try {
// This will throw an error
sentiment.registerLanguage('fr', { /* missing labels */ });
} catch (error) {
console.log(error.message); // "language.labels must be defined!"
}