UNPKG

textconvert

Version:

Public library to convert text into many conventions and formats.

1 lines 75.7 kB
{"version":3,"file":"textConvert.mjs","sources":["../src/assets/regex.ts","../src/text/conventions.ts","../src/text/analysis/language.ts","../src/text/clear.ts","../src/text/count.ts","../src/text/analysis/statistics.ts","../src/text/reverse.ts","../src/text/spread.ts","../src/text/validation/email.ts","../src/numbers/numbersToWords.ts"],"sourcesContent":["/**\n * Make a regex list to split words based on these patterns\n */\n\nconst regex = {\n name: 'Regex List',\n description: 'Regex patterns list to be used in functions',\n values: {\n upperCase: /[A-Z]/g,\n upperCaseKeepLetter: /(?=[A-Z])/g,\n lowerCase: /[a-z]/g,\n lowerUpperCase: /[A-Za-z]/g,\n nonAlphabetic: /[^A-Za-z]/g,\n nonAlphaTest: /[^A-Za-z]/,\n punctuation: /[!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~]/g,\n },\n};\n\nexport { regex };\n","import { regex } from '../assets/regex';\n\nconst { values } = regex;\n\n/**\n * Convert a string from any convention to Camel Case convention.\n * @param text A string to be converted to Camel Case.\n * @returns A string in camelCase convention.\n * @example\n * camelCase('hello world'); // 'helloWorld'\n */\nexport function camelCase(text: string): string {\n // Make sure there's an input\n if (!text) return 'Please provide a valid input text';\n\n // Make an array of words after splitting them\n const wordsArray: string[] = text.split(values.nonAlphabetic);\n // Get the first word out of the array\n const firstWord = wordsArray.shift()?.toLowerCase();\n\n // convert the words to camelCase\n const cCaseArray: string[] = wordsArray.map((word: string) => {\n word = word.charAt(0).toUpperCase() + word.slice(1);\n return word;\n });\n\n // Join the words and return them\n return firstWord + cCaseArray.join('');\n}\n\n/**\n * Convert a string from any convention to Pascal Case convention.\n * @param text A string to be converted to Camel Case.\n * @returns A string in PascalCase convention.\n * @example\n * pascalCase('hello world'); // 'HelloWorld'\n */\nexport function pascalCase(text: string): string {\n // Make sure there's an input\n if (!text) return 'Please provide a valid input text';\n\n // Make an array of words after splitting them\n const wordsArray: string[] = text.split(values.nonAlphabetic);\n\n // convert the words to camelCase\n const pCaseArray: string[] = wordsArray.map((word: string) => {\n word = word.charAt(0).toUpperCase() + word.slice(1);\n return word;\n });\n\n // Join the words and return them\n return pCaseArray.join('');\n}\n\n/**\n * Convert a string from any convention to Snake Case convention.\n * @param text A string to be converted to Snake Case.\n * @returns A string in snake_case convention.\n * @example\n * snakeCase('hello world'); // 'hello_world'\n */\nexport function snakeCase(text: string): string {\n // Make sure there's an input\n if (!text) return 'Please provide a valid input text';\n\n // Make an array of words after splitting them depending on the input case\n const wordsArray: string[] = values.nonAlphaTest.test(text)\n ? text.split(values.nonAlphabetic)\n : text.split(values.upperCaseKeepLetter);\n\n // Filter the words to 1 letter minimum length and convert the words to lowerCase\n const sCaseArray: string[] = wordsArray\n .filter((word: string) => word.length > 0)\n .map((word: string) => {\n word = word.charAt(0).toLowerCase() + word.slice(1);\n return word;\n });\n\n // Join the words with \"_\" and return them\n return sCaseArray.join('_');\n}\n\n/**\n * Convert a string from any convention to Kebab Case convention.\n * @param text A string to be converted to Kebab Case.\n * @returns A string in kebab-case convention.\n * @example\n * kebabCase('hello world'); // 'hello-world'\n */\nexport function kebabCase(text: string): string {\n // Make sure there's an input\n if (!text) return 'Please provide a valid input text';\n\n // Make an array of words after splitting them depending on the input case\n const wordsArray: string[] = values.nonAlphaTest.test(text)\n ? text.split(values.nonAlphabetic)\n : text.split(values.upperCaseKeepLetter);\n\n // Filter the words to 1 letter minimum length and convert the words to lowerCase\n const kCaseArray: string[] = wordsArray\n .filter((word: string) => word.length > 0)\n .map((word: string) => {\n word = word.charAt(0).toLowerCase() + word.slice(1);\n return word;\n });\n\n // Join the words with \"-\" and return them\n return kCaseArray.join('-');\n}\n","/**\n * Supported languages for detection\n */\nexport enum Language {\n English = 'english',\n French = 'french',\n Spanish = 'spanish',\n German = 'german',\n Italian = 'italian',\n Portuguese = 'portuguese',\n Dutch = 'dutch',\n Unknown = 'unknown',\n}\n\n/**\n * Language detection result interface\n */\nexport interface LanguageDetectionResult {\n /**\n * The detected language\n */\n language: Language;\n\n /**\n * Confidence score (0-1) of the detection\n */\n confidence: number;\n\n /**\n * Scores for each language analyzed\n */\n scores: Record<Language, number>;\n}\n\n// Language profiles (character frequency data)\nconst languageProfiles: Record<Language, Record<string, number>> = {\n [Language.English]: {\n e: 12.7,\n t: 9.1,\n a: 8.2,\n o: 7.5,\n i: 7.0,\n n: 6.7,\n s: 6.3,\n h: 6.1,\n r: 6.0,\n d: 4.3,\n l: 4.0,\n u: 2.8,\n c: 2.8,\n m: 2.4,\n w: 2.4,\n f: 2.2,\n g: 2.0,\n y: 2.0,\n p: 1.9,\n b: 1.5,\n v: 1.0,\n k: 0.8,\n j: 0.2,\n x: 0.2,\n q: 0.1,\n z: 0.1,\n th: 3.0,\n he: 2.5,\n in: 2.0,\n er: 1.8,\n an: 1.6,\n re: 1.4,\n on: 1.3,\n at: 1.2,\n },\n [Language.French]: {\n e: 14.7,\n a: 8.0,\n i: 7.5,\n s: 7.9,\n n: 7.1,\n t: 7.0,\n r: 6.5,\n l: 5.5,\n u: 6.0,\n o: 5.3,\n d: 3.5,\n c: 3.0,\n m: 2.6,\n p: 2.5,\n v: 1.6,\n h: 0.8,\n g: 1.0,\n f: 1.0,\n b: 0.9,\n q: 1.3,\n j: 0.3,\n z: 0.1,\n x: 0.4,\n k: 0.0,\n w: 0.0,\n y: 0.3,\n é: 1.9,\n è: 0.3,\n ê: 0.2,\n à: 0.5,\n â: 0.1,\n ç: 0.3,\n ai: 1.0,\n oi: 0.4,\n ou: 0.9,\n },\n [Language.Spanish]: {\n e: 13.7,\n a: 12.5,\n o: 8.7,\n s: 7.8,\n n: 7.0,\n r: 6.4,\n i: 6.2,\n l: 5.8,\n d: 5.8,\n t: 4.6,\n c: 4.0,\n u: 3.9,\n m: 3.1,\n p: 2.5,\n b: 1.4,\n g: 1.0,\n v: 1.0,\n f: 0.7,\n h: 0.7,\n q: 0.9,\n j: 0.4,\n z: 0.5,\n ñ: 0.3,\n y: 1.0,\n x: 0.2,\n k: 0.0,\n w: 0.0,\n á: 0.5,\n é: 0.4,\n í: 0.4,\n ó: 0.9,\n ú: 0.4,\n qu: 0.8,\n ue: 0.6,\n ch: 0.4,\n },\n [Language.German]: {\n e: 16.9,\n n: 10.0,\n i: 7.6,\n s: 7.3,\n r: 7.0,\n t: 6.1,\n a: 6.5,\n d: 5.1,\n h: 4.8,\n u: 4.4,\n l: 3.4,\n c: 2.7,\n g: 3.0,\n m: 2.5,\n o: 2.5,\n b: 1.9,\n w: 1.9,\n f: 1.7,\n k: 1.4,\n z: 1.1,\n v: 0.7,\n p: 0.7,\n j: 0.3,\n y: 0.1,\n q: 0.02,\n x: 0.03,\n ä: 0.5,\n ö: 0.3,\n ü: 0.6,\n ß: 0.3,\n ch: 2.6,\n ei: 1.8,\n en: 3.8,\n er: 3.6,\n ie: 1.7,\n },\n [Language.Italian]: {\n e: 11.8,\n a: 11.7,\n i: 10.1,\n o: 9.8,\n n: 6.9,\n t: 5.6,\n r: 6.4,\n l: 6.3,\n s: 5.0,\n c: 4.5,\n d: 3.7,\n p: 3.0,\n u: 3.0,\n m: 2.5,\n v: 2.1,\n g: 1.6,\n h: 1.5,\n b: 0.9,\n f: 0.9,\n z: 0.5,\n q: 0.5,\n à: 0.6,\n è: 0.4,\n ì: 0.1,\n ò: 0.2,\n ù: 0.1,\n ch: 0.5,\n di: 0.9,\n la: 0.7,\n re: 0.6,\n },\n [Language.Portuguese]: {\n a: 14.6,\n e: 12.6,\n o: 10.7,\n s: 7.8,\n r: 6.5,\n i: 6.2,\n n: 5.0,\n t: 4.7,\n d: 4.9,\n m: 4.7,\n u: 4.0,\n c: 3.7,\n l: 2.8,\n p: 2.5,\n v: 1.7,\n g: 1.3,\n b: 1.0,\n f: 1.0,\n h: 0.8,\n q: 1.2,\n ã: 0.7,\n á: 0.5,\n é: 0.4,\n ó: 0.4,\n ç: 0.5,\n õ: 0.3,\n j: 0.3,\n z: 0.5,\n ê: 0.1,\n â: 0.1,\n qu: 0.8,\n de: 0.7,\n es: 0.7,\n },\n [Language.Dutch]: {\n e: 19.0,\n n: 10.0,\n a: 7.5,\n t: 6.5,\n i: 6.5,\n r: 6.0,\n o: 6.0,\n d: 5.8,\n s: 3.7,\n l: 3.5,\n g: 3.4,\n v: 2.8,\n h: 2.4,\n k: 2.2,\n m: 2.2,\n u: 2.0,\n j: 1.5,\n w: 1.5,\n z: 1.4,\n p: 1.2,\n b: 1.6,\n c: 1.2,\n f: 0.8,\n y: 0.0,\n x: 0.0,\n q: 0.0,\n ij: 1.0,\n en: 3.5,\n de: 3.0,\n er: 2.0,\n ee: 1.8,\n oo: 1.0,\n },\n [Language.Unknown]: {},\n};\n\n// Common stopwords for each language\nconst stopwords: Record<Language, string[]> = {\n [Language.English]: [\n 'the',\n 'be',\n 'to',\n 'of',\n 'and',\n 'a',\n 'in',\n 'that',\n 'have',\n 'i',\n 'it',\n 'for',\n 'not',\n 'on',\n 'with',\n 'he',\n 'as',\n 'you',\n 'do',\n 'at',\n 'this',\n 'but',\n 'his',\n 'by',\n 'from',\n 'they',\n 'we',\n 'say',\n 'her',\n 'she',\n 'or',\n 'an',\n 'will',\n 'my',\n 'one',\n 'all',\n 'would',\n 'there',\n 'their',\n 'what',\n 'so',\n 'up',\n 'out',\n 'if',\n 'about',\n 'who',\n 'get',\n 'which',\n 'go',\n 'me',\n 'when',\n 'make',\n 'can',\n 'like',\n 'time',\n 'no',\n 'just',\n 'him',\n 'know',\n 'take',\n 'people',\n 'into',\n 'year',\n 'your',\n 'good',\n 'some',\n 'could',\n 'them',\n 'see',\n 'other',\n 'than',\n 'then',\n 'now',\n 'look',\n 'only',\n 'come',\n 'its',\n 'over',\n 'think',\n 'also',\n 'back',\n 'after',\n 'use',\n 'two',\n 'how',\n 'our',\n 'work',\n 'first',\n 'well',\n 'way',\n 'even',\n 'new',\n 'want',\n 'because',\n 'any',\n 'these',\n 'give',\n 'day',\n 'most',\n 'us',\n 'is',\n 'am',\n 'are',\n 'was',\n 'were',\n 'been',\n 'has',\n 'had',\n 'would',\n 'should',\n 'could',\n 'hello',\n 'world',\n ],\n [Language.French]: [\n 'le',\n 'la',\n 'les',\n 'un',\n 'une',\n 'des',\n 'et',\n 'est',\n 'en',\n 'que',\n 'qui',\n 'dans',\n 'à',\n 'pour',\n 'pas',\n 'de',\n 'ce',\n 'il',\n 'elle',\n 'je',\n 'nous',\n 'vous',\n 'ils',\n 'elles',\n 'son',\n 'sa',\n 'ses',\n 'mon',\n 'ma',\n 'mes',\n 'ton',\n 'ta',\n 'tes',\n 'notre',\n 'votre',\n 'leur',\n 'leurs',\n 'du',\n 'au',\n 'aux',\n 'sur',\n 'sous',\n 'avec',\n 'sans',\n 'mais',\n 'ou',\n 'où',\n 'donc',\n 'car',\n 'comme',\n 'comment',\n 'quand',\n 'pourquoi',\n 'parce',\n 'plus',\n 'moins',\n 'très',\n 'trop',\n 'peu',\n 'aussi',\n 'bien',\n 'mal',\n 'si',\n 'tout',\n 'tous',\n 'toute',\n 'toutes',\n 'autre',\n 'autres',\n 'même',\n 'ici',\n 'là',\n 'cela',\n 'ceci',\n 'celui',\n 'celle',\n 'ceux',\n 'celles',\n 'rien',\n 'personne',\n 'quelque',\n 'quelques',\n 'plusieurs',\n 'beaucoup',\n 'être',\n 'avoir',\n 'faire',\n 'dire',\n 'venir',\n 'voir',\n 'vouloir',\n 'pouvoir',\n 'bonjour',\n 'monde',\n ],\n [Language.Spanish]: [\n 'el',\n 'la',\n 'los',\n 'las',\n 'un',\n 'una',\n 'unos',\n 'unas',\n 'y',\n 'o',\n 'que',\n 'en',\n 'de',\n 'a',\n 'por',\n 'con',\n 'no',\n 'es',\n 'son',\n 'para',\n 'como',\n 'su',\n 'sus',\n 'mi',\n 'mis',\n 'tu',\n 'tus',\n 'nuestro',\n 'nuestra',\n 'nuestros',\n 'nuestras',\n 'vuestro',\n 'vuestra',\n 'vuestros',\n 'vuestras',\n 'del',\n 'al',\n 'este',\n 'esta',\n 'estos',\n 'estas',\n 'ese',\n 'esa',\n 'esos',\n 'esas',\n 'aquel',\n 'aquella',\n 'aquellos',\n 'aquellas',\n 'pero',\n 'más',\n 'menos',\n 'mucho',\n 'muchos',\n 'mucha',\n 'muchas',\n 'poco',\n 'pocos',\n 'poca',\n 'pocas',\n 'algún',\n 'alguna',\n 'algunos',\n 'algunas',\n 'ningún',\n 'ninguna',\n 'ningunos',\n 'ningunas',\n 'otro',\n 'otra',\n 'otros',\n 'otras',\n 'mismo',\n 'misma',\n 'mismos',\n 'mismas',\n 'tan',\n 'tanto',\n 'tanta',\n 'tantos',\n 'tantas',\n 'así',\n 'también',\n 'solo',\n 'solamente',\n 'hola',\n 'mundo',\n ],\n [Language.German]: [\n 'der',\n 'die',\n 'das',\n 'ein',\n 'eine',\n 'einen',\n 'dem',\n 'den',\n 'des',\n 'einer',\n 'eines',\n 'und',\n 'ist',\n 'sind',\n 'war',\n 'waren',\n 'wird',\n 'werden',\n 'in',\n 'zu',\n 'mit',\n 'für',\n 'von',\n 'auf',\n 'als',\n 'um',\n 'an',\n 'aus',\n 'wie',\n 'bei',\n 'nach',\n 'bis',\n 'seit',\n 'vor',\n 'durch',\n 'über',\n 'unter',\n 'gegen',\n 'ohne',\n 'dass',\n 'weil',\n 'wenn',\n 'aber',\n 'oder',\n 'nur',\n 'noch',\n 'schon',\n 'auch',\n 'selbst',\n 'mir',\n 'dir',\n 'ihm',\n 'ihr',\n 'uns',\n 'euch',\n 'ihnen',\n 'mein',\n 'dein',\n 'sein',\n 'ihr',\n 'unser',\n 'euer',\n 'ihre',\n 'nicht',\n 'kein',\n 'keine',\n 'hallo',\n 'welt',\n ],\n [Language.Italian]: [\n 'il',\n 'lo',\n 'la',\n 'i',\n 'gli',\n 'le',\n 'un',\n 'uno',\n 'una',\n 'e',\n 'è',\n 'che',\n 'di',\n 'a',\n 'per',\n 'in',\n 'con',\n 'su',\n 'non',\n 'sono',\n 'ho',\n 'mi',\n 'ha',\n 'si',\n 'ti',\n 'ci',\n 'vi',\n 'lo',\n 'la',\n 'li',\n 'le',\n 'ne',\n 'mio',\n 'mia',\n 'miei',\n 'mie',\n 'tuo',\n 'tua',\n 'tuoi',\n 'tue',\n 'suo',\n 'sua',\n 'suoi',\n 'sue',\n 'nostro',\n 'nostra',\n 'nostri',\n 'nostre',\n 'vostro',\n 'vostra',\n 'vostri',\n 'vostre',\n 'loro',\n 'questo',\n 'questa',\n 'questi',\n 'queste',\n 'quello',\n 'quella',\n 'quelli',\n 'quelle',\n 'ma',\n 'più',\n 'meno',\n 'molto',\n 'molti',\n 'molta',\n 'molte',\n 'poco',\n 'pochi',\n 'poca',\n 'poche',\n 'grande',\n 'grandi',\n 'piccolo',\n 'piccoli',\n 'piccola',\n 'piccole',\n 'anche',\n 'ciao',\n 'mondo',\n ],\n [Language.Portuguese]: [\n 'o',\n 'a',\n 'os',\n 'as',\n 'um',\n 'uma',\n 'uns',\n 'umas',\n 'e',\n 'é',\n 'que',\n 'de',\n 'em',\n 'para',\n 'com',\n 'não',\n 'por',\n 'se',\n 'na',\n 'do',\n 'da',\n 'dos',\n 'das',\n 'no',\n 'nas',\n 'ao',\n 'aos',\n 'à',\n 'às',\n 'pelo',\n 'pela',\n 'pelos',\n 'pelas',\n 'este',\n 'esta',\n 'estes',\n 'estas',\n 'esse',\n 'essa',\n 'esses',\n 'essas',\n 'aquele',\n 'aquela',\n 'aqueles',\n 'aquelas',\n 'isto',\n 'isso',\n 'aquilo',\n 'meu',\n 'minha',\n 'meus',\n 'minhas',\n 'teu',\n 'tua',\n 'teus',\n 'tuas',\n 'seu',\n 'sua',\n 'seus',\n 'suas',\n 'nosso',\n 'nossa',\n 'nossos',\n 'nossas',\n 'vosso',\n 'vossa',\n 'vossos',\n 'vossas',\n 'dele',\n 'dela',\n 'deles',\n 'delas',\n 'nele',\n 'nela',\n 'neles',\n 'nelas',\n 'olá',\n 'mundo',\n ],\n [Language.Dutch]: [\n 'de',\n 'het',\n 'een',\n 'is',\n 'en',\n 'van',\n 'in',\n 'te',\n 'dat',\n 'op',\n 'voor',\n 'niet',\n 'met',\n 'zijn',\n 'worden',\n 'deze',\n 'dit',\n 'door',\n 'er',\n 'ook',\n 'als',\n 'aan',\n 'maar',\n 'bij',\n 'nog',\n 'om',\n 'uit',\n 'zo',\n 'dan',\n 'over',\n 'na',\n 'toen',\n 'tot',\n 'werd',\n 'wel',\n 'nu',\n 'je',\n 'jij',\n 'jou',\n 'jouw',\n 'ik',\n 'mij',\n 'mijn',\n 'hij',\n 'hem',\n 'zijn',\n 'zij',\n 'haar',\n 'we',\n 'wij',\n 'ons',\n 'onze',\n 'jullie',\n 'hun',\n 'hen',\n 'hallo',\n 'wereld',\n ],\n [Language.Unknown]: [],\n};\n\n// Common English words that should strongly bias toward English\nconst commonEnglishWords = new Set([\n 'hello',\n 'world',\n 'the',\n 'this',\n 'that',\n 'there',\n 'their',\n 'they',\n 'them',\n 'then',\n 'and',\n 'but',\n 'or',\n 'not',\n 'what',\n 'when',\n 'where',\n 'who',\n 'why',\n 'how',\n 'all',\n 'any',\n 'every',\n 'some',\n 'many',\n 'much',\n 'few',\n 'little',\n 'other',\n 'another',\n 'such',\n 'even',\n 'only',\n 'just',\n 'also',\n 'very',\n 'too',\n 'quite',\n 'rather',\n 'enough',\n]);\n\n// Cache for previously analyzed texts\nconst resultCache = new Map<string, LanguageDetectionResult>();\n\n// Normalizes a language profile for cosine similarity\nconst normalizedProfiles: Record<Language, Map<string, number>> = Object.entries(\n languageProfiles,\n).reduce(\n (acc, [lang, profile]) => {\n if (lang !== Language.Unknown) {\n // Calculate magnitude for normalization\n const entries = Object.entries(profile);\n const magnitude = Math.sqrt(entries.reduce((sum, [, value]) => sum + value * value, 0));\n\n // Create normalized map\n const normalizedMap = new Map<string, number>();\n entries.forEach(([char, value]) => {\n normalizedMap.set(char, value / magnitude);\n });\n\n acc[lang as Language] = normalizedMap;\n } else {\n acc[Language.Unknown] = new Map<string, number>();\n }\n return acc;\n },\n {} as Record<Language, Map<string, number>>,\n);\n\n// Handle very common language expressions directly\nconst commonPhrases = new Map([\n // English phrases\n ['hello world', Language.English],\n ['hello', Language.English],\n ['hi there', Language.English],\n ['good morning', Language.English],\n ['good evening', Language.English],\n ['good night', Language.English],\n ['thank you', Language.English],\n ['how are you', Language.English],\n ['nice to meet you', Language.English],\n\n // Spanish phrases\n ['hola mundo', Language.Spanish],\n ['hola', Language.Spanish],\n ['buenos días', Language.Spanish],\n ['buenas tardes', Language.Spanish],\n ['buenas noches', Language.Spanish],\n ['gracias', Language.Spanish],\n ['cómo estás', Language.Spanish],\n ['mucho gusto', Language.Spanish],\n\n // German phrases\n ['hallo welt', Language.German],\n ['hallo', Language.German],\n ['guten morgen', Language.German],\n ['guten tag', Language.German],\n ['guten abend', Language.German],\n ['danke', Language.German],\n ['wie geht es dir', Language.German],\n\n // French phrases\n ['bonjour le monde', Language.French],\n ['bonjour', Language.French],\n ['bonsoir', Language.French],\n ['merci', Language.French],\n ['comment allez-vous', Language.French],\n ['enchanté', Language.French],\n\n // Italian phrases\n ['ciao mondo', Language.Italian],\n ['ciao', Language.Italian],\n ['buongiorno', Language.Italian],\n ['buonasera', Language.Italian],\n ['grazie', Language.Italian],\n ['come stai', Language.Italian],\n ['piacere', Language.Italian],\n\n // Portuguese phrases\n ['olá mundo', Language.Portuguese],\n ['olá', Language.Portuguese],\n ['bom dia', Language.Portuguese],\n ['boa tarde', Language.Portuguese],\n ['boa noite', Language.Portuguese],\n ['obrigado', Language.Portuguese],\n ['como vai', Language.Portuguese],\n ['prazer em conhecê-lo', Language.Portuguese],\n\n // Dutch phrases\n ['hallo wereld', Language.Dutch],\n ['hallo', Language.Dutch],\n ['goedemorgen', Language.Dutch],\n ['goedemiddag', Language.Dutch],\n ['goedenavond', Language.Dutch],\n ['dank je', Language.Dutch],\n ['hoe gaat het', Language.Dutch],\n]);\n\n// Special handling for languages with unique characters\nconst uniqueChars: Partial<Record<Language, string[]>> = {\n [Language.German]: ['ä', 'ö', 'ü', 'ß'],\n [Language.French]: ['é', 'è', 'ê', 'ë', 'à', 'â', 'ù', 'û', 'î', 'ï', 'ô', 'œ', 'ç'],\n [Language.Spanish]: ['ñ', 'á', 'é', 'í', 'ó', 'ú', 'ü', '¿', '¡'],\n [Language.Italian]: ['à', 'è', 'é', 'ì', 'í', 'î', 'ò', 'ó', 'ù', 'ú'],\n [Language.Portuguese]: ['ã', 'õ', 'á', 'à', 'â', 'é', 'ê', 'í', 'ó', 'ô', 'ú', 'ç'],\n};\n\n/**\n * Detects the most likely language of a given text\n *\n * @param text The text to analyze\n * @param minLength Minimum text length for reliable detection (default: 4)\n * @param options Additional options for detection\n * @returns Language detection result with confidence score\n * @example\n * detectLanguage('Bonjour le monde'); // { language: 'French', ... }\n */\nexport function detectLanguage(\n text: string,\n minLength: number = 4,\n options: { maxCharsToAnalyze?: number; useCache?: boolean } = {\n maxCharsToAnalyze: 500,\n useCache: true,\n },\n): LanguageDetectionResult {\n const { maxCharsToAnalyze = 500, useCache = true } = options;\n\n // Caching shortcut\n if (useCache && resultCache.has(text)) {\n return resultCache.get(text)!;\n }\n\n // Empty string case\n if (!text || text.trim().length === 0) {\n return {\n language: Language.Unknown,\n confidence: 0,\n scores: Object.fromEntries(\n Object.values(Language).map((l) => [l, l === Language.Unknown ? 1 : 0]),\n ) as Record<Language, number>,\n };\n }\n\n const lowerText = text.toLowerCase().trim();\n\n // Phrase shortcut (exact match)\n if (commonPhrases.has(lowerText)) {\n const detected = commonPhrases.get(lowerText)!;\n const result: LanguageDetectionResult = {\n language: detected,\n confidence: 0.95,\n scores: Object.fromEntries(\n Object.values(Language).map((l) => [\n l,\n l === detected ? 0.95 : 0.05 / (Object.values(Language).length - 1),\n ]),\n ) as Record<Language, number>,\n };\n if (useCache) cacheResult(text, result);\n return result;\n }\n\n const isShort = text.length < minLength;\n const analyzedText = text.slice(0, maxCharsToAnalyze).toLowerCase().replace(/[0-9]/g, '');\n\n const charCount = new Map<string, number>();\n let totalChars = 0;\n\n const bigramSet = new Set([\n 'th',\n 'he',\n 'in',\n 'er',\n 'an',\n 'en',\n 'ch',\n 'de',\n 'ei',\n 'te',\n 'st',\n 'le',\n 'ou',\n 'qu',\n 'je',\n 'ai',\n 'ui',\n 'ie',\n 're',\n 'oo',\n ]);\n for (let i = 0; i < analyzedText.length; i++) {\n const char = analyzedText[i];\n if (/[a-zäöüßàáâéèêëïîìíñóòôùúûç]/i.test(char)) {\n charCount.set(char, (charCount.get(char) || 0) + 1);\n totalChars++;\n if (i < analyzedText.length - 1) {\n const bigram = analyzedText.substring(i, i + 2);\n if (bigramSet.has(bigram)) {\n charCount.set(bigram, (charCount.get(bigram) || 0) + 0.5);\n totalChars += 0.25;\n }\n }\n }\n }\n\n if (totalChars < 2) {\n return {\n language: Language.Unknown,\n confidence: 0.1,\n scores: Object.fromEntries(\n Object.values(Language).map((l) => [\n l,\n l === Language.Unknown ? 0.9 : 0.1 / (Object.values(Language).length - 1),\n ]),\n ) as Record<Language, number>,\n };\n }\n\n for (const [lang, chars] of Object.entries(uniqueChars)) {\n for (const char of chars) {\n if (analyzedText.includes(char)) {\n charCount.set('unique_' + lang, (charCount.get('unique_' + lang) || 0) + 18);\n totalChars += 3;\n }\n }\n }\n\n const words = analyzedText.split(/\\s+/);\n\n // Skip gibberish check if any language keyword is present\n const languageKeywords = [\n ['english', Language.English],\n ['deutsch', Language.German],\n ['german', Language.German],\n ['français', Language.French],\n ['french', Language.French],\n ['español', Language.Spanish],\n ['spanish', Language.Spanish],\n ['italiano', Language.Italian],\n ['italian', Language.Italian],\n ['português', Language.Portuguese],\n ['portuguese', Language.Portuguese],\n ['nederlands', Language.Dutch],\n ['dutch', Language.Dutch],\n ];\n const hasKeyword = languageKeywords.some(([kw]) => analyzedText.includes(kw));\n\n // Gibberish check: if no stopwords from any language and more than 2 words, return unknown\n if (!hasKeyword) {\n const stopwordHits = Object.values(Language)\n .filter((l) => l !== Language.Unknown)\n .some((lang) => words.some((word) => stopwords[lang].includes(word)));\n\n if (!stopwordHits && words.length > 2) {\n return {\n language: Language.Unknown,\n confidence: 0,\n scores: Object.fromEntries(\n Object.values(Language).map((l) => [l, l === Language.Unknown ? 1 : 0]),\n ) as Record<Language, number>,\n };\n }\n }\n\n for (const lang of Object.values(Language).filter((l) => l !== Language.Unknown)) {\n for (const word of words) {\n if (stopwords[lang].includes(word)) {\n const boost = lang === Language.English && commonEnglishWords.has(word) ? 36 : 28;\n charCount.set(`stopword_${lang}`, (charCount.get(`stopword_${lang}`) || 0) + boost);\n totalChars += 3;\n }\n }\n }\n\n const keywords = [\n ['english', Language.English],\n ['deutsch', Language.German],\n ['german', Language.German],\n ['français', Language.French],\n ['french', Language.French],\n ['español', Language.Spanish],\n ['spanish', Language.Spanish],\n ['italiano', Language.Italian],\n ['italian', Language.Italian],\n ['português', Language.Portuguese],\n ['portuguese', Language.Portuguese],\n ['nederlands', Language.Dutch],\n ['dutch', Language.Dutch],\n ];\n for (const [kw, lang] of keywords) {\n if (analyzedText.includes(kw)) {\n charCount.set(`keyword_${lang}`, (charCount.get(`keyword_${lang}`) || 0) + 70);\n totalChars += 8;\n }\n }\n\n const freqMap = normalizeVector(charCount);\n\n const scores: Record<Language, number> = {} as Record<Language, number>;\n let maxScore = 0;\n let detected: Language = Language.Unknown;\n\n for (const lang of Object.values(Language)) {\n if (lang === Language.Unknown) {\n scores[lang] = 0;\n continue;\n }\n\n const profile = normalizedProfiles[lang];\n let score = 0;\n\n for (const [token, normFreq] of freqMap.entries()) {\n if (token.startsWith(`unique_${lang}`)) score += normFreq * 2;\n else if (token.startsWith(`stopword_${lang}`)) score += normFreq * 3;\n else if (token.startsWith(`keyword_${lang}`)) score += normFreq * 5;\n else if (profile.has(token)) score += normFreq * profile.get(token)!;\n }\n\n scores[lang] = score;\n\n if (score > maxScore) {\n maxScore = score;\n detected = lang;\n }\n }\n\n // Set gibberish threshold to 0.4\n if (maxScore < 0.4) {\n detected = Language.Unknown;\n scores[Language.Unknown] = 1;\n }\n\n const sumScores = Object.values(scores).reduce((a, b) => a + b, 0);\n let confidence = sumScores > 0 ? maxScore / sumScores : 0;\n if (isShort) confidence *= 0.8;\n // For long texts, boost confidence\n if (analyzedText.length > 40) confidence = Math.min(confidence * 1.1, 1.0);\n confidence =\n confidence > 0.7 ? 0.95 : confidence > 0.55 ? 0.85 : confidence > 0.4 ? 0.7 : confidence;\n\n const result: LanguageDetectionResult = {\n language: detected,\n confidence,\n scores,\n };\n if (useCache) cacheResult(text, result);\n return result;\n}\n\n// --- UTILS ---\n\nfunction normalizeVector(map: Map<string, number>): Map<string, number> {\n const magnitude = Math.sqrt([...map.values()].reduce((sum, val) => sum + val * val, 0));\n const normMap = new Map<string, number>();\n for (const [key, val] of map.entries()) {\n normMap.set(key, val / magnitude);\n }\n return normMap;\n}\n\nfunction cacheResult(text: string, result: LanguageDetectionResult) {\n if (resultCache.size >= 100) {\n const firstKey = resultCache.keys().next().value;\n if (typeof firstKey === 'string') {\n resultCache.delete(firstKey);\n }\n }\n resultCache.set(text, result);\n}\n","import { regex } from '../assets/regex';\n\nconst { values } = regex;\n\n/**\n * Clear punctuations from a string and replaces it with a whitespace character or returns an array of strings.\n *\n * @param text String input to clear from punctuation.\n * @returns Either a string or an array of strings cleared from punctuations based on the arguments passed.\n * @example\n * clear('Hello, world!'); // 'hello world'\n */\n\nexport function clear(text: string): string {\n // Make sure there's an input\n if (!text) return 'Please provide a valid input text';\n\n // Create an array of words\n const wordsArray: string[] = text.split(values.punctuation);\n\n // Filter wordsArray and remove punctuations\n const clearWords = wordsArray.map((word) => {\n word = word.trim().toLowerCase().replace(values.punctuation, '');\n return word;\n });\n\n return clearWords.join(' ');\n}\n","import { clear } from './clear';\n\n/**\n * Return a boolean value number of the letters in a string.\n *\n * @param text String input to get letters count from.\n * @param countNumbers boolean value to determine if numbers should be counted as letters.\n *\n * @returns Number of letters and numbers (if requested) in a string.\n * @example\n * count('Hello, world!'); // 10\n * count('Hello0 world', true); // 11\n */\n\nexport function count(text: string, countNumbers = false): number {\n // Check string length\n if (!text.length) return 0;\n // Create a temp number.\n let temp = 0;\n // Clear the string and split the letters into an array.\n const cleared = clear(text).split('');\n // Loop through the letters array.\n cleared.forEach((letter) => {\n // Check if countNumbers is included\n if (!countNumbers) {\n // Count letters only\n if (!(/[a-z]/g.test(letter) || /[A-Z]/g.test(letter))) {\n return;\n }\n temp++;\n return;\n }\n // Count letters with numbers.\n if (!(/[a-z]/g.test(letter) || /[A-Z]/g.test(letter) || /[0-9]/g.test(letter))) return;\n temp++;\n });\n\n // Return the number of letters.\n return temp;\n}\n\n/**\n * Counts the number of words in a string.\n * Words are defined as sequences of letters, numbers, and apostrophes separated by whitespace.\n *\n * @param text String input to count words from\n * @returns Number of words in the string\n * @example\n * countWords('Hello, world!'); // 2\n */\nexport function countWords(text: string): number {\n if (!text?.trim()) return 0;\n\n // If the text contains only punctuation, return 0\n if (!/[a-zA-Z0-9]/.test(text)) return 0;\n\n return text\n .trim()\n .split(/\\s+/)\n .filter((word) => word.length > 0 && /[a-zA-Z0-9]/.test(word)).length;\n}\n\n/**\n * Counts the number of sentences in a string.\n * Sentences are defined as sequences of text ending with ., !, or ? followed by whitespace or end of string.\n * Text without any sentence-ending punctuation is considered to be a single sentence.\n *\n * @param text String input to count sentences from\n * @returns Number of sentences in the string\n * @example\n * countSentences('Hello world! How are you?'); // 2\n */\nexport function countSentences(text: string): number {\n if (!text?.trim()) return 0;\n\n // If there's no sentence-ending punctuation but there is text, it's considered one sentence\n if (!/[.!?]/.test(text) && text.trim().length > 0) return 1;\n\n return text\n .trim()\n .split(/[.!?]+(?=\\s|$)/)\n .filter((sentence) => sentence.trim().length > 0).length;\n}\n","import { count, countSentences, countWords } from '../count';\n\n/**\n * Text statistics interface containing various metrics about text\n */\nexport interface TextStatistics {\n /**\n * Total character count including whitespace and punctuation\n */\n characterCount: number;\n\n /**\n * Character count excluding whitespace\n */\n characterCountNoSpaces: number;\n\n /**\n * Letter count (only alphabetic characters)\n */\n letterCount: number;\n\n /**\n * Letter and number count (alphanumeric characters)\n */\n alphanumericCount: number;\n\n /**\n * Word count in the text\n */\n wordCount: number;\n\n /**\n * Sentence count in the text\n */\n sentenceCount: number;\n\n /**\n * Paragraph count in the text (separated by 2+ newlines)\n */\n paragraphCount: number;\n\n /**\n * Average word length in characters\n */\n averageWordLength: number;\n\n /**\n * Average sentence length in words\n */\n averageSentenceLength: number;\n\n /**\n * Estimated reading time in seconds (based on average reading speed)\n */\n readingTimeSeconds: number;\n\n /**\n * Estimated reading time as formatted string (e.g., \"2 min 30 sec\")\n */\n readingTimeFormatted: string;\n}\n\n/**\n * Analyzes text and returns comprehensive statistics about it\n *\n * @param text The text to analyze\n * @param wordsPerMinute Reading speed in words per minute (default: 200)\n * @returns TextStatistics object with various metrics\n * @example\n * getTextStats('Hello world! This is a test.');\n * // {\n * // characterCount: 28,\n * // characterCountNoSpaces: 24,\n * // letterCount: 20,\n * // alphanumericCount: 20,\n * // wordCount: 6,\n * // sentenceCount: 2,\n * // paragraphCount: 1,\n * // averageWordLength: 3.3,\n * // averageSentenceLength: 3,\n * // readingTimeSeconds: 2,\n * // readingTimeFormatted: '2 sec'\n * // }\n */\nexport function getTextStats(text: string, wordsPerMinute: number = 200): TextStatistics {\n // Handle empty input\n if (!text || !text.trim()) {\n return {\n characterCount: 0,\n characterCountNoSpaces: 0,\n letterCount: 0,\n alphanumericCount: 0,\n wordCount: 0,\n sentenceCount: 0,\n paragraphCount: 0,\n averageWordLength: 0,\n averageSentenceLength: 0,\n readingTimeSeconds: 0,\n readingTimeFormatted: '0 sec',\n };\n }\n\n // Basic counts\n const characterCount = text.length;\n const characterCountNoSpaces = text.replace(/\\s/g, '').length;\n const letterCount = count(text);\n const alphanumericCount = count(text, true);\n const wordCount = countWords(text);\n const sentenceCount = countSentences(text);\n\n // Paragraph count (separated by 2+ newlines)\n const paragraphCount = text.split(/\\n\\s*\\n/).filter((p) => p.trim().length > 0).length || 1;\n\n // Calculate averages - fix for more accurate calculation\n let totalWordLength = 0;\n const words = text.split(/\\s+/).filter((word) => word.length > 0);\n\n for (const word of words) {\n // Count only alphanumeric characters in words\n totalWordLength += word.replace(/[^a-zA-Z0-9]/g, '').length;\n }\n\n const averageWordLength = wordCount > 0 ? Math.round((totalWordLength / wordCount) * 10) / 10 : 0;\n\n const averageSentenceLength =\n sentenceCount > 0 ? Math.round((wordCount / sentenceCount) * 10) / 10 : 0;\n\n // Calculate reading time\n const wordsPerSecond = wordsPerMinute / 60;\n const readingTimeSeconds = Math.round(wordCount / wordsPerSecond);\n\n // Format reading time\n const readingTimeFormatted = formatReadingTime(readingTimeSeconds);\n\n return {\n characterCount,\n characterCountNoSpaces,\n letterCount,\n alphanumericCount,\n wordCount,\n sentenceCount,\n paragraphCount,\n averageWordLength,\n averageSentenceLength,\n readingTimeSeconds,\n readingTimeFormatted,\n };\n}\n\n/**\n * Formats reading time in seconds to a readable string\n *\n * @param seconds Total seconds\n * @returns Formatted string (e.g., \"2 min 30 sec\")\n */\nfunction formatReadingTime(seconds: number): string {\n if (seconds === 0) return '0 sec';\n\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = seconds % 60;\n\n if (minutes === 0) {\n return `${remainingSeconds} sec`;\n } else if (remainingSeconds === 0) {\n return `${minutes} min`;\n } else {\n return `${minutes} min ${remainingSeconds} sec`;\n }\n}\n","/**\n * Reverses all characters in a string.\n * @param text A string to reverse.\n * @returns Reversed string.\n * @example\n * reverse('Hello, world!'); // '!dlrow ,olleH'\n */\n\nexport function reverse(text: string) {\n // return type is inferred\n // Make sure input is valid\n if (!text) return 'Please provide a valid input text';\n // Split string into characters, reverse all of them and join them back together\n return text.split('').reverse().join('');\n}\n","/**\n * Returns an array of characters from the provided string.\n * @param text A string to spread.\n * @param clear Whether to clear punctuation from the text. Default is false.\n * @returns Array of characters or an error message.\n * @example\n * spread('Hello, world!'); // ['H', 'e', ...]\n * spread('Hello, world!', true); // ['H', 'e', ...]\n */\nimport { clear as clearText } from './clear';\n\nexport function spread(text: string, clear = false): string[] | string {\n // Check if clearing punctuation is necessary.\n if (clear) {\n text = clearText(text);\n }\n\n // Make sure input is valid.\n if (typeof text !== 'string') {\n return 'Input text should be a string!';\n }\n\n if (!text.trim()) {\n return 'Please provide a valid text input';\n }\n\n // Spread string into characters and return them in an array.\n const characters = [...(text.charAt(0).toLocaleUpperCase() + text.slice(1)).replace(/\\s/g, '')];\n\n return characters;\n}\n","/**\n * Validates if a string is a valid email address according to RFC 5322 standards.\n *\n * This function performs comprehensive validation including:\n * - Basic email structure (local part + @ + domain)\n * - Valid characters in local part and domain\n * - Domain must contain at least one dot\n * - No consecutive dots\n * - No trailing dots or hyphens\n * - Length limits (local part ≤ 64 chars, domain ≤ 255 chars)\n * - Non-ASCII character rejection\n *\n * @param text - The string to validate as an email address\n * @returns boolean indicating if the string is a valid email address\n *\n * @example\n * ```typescript\n * isEmail('user@example.com') // true\n * isEmail('user.name@example.com') // true\n * isEmail('user+tag@example.com') // true\n * isEmail('plainaddress') // false\n * isEmail('@example.com') // false\n * isEmail('user@') // false\n * ```\n */\nexport function isEmail(text: string): boolean {\n if (!text || typeof text !== 'string') {\n return false;\n }\n\n const email = text.trim();\n\n // Reject non-ASCII characters\n if (/[^\\x20-\\x7E]/.test(email)) {\n return false;\n }\n\n const emailRegex =\n /^(?!.*\\.{2})[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z]{2,}$/;\n\n if (!emailRegex.test(email)) {\n return false;\n }\n\n const [localPart, domain] = email.split('@');\n\n if (!localPart || !domain) return false;\n if (localPart.length > 64 || domain.length > 255) return false;\n if (domain.startsWith('-') || domain.endsWith('-')) return false;\n if (domain.startsWith('.') || domain.endsWith('.')) return false;\n\n return true;\n}\n","// Create digits in words\nconst numbers: string[] =\n 'zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen'.split(\n ' ',\n );\nconst tens: string[] = 'twenty thirty forty fifty sixty seventy eighty ninety'.split(' ');\n\n/**\n * Get any number below 100 million converted to words.\n * @param number Integer input to turn into text.\n * @returns A string of numbers converted to words.\n * @example\n * numbersToWords(12345); // 'twelve thousand three hundred and forty-five'\n */\nexport function numbersToWords(number: number): string {\n // Check if the number is less than 100 million\n if (number >= 100000000) {\n throw new Error('Please enter a number under 100 million!');\n }\n\n // Check if the input is between 0-19\n if (number < 20) return numbers[number];\n\n // Create a digit variable\n const digit: number = number % 10;\n\n // Check if the input is between 20-99\n if (number < 100) return tens[~~(number / 10) - 2] + (digit ? '-' + numbers[digit] : '');\n\n // Check if the input is between 100 and 999\n if (number < 1000)\n return (\n numbers[~~(number / 100)] +\n ' hundred' +\n (number % 100 == 0 ? '' : ' and ' + numbersToWords(number % 100))\n );\n\n // Check if the input is between 1,000 and 999,999\n if (number < 1000000) {\n const thousands = ~~(number / 1000);\n const remainder = number % 1000;\n\n return (\n numbersToWords(thousands) +\n ' thousand' +\n (remainder != 0 ? ' ' + numbersToWords(remainder) : '')\n );\n }\n\n // Handle millions (1,000,000 to 99,999,999)\n const millions = ~~(number / 1000000);\n const remainder = number % 1000000;\n\n return (\n numbersToWords(millions) + ' million' + (remainder != 0 ? ' ' + numbersToWords(remainder) : '')\n );\n}\n"],"names":["values","clear","clearText"],"mappings":"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