Преглед изворни кода

fix(patchTypes): improve export removal logic and clean up code

daiwei пре 2 месеци
родитељ
комит
ec6f40d766
1 измењених фајлова са 62 додато и 29 уклоњено
  1. 62 29
      rolldown.dts.config.js

+ 62 - 29
rolldown.dts.config.js

@@ -75,9 +75,8 @@ export default targetPackages.map(
 function patchTypes(pkg) {
   return {
     name: 'patch-types',
-    // @ts-ignore
     renderChunk(code, chunk, outputOptions, meta) {
-      const s = meta?.magicString
+      const s = meta.magicString
       const { program: ast, errors } = parseSync('x.d.ts', code, {
         sourceType: 'module',
       })
@@ -155,50 +154,84 @@ function patchTypes(pkg) {
       // pass 2: remove exports
       for (const node of ast.body) {
         if (node.type === 'ExportNamedDeclaration' && !node.source) {
-          let removed = 0
+          // Precompute which specifiers are safe to remove.
+          /** @type {boolean[]} */
+          const removable = new Array(node.specifiers.length)
+          let keptCount = 0
           for (let i = 0; i < node.specifiers.length; i++) {
             const spec = node.specifiers[i]
             const localName =
               'name' in spec.local ? spec.local.name : spec.local.value
+            let canRemove = false
             if (
               spec.type === 'ExportSpecifier' &&
               shouldRemoveExport.has(localName)
             ) {
               assert(spec.exported.type === 'Identifier')
               const exported = spec.exported.name
-              if (exported !== localName) {
-                // this only happens if we have something like
-                //   type Foo
-                //   export { Foo as Bar }
-                continue
+              if (exported === localName) {
+                canRemove = true
               }
-              const next = node.specifiers[i + 1]
-              if (next) {
-                assert(typeof spec.start === 'number')
-                assert(typeof next.start === 'number')
-                // @ts-ignore
-                s.remove(spec.start, next.start)
-              } else {
-                // last one
-                const prev = node.specifiers[i - 1]
-                assert(typeof spec.start === 'number')
-                assert(typeof spec.end === 'number')
-                // @ts-ignore
-                s.remove(
-                  prev
-                    ? (assert(typeof prev.end === 'number'), prev.end)
-                    : spec.start,
-                  spec.end,
-                )
-              }
-              removed++
             }
+            removable[i] = canRemove
+            if (!canRemove) keptCount++
           }
-          if (removed === node.specifiers.length) {
+          if (keptCount === 0) {
             assert(typeof node.start === 'number')
             assert(typeof node.end === 'number')
             // @ts-ignore
             s.remove(node.start, node.end)
+            continue
+          }
+
+          // Next kept specifier index for each position (or -1).
+          /** @type {number[]} */
+          const nextKeptIndex = new Array(node.specifiers.length).fill(-1)
+          let nextKept = -1
+          for (let i = node.specifiers.length - 1; i >= 0; i--) {
+            if (!removable[i]) nextKept = i
+            nextKeptIndex[i] = nextKept
+          }
+
+          // Build removal ranges by consecutive removable runs.
+          /** @type {{ start: number, end: number }[]} */
+          const ranges = []
+          let i = 0
+          let prevKeptIndex = -1
+          while (i < node.specifiers.length) {
+            if (!removable[i]) {
+              prevKeptIndex = i
+              i++
+              continue
+            }
+            const runStart = i
+            while (i < node.specifiers.length && removable[i]) i++
+            const runEnd = i - 1
+
+            const first = node.specifiers[runStart]
+            const last = node.specifiers[runEnd]
+            assert(typeof first.start === 'number')
+            assert(typeof last.end === 'number')
+
+            const nextKept = nextKeptIndex[runEnd]
+            if (nextKept !== -1) {
+              const nextSpec = node.specifiers[nextKept]
+              assert(typeof nextSpec.start === 'number')
+              ranges.push({ start: first.start, end: nextSpec.start })
+            } else if (prevKeptIndex >= 0) {
+              const prev = node.specifiers[prevKeptIndex]
+              assert(typeof prev.end === 'number')
+              ranges.push({ start: prev.end, end: last.end })
+            } else {
+              ranges.push({ start: first.start, end: last.end })
+            }
+          }
+
+          // apply removals from back to front to keep ranges stable
+          ranges.sort((a, b) => b.start - a.start)
+          for (const range of ranges) {
+            // @ts-ignore
+            s.remove(range.start, range.end)
           }
         }
       }