Skip to content

Removing comments from TSConfig fails for path aliases #1483

Description

@sievins

Description

(PS - thanks for building Graffle!)

If you have path aliases in tsconfig.json then the graffle CLI can't parse the JSON, because the code to remove multiline comments thinks the alias is a comment.

tsconfig.json example:

{
  "compilerOptions": {
    /* Other config... */
    "baseUrl": ".",
    "paths": {
      "~/*": ["./src/*"]
    }
  }
}

Result:

> bun graffle --schema https://countries.trevorblades.com/graphql
Could not parse tsconfig.json (may contain syntax not supported by simple parser)

I created this patch which fixes it and uses a more robust method to strip comments:

diff --git a/build/generator/validation/graphqlsp.js b/build/generator/validation/graphqlsp.js
index 030b2ce271b424bec7a8b2f7e8e37fe163b692a6..58cc51e00c38f0af542e86fcea5276a37098b48f 100644
--- a/build/generator/validation/graphqlsp.js
+++ b/build/generator/validation/graphqlsp.js
@@ -2,6 +2,71 @@ import { FileSystem } from '@effect/platform';
 import { Fs } from '@wollybeard/kit';
 import { Effect } from 'effect';
 import { Config } from '../config/_.js';
+function stripJsoncComments(input) {
+  let out = "";
+  let i = 0;
+  let inString = false;
+  let escaped = false;
+  let inLineComment = false;
+  let inBlockComment = false;
+  while (i < input.length) {
+    const c = input[i];
+    const n = input[i + 1];
+    // End line comment
+    if (inLineComment) {
+      if (c === "\n") {
+        inLineComment = false;
+        out += c;
+      }
+      i++;
+      continue;
+    }
+    // End block comment
+    if (inBlockComment) {
+      if (c === "*" && n === "/") {
+        inBlockComment = false;
+        i += 2;
+        continue;
+      }
+      i++;
+      continue;
+    }
+    // Inside string
+    if (inString) {
+      out += c;
+      if (escaped) {
+        escaped = false;
+      } else if (c === "\\") {
+        escaped = true;
+      } else if (c === '"') {
+        inString = false;
+      }
+      i++;
+      continue;
+    }
+    // Start string
+    if (c === '"') {
+      inString = true;
+      out += c;
+      i++;
+      continue;
+    }
+    // Start comments (only when NOT in a string)
+    if (c === "/" && n === "/") {
+      inLineComment = true;
+      i += 2;
+      continue;
+    }
+    if (c === "/" && n === "*") {
+      inBlockComment = true;
+      i += 2;
+      continue;
+    }
+    out += c;
+    i++;
+  }
+  return out;
+}
 /**
  * Validates GraphQLSP configuration and provides helpful warnings/suggestions.
  *
@@ -81,9 +146,7 @@ To disable this check: set lint.missingGraphqlSP: false in graffle.config.ts
     let tsconfig;
     try {
         // Remove comments (simple approach - good enough for most tsconfigs)
-        const jsonWithoutComments = tsconfigContent
-            .replace(/\/\/.*$/gm, '') // Remove single-line comments
-            .replace(/\/\*[\s\S]*?\*\//g, ''); // Remove multi-line comments
+        const jsonWithoutComments = stripJsoncComments(tsconfigContent);
         tsconfig = JSON.parse(jsonWithoutComments);
     }
     catch {
diff --git a/src/generator/validation/graphqlsp.ts b/src/generator/validation/graphqlsp.ts
index 7c61f7765e189b8f0321cc43b6499b7f80fb1f08..def11e3d6bced7d316acd2085da4a601961b1357 100644
--- a/src/generator/validation/graphqlsp.ts
+++ b/src/generator/validation/graphqlsp.ts
@@ -4,6 +4,84 @@ import { Fs } from '@wollybeard/kit'
 import { Effect } from 'effect'
 import { Config } from '../config/_.js'
 
+function stripJsoncComments(input: string): string {
+  let out = "";
+  let i = 0;
+
+  let inString = false;
+  let escaped = false;
+  let inLineComment = false;
+  let inBlockComment = false;
+
+  while (i < input.length) {
+    const c = input[i]!;
+    const n = input[i + 1];
+
+    // End line comment
+    if (inLineComment) {
+      if (c === "\n") {
+        inLineComment = false;
+        out += c;
+      }
+      i++;
+      continue;
+    }
+
+    // End block comment
+    if (inBlockComment) {
+      if (c === "*" && n === "/") {
+        inBlockComment = false;
+        i += 2;
+        continue;
+      }
+      i++;
+      continue;
+    }
+
+    // Inside string
+    if (inString) {
+      out += c;
+
+      if (escaped) {
+        escaped = false;
+      } else if (c === "\\") {
+        escaped = true;
+      } else if (c === '"') {
+        inString = false;
+      }
+
+      i++;
+      continue;
+    }
+
+    // Start string
+    if (c === '"') {
+      inString = true;
+      out += c;
+      i++;
+      continue;
+    }
+
+    // Start comments (only when NOT in a string)
+    if (c === "/" && n === "/") {
+      inLineComment = true;
+      i += 2;
+      continue;
+    }
+
+    if (c === "/" && n === "*") {
+      inBlockComment = true;
+      i += 2;
+      continue;
+    }
+
+    out += c;
+    i++;
+  }
+
+  return out;
+}
+
 /**
  * Validates GraphQLSP configuration and provides helpful warnings/suggestions.
  *
@@ -97,9 +175,7 @@ To disable this check: set lint.missingGraphqlSP: false in graffle.config.ts
     let tsconfig: any
     try {
       // Remove comments (simple approach - good enough for most tsconfigs)
-      const jsonWithoutComments = tsconfigContent
-        .replace(/\/\/.*$/gm, '') // Remove single-line comments
-        .replace(/\/\*[\s\S]*?\*\//g, '') // Remove multi-line comments
+      const jsonWithoutComments = stripJsoncComments(tsconfigContent);
 
       tsconfig = JSON.parse(jsonWithoutComments)
     } catch {

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions