import LanguageDetect from 'languagedetect'; import {languages} from 'prismjs/components'; const RESOLVED_ALIASES = Object.fromEntries( Object .entries(languages) .reduce( (resolved, [languageId, languageDefinition]) => { if (Array.isArray(languageDefinition.alias)) { return [ ...resolved, ...(languageDefinition.alias.map((a: string) => [a, { aliasOf: languageId, title: languageDefinition.title, extension: `.${a}`} ])), [languageId, { title: languageDefinition.title, extension: `.${languageId}`}], ]; } if (typeof languageDefinition.alias === 'string') { return [ ...resolved, [languageDefinition.alias, { aliasOf: languageId, title: languageDefinition.title, extension: `.${languageDefinition.alias}`}], [languageId, { title: languageDefinition.title, extension: `.${languageId}`}], ]; } return [ ...resolved, [languageId, { title: languageDefinition.title, extension: `.${languageId}`}], ]; }, [] as [string, { aliasOf?: string, title: string, extension: string }][] ) ); type Language = string; type LanguageProbability = number; type LanguageMatch = [Language, LanguageProbability]; export interface TextMetadata { contents?: string; scheme?: string; schemeTitle?: string; languageMatches?: LanguageMatch[]; lineCount?: number; linesOfCode?: number; } const countLinesOfCode = (lines: string[], scheme: string): number => { // TODO count loc depending on scheme //return lines.filter((line) => !line.trim().startsWith('//')).length; return lines.filter((line) => line.trim().length > 0).length; }; export const getTextMetadata = (contents: string, filename?: string): Promise => { const lineNormalizedContents = contents.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); const lines = lineNormalizedContents.split('\n'); const lineCount = lines.length; const metadata = Object.entries(RESOLVED_ALIASES).reduce( (theMetadata, [key, value]) => { if (typeof theMetadata.scheme === 'undefined' && filename?.endsWith(value.extension)) { if (value.aliasOf) { return { ...theMetadata, scheme: value.aliasOf, schemeTitle: value.title, linesOfCode: countLinesOfCode(lines, value.aliasOf), }; } return { ...theMetadata, scheme: key, schemeTitle: value.title, linesOfCode: countLinesOfCode(lines, key), }; } return theMetadata; }, { contents, lineCount, } as TextMetadata, ); if (typeof metadata.scheme !== 'string') { const naturalLanguageDetector = new LanguageDetect(); metadata.languageMatches = naturalLanguageDetector.detect(contents); } return Promise.resolve(metadata); };