Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions lib/Hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,17 @@ class Hook {
// Fast path: only `name` is set. Build the descriptor as a literal
// so `_insert` and downstream consumers see the same hidden class
// as the string-options path, avoiding a polymorphic call site.
if (
options.before === undefined &&
options.stage === undefined &&
options.context === undefined &&
options.type === undefined &&
options.fn === undefined
) {
// Scan with `for...in` (cheaper than allocating `Object.keys`)
// to verify no other user-provided properties exist - e.g.
// webpack's `additionalAssets` - otherwise they'd be dropped.
let onlyName = true;
for (const key in options) {
if (key !== "name") {
onlyName = false;
break;
}
}
if (onlyName) {
options = { type, fn, name };
} else {
options.name = name;
Expand Down
17 changes: 17 additions & 0 deletions test/Hook.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,23 @@ describe("Hook", () => {
);
});

it("should preserve custom tap options (e.g. webpack's `additionalAssets`) on the tap descriptor", () => {
const hook = new SyncHook();

// Options with only `name` plus a custom property - used by webpack's
// processAssets (`additionalAssets: true`). The fast-path in `_tap`
// must not drop the custom property.
hook.tap({ name: "A", additionalAssets: true }, () => {});
// Options with `name`, `stage` and a custom property go through the
// slow path - also checked for completeness.
hook.tap({ name: "B", stage: 10, extra: "value" }, () => {});

expect(hook.taps[0].name).toBe("A");
expect(hook.taps[0].additionalAssets).toBe(true);
expect(hook.taps[1].name).toBe("B");
expect(hook.taps[1].extra).toBe("value");
});

it("should not ignore invalid before values", () => {
// A plugin may use a hook that will never be executed
const hook = new SyncHook();
Expand Down
Loading