UNPKG

@lobehub/editor

Version:

A powerful and extensible rich text editor built on Meta's Lexical framework, providing a modern editing experience with React integration.

267 lines (254 loc) 8.73 kB
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } /** * Language detection utility for code snippets * Uses pattern matching and heuristics to identify programming languages */ var LANGUAGE_PATTERNS = { // Shell/Config bash: { optional: [/\|\||&&/, /echo\s+/, /if\s+\[/], required: [/^#!\/bin\/(ba)?sh/, /\${?\w+}?/], weight: 7 }, csharp: { optional: [/\[.*]/, /async\s+Task/, /var\s+\w+\s*=/], required: [/(public|private|protected)\s+(class|interface|namespace)/, /using\s+\w+/], weight: 8 }, css: { optional: [/@media|@import|@keyframes/, /!important/], required: [/[#.]?[\w-]+\s*{/, /:\s*[\w#%-]+;/], weight: 8 }, dockerfile: { required: [/^FROM\s+/, /^(RUN|CMD|COPY|ADD|WORKDIR|ENV|EXPOSE)\s+/m], weight: 10 }, go: { optional: [/import\s+\(/, /:=/, /defer|goroutine/], required: [/package\s+\w+/, /func\s+\w+/], weight: 8 }, graphql: { optional: [/fragment\s+/, /on\s+\w+/], required: [/(query|mutation|subscription)\s+/, /{[\S\s]*}/], weight: 8 }, // Web languages html: { optional: [/<\/\w+>/, /class=|id=/], required: [/<(html|head|body|div|span|p|a|img|script|style|link|meta)/i], weight: 9 }, ini: { exclude: [/^\s*</, /{.*}/], required: [/^\[.*]$/m, /\w+\s*=\s*/], weight: 6 }, java: { optional: [/@Override|@Autowired/, /extends|implements/, /System\.out/], required: [/(public|private|protected)\s+(class|interface|static)/, /\w+\s+\w+\s*\([^)]*\)\s*{/], weight: 8 }, // JavaScript family javascript: { exclude: [/^\s*</, /interface\s+\w+/, /:\s*\w+\s*[;=]/], optional: [/=>\s*{/, /console\.(log|error|warn)/, /\.then\(/, /require\(/], required: [/(function|const|let|var|class|import|export|async|await)\s/], weight: 7 }, // Data formats json: { optional: [/"[^"]*"\s*:/, /:\s*["'[{]/], required: [/^\s*[[{]/, /[\]}]\s*$/], weight: 10 }, jsx: { exclude: [/^\s*<!DOCTYPE/, /^\s*<html/], optional: [/className=/, /{.*}/, /import.*from/], required: [/<\w+[^>]*>/, /(const|function|class)\s+\w+/], weight: 8 }, makefile: { optional: [/\$\(.*\)/, /\.PHONY/], required: [/^[\w-]+:\s*/, /^\t/m], weight: 7 }, // Other common languages markdown: { optional: [/```/, /\*\*.*\*\*/, /^\s*[*+-]\s+/m], required: [/^#{1,6}\s+/, /\[.*]\(.*\)/], weight: 6 }, php: { optional: [/function\s+\w+/, /class\s+\w+/, /echo|print/], required: [/<\?php/, /\$\w+/], weight: 10 }, powershell: { optional: [/\|\s*Where/, /\|\s*Select/, /param\(/], required: [/\$\w+/, /(Get|Set|New|Remove)-\w+/], weight: 8 }, // Backend languages python: { optional: [/if __name__|print\(/, /self\.|lambda/, /@\w+\s*$/m], required: [/(def|class|import|from)\s+\w+/, /:\s*$/m], weight: 8 }, ruby: { optional: [/do\s*\|.*\|/, /puts|require/, /:\w+\s*=>/], required: [/(def|class|module|end)\s/, /@\w+/], weight: 7 }, rust: { optional: [/::\w+/, /&mut|&str/, /#\[derive\(/], required: [/(fn|struct|impl|trait|use)\s+/, /let\s+(mut\s+)?\w+/], weight: 8 }, scss: { optional: [/@mixin|@include|@extend/, /#{.*}/], required: [/\$[\w-]+\s*:/, /[&@]\w+/], weight: 8 }, // Database sql: { optional: [/from|where|join|group by|order by/i, /\*/], required: [/(select|insert|update|delete|create|alter|drop)\s+/i], weight: 9 }, // Config formats toml: { optional: [/\[\[.*]]/, /"""[\S\s]*"""/], required: [/^\[.*]$/m, /\w+\s*=\s*[\w"']/], weight: 8 }, tsx: { optional: [/:\s*React\./, /:\s*FC</, /useState|useEffect/], required: [/<\w+[^>]*>/, /interface|type\s+\w+/], weight: 9 }, typescript: { optional: [/<\w+>/, /as\s+\w+/, /implements|extends/], required: [/(interface|type|enum)\s+\w+/, /:\s*\w+(\[]|<.+>)?\s*[);=]/], weight: 8 }, xml: { optional: [/<\/\w+>/, /xmlns/], required: [/<\?xml|<\w+[^>]*>/], weight: 9 }, yaml: { exclude: [/^\s*[[\]{]/], required: [/^[\s-]*\w+:\s*/, /^[\s-]*-\s+/m], weight: 8 } }; /** * Detect the programming language of a code snippet * @param code - The code snippet to analyze * @returns Language detection result with confidence score */ export function detectLanguage(code) { if (!code || code.trim().length === 0) { return null; } var trimmed = code.trim(); var scores = {}; // Test each language pattern for (var _i = 0, _Object$entries = Object.entries(LANGUAGE_PATTERNS); _i < _Object$entries.length; _i++) { var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), language = _Object$entries$_i[0], pattern = _Object$entries$_i[1]; var score = 0; var baseWeight = pattern.weight || 5; // Check exclude patterns first if (pattern.exclude) { var hasExclude = pattern.exclude.some(function (regex) { return regex.test(trimmed); }); if (hasExclude) { continue; // Skip this language } } // Check required patterns if (pattern.required) { var allRequired = pattern.required.every(function (regex) { return regex.test(trimmed); }); if (!allRequired) { continue; // All required patterns must match } score += baseWeight * 2; // Strong indicator } // Check optional patterns if (pattern.optional) { var matchedOptional = pattern.optional.filter(function (regex) { return regex.test(trimmed); }).length; score += matchedOptional * baseWeight; } if (score > 0) { scores[language] = score; } } // Find language with highest score var entries = Object.entries(scores); if (entries.length === 0) { return null; } entries.sort(function (a, b) { return b[1] - a[1]; }); var _entries$ = _slicedToArray(entries[0], 2), topLanguage = _entries$[0], topScore = _entries$[1]; // Calculate confidence (0-100) var maxPossibleScore = (LANGUAGE_PATTERNS[topLanguage].weight || 5) * 5; var confidence = Math.min(100, Math.round(topScore / maxPossibleScore * 100)); // Only return if confidence is high enough if (confidence < 30) { return null; } return { confidence: confidence, language: topLanguage }; } /** * Simple detection for common formats with high confidence * Falls back to detectLanguage for more complex detection */ export function detectCodeLanguage(code) { var trimmed = code.trim(); // Fast path for JSON if (trimmed.startsWith('{') && trimmed.endsWith('}') || trimmed.startsWith('[') && trimmed.endsWith(']')) { try { JSON.parse(trimmed); return 'json'; } catch (_unused) { // Not valid JSON } } // Fast path for common patterns if (/^\s*(select|insert|update|delete|create|alter|drop)\s+/i.test(code)) { return 'sql'; } if (/^<\?xml/i.test(code)) { return 'xml'; } if (/^FROM\s+|^RUN\s+|^CMD\s+/m.test(code)) { return 'dockerfile'; } if (/<\?php/.test(code)) { return 'php'; } // Use pattern matching for complex detection var result = detectLanguage(code); return result && result.confidence > 50 ? result.language : null; }