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 {

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions