Browse Source

fix(compiler-sfc): skip circular tsconfig project reference (#11680)

Co-authored-by: cluezhang <cluezhang@futurefab.ai>

close #11382
cyrilluce 1 year ago
parent
commit
9c4c2e51b0

+ 43 - 0
packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts

@@ -1185,6 +1185,49 @@ describe('resolveType', () => {
       expect(deps && [...deps]).toStrictEqual(['/user.ts'])
     })
 
+    // #11382
+    test('ts module resolve circular project reference', () => {
+      const files = {
+        '/tsconfig.json': JSON.stringify({
+          exclude: ['**/*.ts', '**/*.vue'],
+          references: [
+            {
+              path: './tsconfig.web.json',
+            },
+          ],
+        }),
+        '/tsconfig.web.json': JSON.stringify({
+          include: ['**/*.ts', '**/*.vue'],
+          compilerOptions: {
+            composite: true,
+            paths: {
+              user: ['./user.ts'],
+            },
+          },
+          references: [
+            {
+              // circular reference
+              path: './tsconfig.json',
+            },
+          ],
+        }),
+        '/user.ts': 'export type User = { bar: string }',
+      }
+
+      const { props, deps } = resolve(
+        `
+        import { User } from 'user'
+        defineProps<User>() 
+        `,
+        files,
+      )
+
+      expect(props).toStrictEqual({
+        bar: ['String'],
+      })
+      expect(deps && [...deps]).toStrictEqual(['/user.ts'])
+    })
+
     test('ts module resolve w/ path aliased vue file', () => {
       const files = {
         '/tsconfig.json': JSON.stringify({

+ 4 - 2
packages/compiler-sfc/src/script/resolveType.ts

@@ -1070,6 +1070,7 @@ function loadTSConfig(
   configPath: string,
   ts: typeof TS,
   fs: FS,
+  visited = new Set<string>(),
 ): TS.ParsedCommandLine[] {
   // The only case where `fs` is NOT `ts.sys` is during tests.
   // parse config host requires an extra `readDirectory` method
@@ -1089,14 +1090,15 @@ function loadTSConfig(
     configPath,
   )
   const res = [config]
+  visited.add(configPath)
   if (config.projectReferences) {
     for (const ref of config.projectReferences) {
       const refPath = ts.resolveProjectReferencePath(ref)
-      if (!fs.fileExists(refPath)) {
+      if (visited.has(refPath) || !fs.fileExists(refPath)) {
         continue
       }
       tsConfigRefMap.set(refPath, configPath)
-      res.unshift(...loadTSConfig(refPath, ts, fs))
+      res.unshift(...loadTSConfig(refPath, ts, fs, visited))
     }
   }
   return res