Skip to content

Commit 30fd696

Browse files
committed
fix: deduplicate warnedMessages
1 parent 547ee98 commit 30fd696

File tree

2 files changed

+34
-2
lines changed

2 files changed

+34
-2
lines changed

src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ interface PendingViolation {
138138
suggestions?: string[]
139139
options: ImpoundMatcherOptions
140140
errorFn: (msg: string) => void
141+
warnedMessages: Set<string> | undefined
141142
}
142143

143144
/** Convert a byte offset in source code to a 1-indexed line and 0-indexed column. */
@@ -472,6 +473,7 @@ export const ImpoundPlugin = createUnplugin<ImpoundOptions>((globalOptions) => {
472473
suggestions,
473474
options,
474475
errorFn,
476+
warnedMessages,
475477
}
476478

477479
if (moduleGraph.has(importer)) {
@@ -584,8 +586,7 @@ export const ImpoundPlugin = createUnplugin<ImpoundOptions>((globalOptions) => {
584586
if (pending) {
585587
pendingViolations.delete(key)
586588
for (const violation of pending) {
587-
const warnedMessages = violation.options.warn !== 'always' ? new Set<string>() : undefined
588-
enrichAndReport(violation, moduleGraph, resolvedImports, entries, maxTraceDepth, globalOptions.cwd, warnedMessages)
589+
enrichAndReport(violation, moduleGraph, resolvedImports, entries, maxTraceDepth, globalOptions.cwd, violation.warnedMessages)
589590
}
590591
}
591592
}

test/index.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -994,6 +994,37 @@ describe('trace mode (deferred violations)', () => {
994994

995995
errorSpy.mockRestore()
996996
})
997+
998+
it('deduplicates deferred violations using shared warnedMessages set from matcher', async () => {
999+
const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
1000+
1001+
// Use two patterns that produce the same message for the same import
1002+
const plugins = ImpoundPlugin.rollup({ trace: true, patterns: [['secret', 'Not allowed']], error: false })
1003+
const pluginArray = Array.isArray(plugins) ? plugins : [plugins]
1004+
const impoundPlugin = pluginArray.find(p => p.name === 'impound')!
1005+
const tracePlugin = pluginArray.find(p => p.name === 'impound:trace')!
1006+
1007+
const context = { error: () => {} }
1008+
1009+
// First: defer a violation, then flush via transform
1010+
await (impoundPlugin as any).resolveId.call(context, 'secret', 'a.js')
1011+
await (tracePlugin as any).transform('import secret from "secret"', 'a.js')
1012+
expect(errorSpy).toHaveBeenCalledTimes(1)
1013+
1014+
// Second: same import from a different file triggers immediate path (a.js already in graph).
1015+
// The warnedMessages set is shared with the matcher, so the *immediate* violation from b.js
1016+
// is a different message (different importer) and should log.
1017+
await (tracePlugin as any).transform('import secret from "secret"', 'b.js')
1018+
await (impoundPlugin as any).resolveId.call(context, 'secret', 'b.js')
1019+
expect(errorSpy).toHaveBeenCalledTimes(2)
1020+
1021+
// Third: re-resolve 'secret' from a.js — immediate path, same message as first.
1022+
// Should be deduped because the deferred flush used the matcher's warnedMessages set.
1023+
await (impoundPlugin as any).resolveId.call(context, 'secret', 'a.js')
1024+
expect(errorSpy).toHaveBeenCalledTimes(2) // still 2, deduped
1025+
1026+
errorSpy.mockRestore()
1027+
})
9971028
})
9981029

9991030
async function buildWithTrace(files: Record<string, string>, libs: string[], opts: ImpoundOptions, extraPlugins: any[] = []) {

0 commit comments

Comments
 (0)