Skip to content

Commit fffe16e

Browse files
authored
build: clean generated type file (#14582)
1 parent f54e6d8 commit fffe16e

File tree

1 file changed

+92
-3
lines changed

1 file changed

+92
-3
lines changed

packages/vite/rollup.dts.config.ts

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { readFileSync } from 'node:fs'
22
import { fileURLToPath } from 'node:url'
3+
import { findStaticImports } from 'mlly'
34
import { type Plugin, defineConfig } from 'rollup'
45
import dts from 'rollup-plugin-dts'
56

@@ -28,12 +29,34 @@ const multilineCommentsRE = /\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\//g
2829
const singlelineCommentsRE = /\/\/[^/].*/g
2930
const licenseCommentsRE = /MIT License|MIT license|BSD license/
3031
const consecutiveNewlinesRE = /\n{2,}/g
32+
const identifierWithTrailingDollarRE = /\b(\w+)\$\d+\b/g
33+
34+
/**
35+
* Replace specific identifiers with a more readable name, grouped by
36+
* the module that imports the identifer as a named import alias
37+
*/
38+
const identifierReplacements: Record<string, Record<string, string>> = {
39+
rollup: {
40+
Plugin$1: 'rollup.Plugin',
41+
TransformResult$2: 'rollup.TransformResult',
42+
},
43+
esbuild: {
44+
TransformResult$1: 'esbuild_TransformResult',
45+
TransformOptions$1: 'esbuild_TransformOptions',
46+
BuildOptions$1: 'esbuild_BuildOptions',
47+
},
48+
'node:https': {
49+
Server$1: 'HttpsServer',
50+
ServerOptions$1: 'HttpsServerOptions',
51+
},
52+
}
3153

3254
/**
3355
* Patch the types files before passing to dts plugin
3456
* 1. Resolve `dep-types/*` and `types/*` imports
3557
* 2. Validate unallowed dependency imports
36-
* 3. Clean unnecessary comments
58+
* 3. Replace confusing type names
59+
* 4. Clean unnecessary comments
3760
*/
3861
function patchTypes(): Plugin {
3962
return {
@@ -56,8 +79,8 @@ function patchTypes(): Plugin {
5679
}
5780
},
5881
renderChunk(code, chunk) {
59-
const deps = new Set(Object.keys(pkg.dependencies))
6082
// Validate that chunk imports do not import dev deps
83+
const deps = new Set(Object.keys(pkg.dependencies))
6184
for (const id of chunk.imports) {
6285
if (
6386
!id.startsWith('./') &&
@@ -72,13 +95,79 @@ function patchTypes(): Plugin {
7295
}
7396
}
7497

98+
// Rollup deduplicate type names with a trailing `$1` or `$2`, which can be
99+
// confusing when showed in autocompletions. Try to replace with a better name
100+
const imports = findStaticImports(code)
101+
for (const modName in identifierReplacements) {
102+
const imp = imports.find(
103+
(imp) => imp.specifier === modName && imp.imports.includes('{'),
104+
)
105+
// Validate that `identifierReplacements` is not outdated if there's no match
106+
if (!imp) {
107+
this.warn(
108+
`${chunk.fileName} does not import "${modName}" for replacement`,
109+
)
110+
process.exitCode = 1
111+
continue
112+
}
113+
114+
const replacements = identifierReplacements[modName]
115+
for (const id in replacements) {
116+
// Validate that `identifierReplacements` is not outdated if there's no match
117+
if (!imp.imports.includes(id)) {
118+
this.warn(
119+
`${chunk.fileName} does not import "${id}" from "${modName}" for replacement`,
120+
)
121+
process.exitCode = 1
122+
continue
123+
}
124+
125+
const betterId = replacements[id]
126+
const regexEscapedId = escapeRegex(id)
127+
// If the better id accesses a namespace, the existing `Foo as Foo$1`
128+
// named import cannot be replaced with `Foo as Namespace.Foo`, so we
129+
// pre-emptively remove the whole named import
130+
if (betterId.includes('.')) {
131+
code = code.replace(
132+
new RegExp(`\\b\\w+\\b as ${regexEscapedId},?\\s?`),
133+
'',
134+
)
135+
}
136+
code = code.replace(
137+
new RegExp(`\\b${regexEscapedId}\\b`, 'g'),
138+
betterId,
139+
)
140+
}
141+
}
142+
const unreplacedIds = unique(
143+
Array.from(code.matchAll(identifierWithTrailingDollarRE), (m) => m[0]),
144+
)
145+
if (unreplacedIds.length) {
146+
const unreplacedStr = unreplacedIds.map((id) => `\n- ${id}`).join('')
147+
this.warn(
148+
`${chunk.fileName} contains confusing identifier names${unreplacedStr}`,
149+
)
150+
process.exitCode = 1
151+
}
152+
75153
// Clean unnecessary comments
76-
return code
154+
code = code
77155
.replace(singlelineCommentsRE, '')
78156
.replace(multilineCommentsRE, (m) => {
79157
return licenseCommentsRE.test(m) ? '' : m
80158
})
81159
.replace(consecutiveNewlinesRE, '\n\n')
160+
161+
return code
82162
},
83163
}
84164
}
165+
166+
const escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g
167+
function escapeRegex(str: string): string {
168+
return str.replace(escapeRegexRE, '\\$&')
169+
}
170+
171+
function unique<T>(arr: T[]): T[] {
172+
return Array.from(new Set(arr))
173+
}

0 commit comments

Comments
 (0)