qd-arabic-words
Version:
A package for generating random Arabic words that belongs to the Quantum Developers server in discord.
236 lines (201 loc) • 7.21 kB
JavaScript
const arabicWords = require('./words');
// Constants for validation
const MIN_WORD_LENGTH = 1;
const MAX_WORD_LENGTH = Math.max(...arabicWords.map(word => word.length));
const MAX_REQUESTED_WORDS = 100; // Prevent excessive memory usage
/**
* Validates input parameters
* @param {any} options - The input options to validate
* @throws {TypeError} When input is invalid
*/
function validateInput(options) {
// Check for null or undefined (explicit checks)
if (options === null || options === undefined) {
return; // Allowed as it means use defaults
}
// Validate number input
if (Number.isInteger(options)) {
if (options <= 0) {
throw new TypeError('Number of words must be positive');
}
if (options > MAX_REQUESTED_WORDS) {
throw new RangeError(`Cannot request more than ${MAX_REQUESTED_WORDS} words`);
}
return;
}
// Validate object input
if (typeof options === 'object') {
// Check for invalid object properties
const validProperties = ['num', 'minLength', 'maxLength', 'join'];
const invalidProps = Object.keys(options).filter(
prop => !validProperties.includes(prop)
);
if (invalidProps.length > 0) {
throw new TypeError(`Invalid properties: ${invalidProps.join(', ')}`);
}
// Validate num
if (options.num !== undefined) {
if (!Number.isInteger(options.num)) {
throw new TypeError('num must be an integer');
}
if (options.num <= 0) {
throw new RangeError('num must be positive');
}
if (options.num > MAX_REQUESTED_WORDS) {
throw new RangeError(`num cannot exceed ${MAX_REQUESTED_WORDS}`);
}
}
// Validate lengths
if (options.minLength !== undefined) {
if (!Number.isInteger(options.minLength)) {
throw new TypeError('minLength must be an integer');
}
if (options.minLength < MIN_WORD_LENGTH) {
throw new RangeError(`minLength must be at least ${MIN_WORD_LENGTH}`);
}
}
if (options.maxLength !== undefined) {
if (!Number.isInteger(options.maxLength)) {
throw new TypeError('maxLength must be an integer');
}
if (options.maxLength > MAX_WORD_LENGTH) {
throw new RangeError(`maxLength cannot exceed ${MAX_WORD_LENGTH}`);
}
}
// Validate length range
if (options.minLength !== undefined && options.maxLength !== undefined) {
if (options.minLength > options.maxLength) {
throw new RangeError('minLength cannot be greater than maxLength');
}
}
// Validate join
if (options.join !== undefined && typeof options.join !== 'string') {
throw new TypeError('join must be a string');
}
return;
}
throw new TypeError('Invalid input type. Expected number or options object');
}
/**
* Generate random Arabic words with various options
* @param {number|Object} [options={}] - Can be a number or options object
* @returns {Promise<string|Array<string>>} - Single word or array of words
* @throws {Error} When no words match criteria
*/
async function generateArabicWords(options = {}) {
try {
// Input validation
validateInput(options);
// Default case: single random word
if (Object.keys(options).length === 0 && !Number.isInteger(options)) {
return getRandomWord();
}
// Number case: array of words
if (Number.isInteger(options)) {
return getMultipleWords(options);
}
// Object options case
const { num, minLength, maxLength, join } = options;
// Handle num with join
if (num !== undefined && join !== undefined) {
const words = await getFilteredWords(num, minLength, maxLength);
return words.join(join);
}
// Handle num without join
if (num !== undefined) {
return getFilteredWords(num, minLength, maxLength);
}
// Handle length constraints
if (minLength !== undefined || maxLength !== undefined) {
return getWordByLength(minLength, maxLength);
}
// Fallback to single word if no recognized options
return getRandomWord();
} catch (error) {
console.error('Generation error:', error.message);
throw error; // Re-throw for caller to handle
}
}
// Helper: Get single random word with safety check
function getRandomWord() {
if (arabicWords.length === 0) {
throw new Error('Word database is empty');
}
return arabicWords[Math.floor(Math.random() * arabicWords.length)];
}
// Helper: Get multiple random words with validation
function getMultipleWords(count) {
if (arabicWords.length === 0) {
throw new Error('Word database is empty');
}
// For small databases, ensure we don't request duplicates if not enough words
if (count > arabicWords.length) {
throw new Error(`Cannot return ${count} unique words from a pool of ${arabicWords.length}`);
}
// Create a copy to avoid modifying original array
const wordPool = [...arabicWords];
const result = [];
// Fisher-Yates shuffle algorithm for better randomness
for (let i = wordPool.length - 1; i > 0 && result.length < count; i--) {
const j = Math.floor(Math.random() * (i + 1));
[wordPool[i], wordPool[j]] = [wordPool[j], wordPool[i]];
result.push(wordPool[i]);
}
return result.slice(0, count);
}
// Helper: Get word by length constraints with thorough validation
function getWordByLength(minLength, maxLength) {
const filteredWords = arabicWords.filter(word => {
const length = word.length;
return (
(minLength === undefined || length >= minLength) &&
(maxLength === undefined || length <= maxLength)
);
});
if (filteredWords.length === 0) {
throw new Error(
`No words found matching length criteria: ${
minLength !== undefined ? `minLength=${minLength}` : ''
}${
minLength !== undefined && maxLength !== undefined ? ', ' : ''
}${
maxLength !== undefined ? `maxLength=${maxLength}` : ''
}`
);
}
return filteredWords[Math.floor(Math.random() * filteredWords.length)];
}
// Helper: Get filtered words with constraints
async function getFilteredWords(count, minLength, maxLength) {
const filteredWords = arabicWords.filter(word => {
const length = word.length;
return (
(minLength === undefined || length >= minLength) &&
(maxLength === undefined || length <= maxLength)
);
});
if (filteredWords.length === 0) {
throw new Error(
`No words found matching criteria: ${
minLength !== undefined ? `minLength=${minLength}` : ''
}${
minLength !== undefined && maxLength !== undefined ? ', ' : ''
}${
maxLength !== undefined ? `maxLength=${maxLength}` : ''
}`
);
}
if (count > filteredWords.length) {
throw new Error(
`Cannot return ${count} words. Only ${filteredWords.length} words match the criteria`
);
}
// Improved shuffling algorithm
const shuffled = [...filteredWords];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled.slice(0, count);
}
module.exports = generateArabicWords;