1: | <?php declare(strict_types = 1); |
2: | |
3: | namespace ApiGen\Renderer; |
4: | |
5: | use ApiGen\Index\NamespaceIndex; |
6: | use ApiGen\Info\AliasInfo; |
7: | use ApiGen\Info\ClassLikeInfo; |
8: | use ApiGen\Info\ConstantInfo; |
9: | use ApiGen\Info\EnumCaseInfo; |
10: | use ApiGen\Info\FunctionInfo; |
11: | use ApiGen\Info\MemberInfo; |
12: | use ApiGen\Info\MethodInfo; |
13: | use ApiGen\Info\ParameterInfo; |
14: | use ApiGen\Info\PropertyInfo; |
15: | |
16: | use function assert; |
17: | use function get_debug_type; |
18: | use function sprintf; |
19: | use function str_starts_with; |
20: | use function strlen; |
21: | use function strrpos; |
22: | use function strtr; |
23: | use function substr; |
24: | |
25: | use const DIRECTORY_SEPARATOR; |
26: | |
27: | |
28: | class UrlGenerator |
29: | { |
30: | public function __construct( |
31: | protected string $baseDir, |
32: | protected string $baseUrl, |
33: | ) { |
34: | } |
35: | |
36: | |
37: | public function getRelativePath(string $path): string |
38: | { |
39: | if (str_starts_with($path, $this->baseDir)) { |
40: | return substr($path, strlen($this->baseDir) + 1); |
41: | |
42: | } else { |
43: | throw new \LogicException("{$path} does not start with {$this->baseDir}"); |
44: | } |
45: | } |
46: | |
47: | |
48: | public function getAssetUrl(string $name): string |
49: | { |
50: | return $this->baseUrl . $this->getAssetPath($name); |
51: | } |
52: | |
53: | |
54: | public function getAssetPath(string $name): string |
55: | { |
56: | return "assets/$name"; |
57: | } |
58: | |
59: | |
60: | public function getIndexUrl(): string |
61: | { |
62: | return $this->baseUrl . $this->getIndexPath(); |
63: | } |
64: | |
65: | |
66: | public function getIndexPath(): string |
67: | { |
68: | return 'index.html'; |
69: | } |
70: | |
71: | |
72: | public function getTreeUrl(): string |
73: | { |
74: | return $this->baseUrl . $this->getTreePath(); |
75: | } |
76: | |
77: | |
78: | public function getTreePath(): string |
79: | { |
80: | return 'tree.html'; |
81: | } |
82: | |
83: | |
84: | public function getSitemapPath(): string |
85: | { |
86: | return 'sitemap.xml'; |
87: | } |
88: | |
89: | |
90: | public function getSitemapUrl(): string |
91: | { |
92: | return $this->baseUrl . $this->getSitemapPath(); |
93: | } |
94: | |
95: | |
96: | public function getNamespaceUrl(NamespaceIndex $namespace): string |
97: | { |
98: | return $this->baseUrl . $this->getNamespacePath($namespace); |
99: | } |
100: | |
101: | |
102: | public function getNamespacePath(NamespaceIndex $namespace): string |
103: | { |
104: | return 'namespace-' . strtr($namespace->name->full ?: 'none', '\\', '.') . '.html'; |
105: | } |
106: | |
107: | |
108: | public function getClassLikeUrl(ClassLikeInfo $classLike): string |
109: | { |
110: | return $this->baseUrl . $this->getClassLikePath($classLike); |
111: | } |
112: | |
113: | |
114: | public function getClassLikePath(ClassLikeInfo $classLike): string |
115: | { |
116: | return strtr($classLike->name->full, '\\', '.') . '.html'; |
117: | } |
118: | |
119: | |
120: | public function getClassLikeSourceUrl(ClassLikeInfo $classLike): string |
121: | { |
122: | assert($classLike->file !== null); |
123: | return $this->getSourceUrl($classLike->file, $classLike->startLine, null); |
124: | } |
125: | |
126: | |
127: | public function getMemberUrl(ClassLikeInfo $classLike, MemberInfo $member): string |
128: | { |
129: | return $this->getClassLikeUrl($classLike) . '#' . $this->getMemberAnchor($member); |
130: | } |
131: | |
132: | |
133: | public function getMemberAnchor(MemberInfo $member): string |
134: | { |
135: | if ($member instanceof ConstantInfo || $member instanceof EnumCaseInfo) { |
136: | return $member->name; |
137: | |
138: | } elseif ($member instanceof PropertyInfo) { |
139: | return '$' . $member->name; |
140: | |
141: | } elseif ($member instanceof MethodInfo) { |
142: | return '_' . $member->name; |
143: | |
144: | } else { |
145: | throw new \LogicException(sprintf('Unexpected member type %s', get_debug_type($member))); |
146: | } |
147: | } |
148: | |
149: | |
150: | public function getMemberSourceUrl(ClassLikeInfo $classLike, MemberInfo $member): string |
151: | { |
152: | assert($classLike->file !== null); |
153: | return $this->getSourceUrl($classLike->file, $member->startLine, $member->endLine); |
154: | } |
155: | |
156: | |
157: | public function getAliasUrl(ClassLikeInfo $classLike, AliasInfo $alias): string |
158: | { |
159: | return $this->getClassLikeUrl($classLike) . '#' . $this->getAliasAnchor($alias); |
160: | } |
161: | |
162: | |
163: | public function getAliasAnchor(AliasInfo $alias): string |
164: | { |
165: | return '~' . $alias->name; |
166: | } |
167: | |
168: | |
169: | public function getAliasSourceUrl(ClassLikeInfo $classLike, AliasInfo $alias): string |
170: | { |
171: | assert($classLike->file !== null); |
172: | return $this->getSourceUrl($classLike->file, $alias->startLine, $alias->endLine); |
173: | } |
174: | |
175: | |
176: | public function getFunctionUrl(FunctionInfo $function): string |
177: | { |
178: | return $this->baseUrl . $this->getFunctionPath($function); |
179: | } |
180: | |
181: | |
182: | public function getFunctionPath(FunctionInfo $function): string |
183: | { |
184: | return 'function-' . strtr($function->name->full, '\\', '.') . '.html'; |
185: | } |
186: | |
187: | |
188: | public function getFunctionSourceUrl(FunctionInfo $function): string |
189: | { |
190: | assert($function->file !== null); |
191: | return $this->getSourceUrl($function->file, $function->startLine, $function->endLine); |
192: | } |
193: | |
194: | |
195: | public function getParameterAnchor(ParameterInfo $parameter): string |
196: | { |
197: | return '$' . $parameter->name; |
198: | } |
199: | |
200: | |
201: | public function getSourceUrl(string $path, ?int $startLine, ?int $endLine): string |
202: | { |
203: | if ($startLine === null) { |
204: | $fragment = ''; |
205: | |
206: | } elseif ($endLine === null || $endLine === $startLine) { |
207: | $fragment = "#$startLine"; |
208: | |
209: | } else { |
210: | $fragment = "#$startLine-$endLine"; |
211: | } |
212: | |
213: | return $this->baseUrl . $this->getSourcePath($path) . $fragment; |
214: | } |
215: | |
216: | |
217: | public function getSourcePath(string $path): string |
218: | { |
219: | $relativePath = $this->getRelativePath($path); |
220: | $relativePathWithoutExtension = substr($relativePath, 0, strrpos($relativePath, '.') ?: null); |
221: | return 'source-' . strtr($relativePathWithoutExtension, DIRECTORY_SEPARATOR, '.') . '.html'; |
222: | } |
223: | } |
224: | |