Skip to content

Commit 94116df

Browse files
committed
fix(test): only merge new interfaces in module augmentation patching
1 parent 7202326 commit 94116df

1 file changed

Lines changed: 46 additions & 5 deletions

File tree

packages/test/build.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,13 +2138,54 @@ async function patchModuleAugmentations() {
21382138

21392139
const innerContent = content.slice(braceStart + 1, braceEnd).trim();
21402140

2141-
// Merge augmented types into the target .d.ts file
2141+
// Merge only NEW type declarations into the target .d.ts file.
2142+
// Interfaces that already exist (e.g., ExpectStatic, Assertion, MatcherState) must NOT
2143+
// be re-declared, as that would shadow extends clauses and break call signatures.
21422144
if (innerContent && existsSync(targetFile)) {
21432145
let targetContent = await readFile(targetFile, 'utf-8');
2144-
const exportBlock = innerContent.replace(/^(\t*)interface /gm, '$1export interface ');
2145-
targetContent += `\n// Merged from module augmentation: declare module "${bareSpecifier}"\n${exportBlock}\n`;
2146-
await writeFile(targetFile, targetContent, 'utf-8');
2147-
console.log(` Merged augmentation "${bareSpecifier}" into ${basename(targetFile)}`);
2146+
2147+
// Extract individual interface blocks from the augmentation content
2148+
const interfaceRegex = /(?:export\s+)?interface\s+(\w+)(?:<[^>]*>)?\s*\{/g;
2149+
let match;
2150+
const newDeclarations: string[] = [];
2151+
2152+
while ((match = interfaceRegex.exec(innerContent)) !== null) {
2153+
const name = match[1];
2154+
// Only merge if this interface does NOT already exist in the target file
2155+
if (new RegExp(`\\binterface\\s+${name}\\b`).test(targetContent)) {
2156+
console.log(` Skipped existing interface "${name}" (already in ${basename(targetFile)})`);
2157+
continue;
2158+
}
2159+
2160+
// Extract this interface block using brace matching
2161+
const ifaceStart = match.index;
2162+
const ifaceBraceStart = innerContent.indexOf('{', ifaceStart);
2163+
let ifaceDepth = 0;
2164+
let ifaceBraceEnd = -1;
2165+
for (let i = ifaceBraceStart; i < innerContent.length; i++) {
2166+
if (innerContent[i] === '{') ifaceDepth++;
2167+
else if (innerContent[i] === '}') {
2168+
ifaceDepth--;
2169+
if (ifaceDepth === 0) {
2170+
ifaceBraceEnd = i;
2171+
break;
2172+
}
2173+
}
2174+
}
2175+
if (ifaceBraceEnd === -1) continue;
2176+
2177+
let block = innerContent.slice(ifaceStart, ifaceBraceEnd + 1).trim();
2178+
if (!block.startsWith('export')) {
2179+
block = `export ${block}`;
2180+
}
2181+
newDeclarations.push(block);
2182+
console.log(` Merged new interface "${name}" into ${basename(targetFile)}`);
2183+
}
2184+
2185+
if (newDeclarations.length > 0) {
2186+
targetContent += `\n// Merged from module augmentation: declare module "${bareSpecifier}"\n${newDeclarations.join('\n')}\n`;
2187+
await writeFile(targetFile, targetContent, 'utf-8');
2188+
}
21482189
}
21492190

21502191
// Rewrite declare module path to relative

0 commit comments

Comments
 (0)