PageSourceSearch

https://webawesome.com/assets/scripts/docs-path-parser.js

js webawesome.com collected 2026-09-24 21:47:52 UTC 2,751 bytes, 87 lines download raw bytes

1/**
2 * Shared module for parsing docs paths to extract item name and type.
3 * Used by both server-side (TypeScript) and client-side (JavaScript) code.
4 *
5 * Requires: ES modules support, URL constructor (Node.js 10+, modern browsers)
6 */
7
8const KNOWN_TYPES = {
9  patterns: 'pattern',
10  components: 'component',
11  utilities: 'utility'
12};
13
14/**
15 * Extracts docs item name and type from a pathname.
16 *
17 * @param {string} pathname - URL pathname (may include query params or hash fragments)
18 * @returns {{name: string, type?: string} | null} Object with `name` and optionally `type`, or null
19 */
20export function parseDocsPath(pathname) {
21  if (!pathname || typeof pathname !== 'string') {
22    return null;
23  }
24
25  // Validate URL constructor is available (Node.js 10+, all modern browsers)
26  if (typeof URL === 'undefined') {
27    if (typeof console !== 'undefined' && console.error) {
28      console.error('URL constructor not available. This module requires Node.js 10+ or a modern browser.');
29    }
30    return null;
31  }
32
33  const extractFromPath = path => {
34    // Use URL constructor to handle query params and hash fragments
35    // Supply a base URL so it doesn't error on relative paths
36    const url = new URL(path, 'https://webawesome.com');
37
38    // If an absolute URL was provided, validate it's from webawesome.com
39    // This prevents parsing paths from other domains that happen to have /docs/ in them
40    if (path.startsWith('http://') || path.startsWith('https://')) {
41      const inputUrl = new URL(path);
42      if (inputUrl.hostname !== 'webawesome.com' && inputUrl.hostname !== 'www.webawesome.com') {
43        return null;
44      }
45    }
46
47    const pathname = url.pathname;
48
49    if (!pathname.startsWith('/docs/')) {
50      return null;
51    }
52
53    const pathWithoutPrefix = pathname.slice('/docs/'.length).replace(/\/$/, '');
54    const segments = pathWithoutPrefix.split('/').filter(Boolean);
55
56    if (segments.length === 0) {
57      return null;
58    }
59
60    const name = segments[segments.length - 1];
61
62    // Only include type if there are multiple segments (category/item structure)
63    if (segments.length > 1) {
64      const firstSegment = segments[0];
65      const type = KNOWN_TYPES[firstSegment] || firstSegment;
66      return { name, type };
67    }
68
69    return { name };
70  };
71
72  const result = extractFromPath(pathname);
73  if (result) {
74    return result;
75  }
76
77  // Try decoding in case pathname is URL-encoded
78  try {
79    return extractFromPath(decodeURIComponent(pathname));
80  } catch (error) {
81    // Invalid percent-encoding - return null. Log to help identify unexpected cases.
82    if (typeof console !== 'undefined' && console.warn) {
83      console.warn('Failed to decode URI component:', pathname, error);
84    }
85    return null;
86  }
87}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.