Przeglądaj źródła

Merge pull request #7060 from overleaf/ii-5273-latex-log-parsers

Clean up log parsers code

GitOrigin-RevId: 7dc4dbbb07bba72dda63d75502602570620fe07d
ilkin-overleaf 4 lat temu
rodzic
commit
be0774be8f

+ 22 - 46
services/web/frontend/js/ide/log-parser/bib-log-parser.js

@@ -18,32 +18,21 @@ const MESSAGE_LEVELS = {
   ERROR: 'error',
 }
 
-const parserReducer = function (maxErrors, buildMaxErrorsReachedMessage) {
+const parserReducer = function (maxErrors) {
   return function (accumulator, parser) {
     const consume = function (logText, regex, process) {
       let match
       let text = logText
       const result = []
-      const re = regex
       let iterationCount = 0
-      while ((match = re.exec(text))) {
-        iterationCount += 1
+
+      while ((match = regex.exec(text))) {
+        iterationCount++
         const newEntry = process(match)
 
         // Too many log entries can cause browser crashes
         // Construct a too many files error from the last match
         if (maxErrors != null && iterationCount >= maxErrors) {
-          if (buildMaxErrorsReachedMessage) {
-            const level = newEntry.level + 's'
-            newEntry.message = [
-              'Over',
-              maxErrors,
-              level,
-              'returned. Download raw logs to see full list',
-            ].join(' ')
-            newEntry.line = undefined
-            result.unshift(newEntry)
-          }
           return [result, '']
         }
 
@@ -55,6 +44,7 @@ const parserReducer = function (maxErrors, buildMaxErrorsReachedMessage) {
             match.input.length
           )
       }
+
       return [result, text]
     }
 
@@ -66,12 +56,12 @@ const parserReducer = function (maxErrors, buildMaxErrorsReachedMessage) {
 }
 
 export default class BibLogParser {
-  constructor(text, options) {
+  constructor(text, options = {}) {
     if (typeof text !== 'string') {
       throw new Error('BibLogParser Error: text parameter must be a string')
     }
     this.text = text.replace(/(\r\n)|\r/g, '\n')
-    this.options = options || {}
+    this.options = options
     this.lines = text.split('\n')
 
     // each parser is a pair of [regex, processFunction], where processFunction
@@ -163,33 +153,23 @@ export default class BibLogParser {
   }
 
   parseBibtex() {
-    let allErrors
-    const result = {
-      all: [],
-      errors: [],
-      warnings: [],
-      files: [], // not used
-      typesetting: [], // not used
-    }
     // reduce over the parsers, starting with the log text,
-    let [allWarnings, remainingText] = this.warningParsers.reduce(
-      parserReducer(
-        this.options.maxErrors,
-        this.options.buildMaxErrorsReachedMessage
-      ),
+    const [allWarnings, remainingText] = this.warningParsers.reduce(
+      parserReducer(this.options.maxErrors),
       [[], this.text]
     )
-    ;[allErrors, remainingText] = this.errorParsers.reduce(
-      parserReducer(
-        this.options.maxErrors,
-        this.options.buildMaxErrorsReachedMessage
-      ),
+    const [allErrors] = this.errorParsers.reduce(
+      parserReducer(this.options.maxErrors),
       [[], remainingText]
     )
-    result.warnings = allWarnings
-    result.errors = allErrors
-    result.all = allWarnings.concat(allErrors)
-    return result
+
+    return {
+      all: allWarnings.concat(allErrors),
+      errors: allErrors,
+      warnings: allWarnings,
+      files: [], // not used
+      typesetting: [], // not used
+    }
   }
 
   parseBiber() {
@@ -203,9 +183,7 @@ export default class BibLogParser {
     this.lines.forEach(function (line) {
       const match = line.match(LINE_SPLITTER_REGEX)
       if (match) {
-        const fullLine = match[0]
-        const messageType = match[2]
-        const message = match[3]
+        const [fullLine, , messageType, message] = match
         const newEntry = {
           file: '',
           level: MESSAGE_LEVELS[messageType] || 'INFO',
@@ -218,10 +196,8 @@ export default class BibLogParser {
         const lineMatch = newEntry.message.match(
           /^BibTeX subsystem: \/.+\/(\w+\.\w+)_.+, line (\d+), (.+)$/
         )
-        if (lineMatch && lineMatch.length === 4) {
-          const fileName = lineMatch[1]
-          const lineNumber = lineMatch[2]
-          const realMessage = lineMatch[3]
+        if (lineMatch) {
+          const [, fileName, lineNumber, realMessage] = lineMatch
           newEntry.file = fileName
           newEntry.line = lineNumber
           newEntry.message = realMessage

+ 45 - 43
services/web/frontend/js/ide/log-parser/latex-log-parser.js

@@ -15,9 +15,8 @@ const STATE = {
 }
 
 export default class LatexParser {
-  constructor(text, options) {
+  constructor(text, options = {}) {
     this.state = STATE.NORMAL
-    options = options || {}
     this.fileBaseNames = options.fileBaseNames || [/compiles/, /\/usr\/local/]
     this.ignoreDuplicates = options.ignoreDuplicates
     this.data = []
@@ -159,10 +158,10 @@ export default class LatexParser {
   parseMultipleWarningLine() {
     // Some package warnings are multiple lines, let's parse the first line
     let warningMatch = this.currentLine.match(PACKAGE_WARNING_REGEX)
+    // Something strange happened, return early
     if (!warningMatch) {
       return
     }
-    // Something strange happened, return early
     const warningLines = [warningMatch[1]]
     let lineMatch = this.currentLine.match(LINES_REGEX)
     let line = lineMatch ? parseInt(lineMatch[1], 10) : null
@@ -285,62 +284,60 @@ export default class LatexParser {
 
   postProcess(data) {
     const all = []
-    const errors = []
-    const warnings = []
-    const typesetting = []
-    const hashes = []
+    const errorsByLevel = {
+      error: [],
+      warning: [],
+      typesetting: [],
+    }
+    const hashes = new Set()
 
     const hashEntry = entry => entry.raw
 
-    let i = 0
-    while (i < data.length) {
-      if (this.ignoreDuplicates && hashes.indexOf(hashEntry(data[i])) > -1) {
-        i++
-        continue
-      }
-      if (data[i].level === 'error') {
-        errors.push(data[i])
-      } else if (data[i].level === 'typesetting') {
-        typesetting.push(data[i])
-      } else if (data[i].level === 'warning') {
-        warnings.push(data[i])
+    data.forEach(item => {
+      const hash = hashEntry(item)
+
+      if (this.ignoreDuplicates && hashes.has(hash)) {
+        return
       }
-      all.push(data[i])
-      hashes.push(hashEntry(data[i]))
-      i++
-    }
+
+      errorsByLevel[item.level]?.push(item)
+
+      all.push(item)
+      hashes.add(hash)
+    })
+
     return {
-      errors,
-      warnings,
-      typesetting,
+      errors: errorsByLevel.error,
+      warnings: errorsByLevel.warning,
+      typesetting: errorsByLevel.typesetting,
       all,
       files: this.rootFileList,
     }
   }
 }
 
-const LogText = class LogText {
+class LogText {
   constructor(text) {
     this.text = text.replace(/(\r\n)|\r/g, '\n')
     // Join any lines which look like they have wrapped.
     const wrappedLines = this.text.split('\n')
     this.lines = [wrappedLines[0]]
-    let i = 1
-    while (i < wrappedLines.length) {
+
+    for (let i = 1; i < wrappedLines.length; i++) {
       // If the previous line is as long as the wrap limit then
       // append this line to it.
       // Some lines end with ... when LaTeX knows it's hit the limit
       // These shouldn't be wrapped.
-      if (
-        wrappedLines[i - 1].length === LOG_WRAP_LIMIT &&
-        wrappedLines[i - 1].slice(-3) !== '...'
-      ) {
-        this.lines[this.lines.length - 1] += wrappedLines[i]
+      const prevLine = wrappedLines[i - 1]
+      const currentLine = wrappedLines[i]
+
+      if (prevLine.length === LOG_WRAP_LIMIT && prevLine.slice(-3) !== '...') {
+        this.lines[this.lines.length - 1] += currentLine
       } else {
-        this.lines.push(wrappedLines[i])
+        this.lines.push(currentLine)
       }
-      i++
     }
+
     this.row = 0
   }
 
@@ -363,16 +360,21 @@ const LogText = class LogText {
 
   linesUpToNextMatchingLine(match) {
     const lines = []
-    let nextLine = this.nextLine()
-    if (nextLine !== false) {
+
+    while (true) {
+      const nextLine = this.nextLine()
+
+      if (nextLine === false) {
+        break
+      }
+
       lines.push(nextLine)
-    }
-    while (nextLine !== false && !nextLine.match(match) && nextLine !== false) {
-      nextLine = this.nextLine()
-      if (nextLine !== false) {
-        lines.push(nextLine)
+
+      if (nextLine.match(match)) {
+        break
       }
     }
+
     return lines
   }
 }