Skip to content

Commit a014c0b

Browse files
authored
Merge pull request #6 from 10up/fix/5
Fix issues with multiple types for parameter and duplicate hooks
2 parents 9dd0078 + d2e3ced commit a014c0b

File tree

4 files changed

+78
-14
lines changed

4 files changed

+78
-14
lines changed

src/cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const program = new Command();
1111
const defaultConfig: WPHooksDocConfig = {
1212
input: '.',
1313
outputDir: './wp-hooks-docs',
14-
ignoreFiles: [],
14+
ignoreFiles: ['/tests/', '/vendor/', '/node_modules/'],
1515
ignoreHooks: [],
1616
title: 'Plugin Hooks Documentation',
1717
tagline: 'Documentation for the plugin hooks',

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+
// Collect sources of all hooks.
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: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export class MarkdownGenerator {
9696
content.push('|------|------|-------------|');
9797
hook.doc.params.forEach((param) => {
9898
content.push(
99-
`| ${param.name} | \`${param.type}\` | ${this.sanitizeContent(param.description, true)} |`
99+
`| ${this.sanitizeContent(param.name)} | \`${this.sanitizeContent(param.type)}\` | ${this.sanitizeContent(param.description, true)} |`
100100
);
101101
});
102102
content.push('');
@@ -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(
@@ -216,7 +229,7 @@ export class MarkdownGenerator {
216229
sanitized = sanitized.replace(/\n/g, '');
217230
}
218231

219-
return sanitized.replace(/[{}]/g, (match) => `\\${match}`);
232+
return sanitized.replace(/[{}|]/g, (match) => `\\${match}`);
220233
}
221234

222235
private sanitizeHookName(hookName: string): string {

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)