(text: string, fromRoot = false)
| 779 | |
| 780 | /** The destination a command array names: `['/article', slug]` is `/article/${…}`; null when it is relative or not a literal array. */ |
| 781 | export function commandsHref(text: string, fromRoot = false): HrefLiteral | null { |
| 782 | const arr = text.trim(); |
| 783 | if (arr[0] !== '[') return null; |
| 784 | const close = matchBracket(arr, 0); |
| 785 | if (close < 0) return null; |
| 786 | const parts: string[] = []; |
| 787 | let i = 1; |
| 788 | let element = ''; |
| 789 | const flush = (): boolean => { |
| 790 | const e = element.trim(); |
| 791 | element = ''; |
| 792 | if (e.length === 0) return true; |
| 793 | const literal = staticString(e); |
| 794 | if (literal !== null) { |
| 795 | parts.push(...literal.split('/').filter((seg) => seg.length > 0)); |
| 796 | return true; |
| 797 | } |
| 798 | // A matrix-params object says nothing about the path. |
| 799 | if (e.startsWith('{')) return true; |
| 800 | parts.push(HOLE); |
| 801 | return true; |
| 802 | }; |
| 803 | while (i < close) { |
| 804 | const ch = arr[i]!; |
| 805 | if (ch === '"' || ch === "'" || ch === '`') { |
| 806 | const end = skipString(arr, i); |
| 807 | if (end < 0) return null; |
| 808 | element += arr.slice(i, end + 1); |
| 809 | i = end + 1; |
| 810 | continue; |
| 811 | } |
| 812 | if (ch === '[' || ch === '{' || ch === '(') { |
| 813 | const end = matchBracket(arr, i); |
| 814 | if (end < 0) return null; |
| 815 | element += arr.slice(i, end + 1); |
| 816 | i = end + 1; |
| 817 | continue; |
| 818 | } |
| 819 | if (ch === ',') flush(); |
| 820 | else element += ch; |
| 821 | i++; |
| 822 | } |
| 823 | flush(); |
| 824 | // Only an absolute destination: `['/login']`. In a template, `['../', id]` |
| 825 | // and a bare `['edit']` are relative to wherever the component is; a |
| 826 | // `router.navigate(['project', 'issue', id])` with no `relativeTo` starts |
| 827 | // from the root. |
| 828 | const firstElement = arr.slice(1, close).split(',')[0] ?? ''; |
| 829 | const first = staticString(firstElement); |
| 830 | if (first === null || (!first.startsWith('/') && !(fromRoot && !first.startsWith('.')))) return null; |
| 831 | const pathText = '/' + parts.filter((p) => p.length > 0).join('/'); |
| 832 | return namesSomewhere({ path: pathText, display: pathText.split(HOLE).join('${…}') }); |
| 833 | } |
| 834 | |
| 835 | /** |
| 836 | * The href, when it names at least one segment of its own. A path made only |
no test coverage detected