fix(repository): make sure to escape newlines from git log so it doesnt break JSON parser
+ 56
- 35
@@ -1,5 +1,5 @@
 {
-  "_generatedAtUnix": 1663840840477,
+  "_generatedAtUnix": 1663840945689,
   "_hashAlgorithm": "sha1",
   "_version": 2,
   "islands": {

...
@@ -66,7 +66,7 @@
       "pathSource": "./app/views/repository/RepositoryBrowserView.tsx"
     },
     "RepositoryCommitsLogView": {
-      "hash": "9c2b20bc4bc30e627457e6d48b353ff0d9816b09",
+      "hash": "7182aef2cd68058c2994e84e8019f87be0ee313a",
       "pathSource": "./app/views/repository/RepositoryCommitsLogView.tsx"
     },
     "RepositoryCompareView": {

app/services/repository/getRepositoryCommitLog.ts
@@ -11,6 +11,9 @@ import { Env } from "../../env";
 import type { RepositoryLog } from "../../types";
 import type { RepositoryServiceDeps } from "./types";
 
+const GIT_LOG_NEWLINEW_FINDER_REGEXP =
+  /  \^@\^[a-z_]+\^@\^: \^@\^([^\^]+|)\^@\^,?/gim;
+
 const makeGetRepositoryCommitLog: ServiceMethodFactory<
   RepositoryServiceDeps,
   [Repository, string | undefined, string | undefined, boolean | undefined],

...
@@ -60,22 +63,42 @@ const makeGetRepositoryCommitLog: ServiceMethodFactory<
             reject(new Error(Buffer.from(data).toString("utf-8")));
           });
           gitLogProcess.stdout.on("close", () => {
-            const escapedJson = buffer
-              .join("")
-              .replace(/\n\^@\^/g, "\\n^@^") // Escape unterminated lines: \n^@\^ -> \\n^@\^
+            let escapedJson = buffer.join("");
+
+            const fieldsToEscape = escapedJson.match(
+              GIT_LOG_NEWLINEW_FINDER_REGEXP
+            );
+
+            if (fieldsToEscape != null && Array.isArray(fieldsToEscape)) {
+              fieldsToEscape.forEach((fieldTxt) => {
+                escapedJson = escapedJson.replace(
+                  fieldTxt,
+                  fieldTxt.split("\n").join("\\n") // Escape newlines
+                );
+              });
+            }
+
+            escapedJson = escapedJson
               .replace(/"/gm, '\\"') // Escape double-quotes: " -> \"
               .replace(/\^@\^/gm, '"'); // Escaped double-quotes back to double quotes
-            resolve(
-              JSON.parse(
-                `[${escapedJson.substring(0, escapedJson.length - 1)}]`
-              )
-            );
+
+            try {
+              resolve(
+                JSON.parse(
+                  `[${escapedJson.substring(0, escapedJson.length - 1)}]`
+                )
+              );
+            } catch (err) {
+              // console.log("escapedJson:", escapedJson);
+              reject(err);
+            }
           });
         }
       );
 
       return gitLogResult as RepositoryLog[];
     } catch (err) {
+      console.error("Cannot get git log", err);
       return [];
     }
   };

app/views/repository/RepositoryCommitsLogView.tsx
@@ -6,7 +6,7 @@ import React from "react";
 import type { Organization, Repository } from "@prisma/client";
 // app
 import type { CommonProps, RepositoryLog } from "../../types";
-import { Layout, PageWrapper } from "../../components";
+import { Card, Layout, PageWrapper } from "../../components";
 
 export interface RepositoryCommitsLogViewProps extends CommonProps {
   history: RepositoryLog[];

...
@@ -33,30 +33,28 @@ const RepositoryCommitsLogView: ReactView<RepositoryCommitsLogViewProps> = ({
           </a>
           {" / Commits"}
         </h1>
-        <div style={{ width: "100%" }}>
-          <ul>
-            {history.map((log) => (
-              <li key={log.tree}>
-                <a
-                  href={`/${parentOrg.slug}/${repo.slug}/compare/${log.abbreviated_parent}..${log.abbreviated_commit}`}
-                >
-                  <strong>{log.author.name}</strong>
-                  {" ∙ "}
-                  <span>{log.subject}</span>
-                  {" - "}
-                  <span>
-                    {log.abbreviated_commit}
-                    {log.abbreviated_parent.trim() != ""
-                      ? ` ∙ parent ${log.abbreviated_parent}`
-                      : ""}
-                  </span>
-                  {" ∙ "}
-                  <span>{new Date(log.author.date).toUTCString()}</span>
-                </a>
-              </li>
-            ))}
-          </ul>
-        </div>
+        <Card style={{ width: "100%" }} themeScheme={commonProps.themeScheme}>
+          {history.map((log) => (
+            <a
+              key={log.tree}
+              href={`/${parentOrg.slug}/${repo.slug}/compare/${log.abbreviated_parent}..${log.abbreviated_commit}`}
+              style={{ marginTop: 8 }}
+            >
+              <strong>{log.author.name}</strong>
+              {" ∙ "}
+              <span>{log.subject}</span>
+              {" - "}
+              <span>
+                {log.abbreviated_commit}
+                {log.abbreviated_parent.trim() != ""
+                  ? ` ∙ parent ${log.abbreviated_parent}`
+                  : ""}
+              </span>
+              {" ∙ "}
+              <span>{new Date(log.author.date).toUTCString()}</span>
+            </a>
+          ))}
+        </Card>
       </PageWrapper>
     </Layout>
   );