HumanReadableLogs.ts 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import LatexLogParser, {
  2. LatexParserOptions,
  3. ParseResult,
  4. } from '../log-parser/latex-log-parser'
  5. import ruleset from './HumanReadableLogsRules'
  6. export default {
  7. parse(rawLog: string | ParseResult, options: LatexParserOptions) {
  8. const parsedLogEntries =
  9. typeof rawLog === 'string'
  10. ? new LatexLogParser(rawLog, options).parse()
  11. : rawLog
  12. const seenErrorTypes: Record<string, boolean> = {} // keep track of types of errors seen
  13. for (const entry of parsedLogEntries.all) {
  14. const ruleDetails = ruleset.find(rule =>
  15. rule.regexToMatch.test(entry.message)
  16. )
  17. if (ruleDetails) {
  18. if (ruleDetails.ruleId) {
  19. entry.ruleId = ruleDetails.ruleId
  20. }
  21. if (ruleDetails.newMessage) {
  22. entry.message = entry.message.replace(
  23. ruleDetails.regexToMatch,
  24. ruleDetails.newMessage
  25. )
  26. }
  27. if (ruleDetails.contentRegex) {
  28. if (entry.content != null) {
  29. const match = entry.content.match(ruleDetails.contentRegex)
  30. if (match) {
  31. entry.contentDetails = match.slice(1)
  32. }
  33. }
  34. }
  35. if (entry.contentDetails && ruleDetails.improvedTitle) {
  36. const message = ruleDetails.improvedTitle(
  37. entry.message,
  38. entry.contentDetails
  39. )
  40. if (Array.isArray(message)) {
  41. entry.message = message[0]
  42. // removing the messageComponent, as the markup possible in it was causing crashes when
  43. // attempting to broadcast it in the detach-context (cant structuredClone an html node)
  44. // see https://github.com/overleaf/internal/discussions/15031 for context
  45. // entry.messageComponent = message[1]
  46. } else {
  47. entry.message = message
  48. }
  49. }
  50. if (entry.contentDetails && ruleDetails.highlightCommand) {
  51. entry.command = ruleDetails.highlightCommand(entry.contentDetails)
  52. }
  53. // suppress any entries that are known to cascade from previous error types
  54. if (ruleDetails.cascadesFrom) {
  55. for (const type of ruleDetails.cascadesFrom) {
  56. if (seenErrorTypes[type]) {
  57. entry.suppressed = true
  58. }
  59. }
  60. }
  61. // record the types of errors seen
  62. if (ruleDetails.types) {
  63. for (const type of ruleDetails.types) {
  64. seenErrorTypes[type] = true
  65. }
  66. }
  67. }
  68. }
  69. // filter out the suppressed errors (from the array entries in parsedLogEntries)
  70. for (const type of ['errors', 'warnings', 'typesetting'] as const) {
  71. const errors = parsedLogEntries[type]
  72. if (Array.isArray(errors) && errors.length > 0) {
  73. parsedLogEntries[type] = Array.from(errors).filter(
  74. err => !err.suppressed
  75. )
  76. }
  77. }
  78. return parsedLogEntries
  79. },
  80. }