(rootUrl: URL, targetUrl: URL)
| 148 | } |
| 149 | |
| 150 | function getRelativeUrlPath(rootUrl: URL, targetUrl: URL): string | null { |
| 151 | if (targetUrl.origin !== rootUrl.origin) { |
| 152 | return null; |
| 153 | } |
| 154 | |
| 155 | const rootPath = ensureTrailingSlash(rootUrl.pathname); |
| 156 | if (!targetUrl.pathname.startsWith(rootPath)) { |
| 157 | return null; |
| 158 | } |
| 159 | |
| 160 | const relativePath = targetUrl.pathname.slice(rootPath.length); |
| 161 | if (!relativePath) { |
| 162 | return null; |
| 163 | } |
| 164 | |
| 165 | // URL.pathname keeps segments percent-encoded; decode them so the stored |
| 166 | // relative path matches the decoded form HuggingFace paths use. Callers |
| 167 | // re-encode exactly once (encodeUrlPath/joinManifestUrlPath); leaving it |
| 168 | // encoded here would double-encode tiles with '#'/spaces (e.g. 5x5#-5.ply) |
| 169 | // and 404 the fetch. |
| 170 | return normalizePath(relativePath) |
| 171 | .split('/') |
| 172 | .map(decodePathSegment) |
| 173 | .join('/'); |
| 174 | } |
| 175 | |
| 176 | function shouldSkipDirectoryHref(href: string): boolean { |
| 177 | const lower = href.trim().toLowerCase(); |
no test coverage detected