Skip to content

Commit 2bcb9bf

Browse files
committed
Handle duplicate hooks.
1 parent c86ffa1 commit 2bcb9bf

File tree

3 files changed

+75
-11
lines changed

3 files changed

+75
-11
lines changed

src/collectors/hook-collector.ts

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,24 +60,58 @@ export class HookCollector {
6060
}
6161

6262
private transformHooks(rawData: RawHookCollection): HookCollection {
63-
// Deduplicate hooks based on name
63+
// Helper function to merge hooks with the same name and transform them.
64+
const prepareHooks = (hooks: RawHookData['hooks']): Hook[] => {
65+
const hookMap = new Map<string, RawHookData['hooks'][0][]>();
66+
67+
// Group hooks by name
68+
hooks.forEach((hook) => {
69+
const hookId = this.getHookId(this.escapeHookName(hook.name));
70+
if (!hookMap.has(hookId)) {
71+
hookMap.set(hookId, []);
72+
}
73+
hookMap.get(hookId)?.push(hook);
74+
});
75+
76+
// Merge and transform hooks
77+
return Array.from(hookMap.entries()).map(([_, hooks]) => {
78+
if (hooks.length === 1) {
79+
return this.transformHook(hooks[0]);
80+
}
81+
82+
// Merge multiple hooks with the same name
83+
const mergedHook = { ...hooks[0] };
84+
85+
// Use the first non-empty source
86+
mergedHook.files = [];
87+
hooks.forEach((h) => {
88+
const file = {
89+
file: h.file || '',
90+
line: h.line || 0,
91+
};
92+
mergedHook.files?.push(file);
93+
});
94+
95+
return this.transformHook(mergedHook);
96+
});
97+
};
98+
6499
return {
65-
actions: rawData.actions.hooks.map(this.transformHook.bind(this)),
66-
filters: rawData.filters.hooks.map(this.transformHook.bind(this)),
100+
actions: prepareHooks(rawData.actions.hooks),
101+
filters: prepareHooks(rawData.filters.hooks),
67102
};
68103
}
69104

70-
private transformHook(hook: RawHookData['hooks'][0]): Hook {
71-
let hookName = hook.name;
72-
105+
private escapeHookName(hookName: string): string {
106+
let escapedHookName = hookName;
73107
/**
74108
* Replace PHP-style interpolations with {$var}_suffix
75109
* Example:
76110
* 'woocommerce_analytics_' . $field . '_' . $context
77111
* becomes
78112
* 'woocommerce_analytics_{$field}_$context'
79113
*/
80-
hookName = hookName.replace(
114+
escapedHookName = hookName.replace(
81115
/['"]\s*\.\s*(\$(?:[a-zA-Z_]\w*)(?:->\w+|\[[^\]]+\]|\(\))*((?:->\w+|\[[^\]]+\]|\(\)))*)\s*\.\s*['"]?_?([a-zA-Z0-9_]*)/g,
82116
(_, variable, rest, suffix) => `{${variable}${rest || ''}}${suffix ? `_${suffix}` : ''}`
83117
);
@@ -89,26 +123,36 @@ export class HookCollector {
89123
* becomes
90124
* 'woocommerce_analytics_{$field}'
91125
*/
92-
hookName = hookName.replace(
126+
escapedHookName = hookName.replace(
93127
/['"]\s*\.\s*(\$(?:[a-zA-Z_]\w*)(?:->\w+|\[[^\]]+\]|\(\))*((?:->\w+|\[[^\]]+\]|\(\)))*)/g,
94128
(_, variable, rest) => `{${variable}${rest || ''}}`
95129
);
96130

97131
/**
98132
* Remove quotes from hook name
99133
*/
100-
hookName = hookName.replace(/['"]/g, '');
134+
escapedHookName = hookName.replace(/['"]/g, '');
135+
136+
return escapedHookName;
137+
}
101138

102-
const hookId = hookName
139+
private getHookId(hookName: string): string {
140+
return hookName
103141
.replace(/[^a-zA-Z0-9\-_.~]/g, '')
104142
.replace(/^__/, '')
105143
.replace(/^_/, '');
144+
}
145+
146+
private transformHook(hook: RawHookData['hooks'][0]): Hook {
147+
const hookName = this.escapeHookName(hook.name);
148+
const hookId = this.getHookId(hookName);
106149

107150
return {
108151
id: hookId,
109152
name: hookName,
110153
type: hook.type,
111154
file: hook.file,
155+
files: hook.files || [],
112156
line: hook.line || 0,
113157
doc: {
114158
description: hook.doc?.description || '',

src/generators/markdown-generator.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,20 @@ export class MarkdownGenerator {
114114
});
115115
}
116116

117-
if (hook.file) {
117+
if (hook.files && hook.files.length > 0) {
118+
content.push('### Source\n');
119+
hook.files.forEach((file) => {
120+
if (file.line && file.line > 0 && this.config.githubSourceCodeUrl) {
121+
content.push(
122+
`- Defined in [\`${file.file}\` at line ${file.line}](${this.config.githubSourceCodeUrl}/${file.file}#L${file.line})`
123+
);
124+
} else if (file.line && file.line > 0) {
125+
content.push(`- Defined in \`${file.file}\` at line ${file.line}`);
126+
} else {
127+
content.push(`- Defined in \`${file.file}\``);
128+
}
129+
});
130+
} else if (hook.file) {
118131
content.push('### Source\n');
119132
if (hook.line && hook.line > 0 && this.config.githubSourceCodeUrl) {
120133
content.push(

src/utils/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1+
export interface HookFile {
2+
file: string;
3+
line: number;
4+
}
5+
16
export interface Hook {
27
id: string;
38
name: string;
49
type: string;
510
file: string;
11+
files?: HookFile[];
612
line?: number;
713
doc: {
814
description?: string;
@@ -55,6 +61,7 @@ export interface RawHookData {
5561
name: string;
5662
type: string;
5763
file: string;
64+
files?: HookFile[];
5865
line?: number;
5966
doc?: {
6067
description?: string;

0 commit comments

Comments
 (0)