src/vs/workbench/contrib/browserView/common/browserSearch.ts

449 LOC · 430 covered · 19 uncovered · 85 ranges · 33 concepts · 30 introducers · 17 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filebrowserSearch.ts ×4 · 8 introduced LOCbrowserSearch.ts ×4browserSearch.ts ×6 · 15 introduced LOCbrowserSearch.ts ×6fragment is a URL (percent-encoded later)|occurrence=1, browserSearch.test|title=BrowserSearch - resolveAddressBarInput input is trimmed before classification|occurrence=1 · 0 introduced LOCfragment is a URL (perce…browserSearch.ts ×4 · 16 introduced LOCbrowserSearch.ts ×4browserSearch.ts ×2 · 5 introduced LOCbrowserSearch.ts ×2browserSearch.ts ×4 · 9 introduced LOCbrowserSearch.ts ×4browserSearch.ts ×6 · 13 introduced LOCbrowserSearch.ts ×6browserSearch.test|title=BrowserSearch - resolveAddressBarInput whitespace in the userinfo with an IP-literal host is still a URL|occurrence=1 · 0 introduced LOCbrowserSearch.test|title…browserSearch.ts ×2 · 4 introduced LOCbrowserSearch.ts ×2browserSearch.test|title=BrowserSearch - resolveAddressBarInput an explicit http(s) scheme keeps whitespace-userinfo input a URL|occurrence=1 · 0 introduced LOCbrowserSearch.test|title…browserSearch.ts ×2 · 7 introduced LOCbrowserSearch.ts ×2browserSearch.ts ×4 · 13 introduced LOCbrowserSearch.ts ×4browserSearch.ts ×1 · 2 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×2 · 5 introduced LOCbrowserSearch.ts ×2browserSearch.ts ×1 · 3 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×1 · 7 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×1 · 3 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×12 · 55 introduced LOCbrowserSearch.ts ×12browserSearch.ts ×1 · 2 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×1 · 2 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×3 · 3 introduced LOCbrowserSearch.ts ×3browserSearch.ts ×1 · 1 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×1 · 1 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×1 · 4 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×1 · 1 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×1 · 2 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×1 · 2 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×8 · 19 introduced LOCbrowserSearch.ts ×8browserSearch.ts ×1 · 1 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×1 · 1 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×3 · 10 introduced LOCbrowserSearch.ts ×3browserSearch.ts ×1 · 5 introduced LOCbrowserSearch.ts ×1browserSearch.ts ×8 · 211 introduced LOCbrowserSearch.ts ×8browserSearch.test|title=BrowserSearch - buildSearchUrl encodes queries for each engine|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - buildSearchUrl encodes queries for each engine|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - buildSearchUrl encodes special characters|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - buildSearchUrl encodes special characters|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - buildSearchUrl trims and collapses internal whitespace|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - buildSearchUrl trims and collapses internal whitespace|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - buildSearchUrl unknown engine id falls back to default (Bing)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - buildSearchUrl unknown engine id falls back to default (Bing)|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - getBrowserSearchEngineLabel returns the engine label, falling back to default for unknown ids|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - getBrowserSearchEngineLabel returns the engine label, falling back to default for unknown ids|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - resolveAddressBarInput ambiguous inputs return unknown|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput ambiguous inputs return unknown|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - resolveAddressBarInput an explicit http(s) scheme keeps whitespace-userinfo input a URL|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput an explicit http(s) scheme keeps whitespace-userinfo input a URL|occurrence=1browserSearch.test|title… whitespace input returns empty|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput empty / whitespace input returns empty|occurrence=1 whitespace input return…browserSearch.test|title=BrowserSearch - resolveAddressBarInput input is trimmed before classification|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput input is trimmed before classification|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - resolveAddressBarInput javascript: with non-code body is unknown|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput javascript: with non-code body is unknown|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - resolveAddressBarInput queries (whitespace or invalid host chars) return query|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput queries (whitespace or invalid host chars) return query|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - resolveAddressBarInput recognized schemes are URLs|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput recognized schemes are URLs|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - resolveAddressBarInput scheme-less hosts and IPs are URLs|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput scheme-less hosts and IPs are URLs|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - resolveAddressBarInput unknown scheme that looks like user:password@host is a URL|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput unknown scheme that looks like user:password@host is a URL|occurrence=1browserSearch.test|title…fragment is a URL (percent-encoded later)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput whitespace in the path/query/fragment is a URL (percent-encoded later)|occurrence=1fragment is a URL (perce…browserSearch.test|title=BrowserSearch - resolveAddressBarInput whitespace in the userinfo is unknown (defaults to search)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput whitespace in the userinfo is unknown (defaults to search)|occurrence=1browserSearch.test|title…browserSearch.test|title=BrowserSearch - resolveAddressBarInput whitespace in the userinfo with an IP-literal host is still a URL|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/workbench/contrib/browserView/test/common/browserSearch.test|title=BrowserSearch - resolveAddressBarInput whitespace in the userinfo with an IP-literal host is still a URL|occurrence=1browserSearch.test|title…Focused file · src/vs/workbench/contrib/browserView/common/browserSearch.ts · 449 LOCcommon/browserSearch.ts

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 > /*--------------------------------------------------------------------------------------------- browserSearch.ts ×8
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > /*
7 > * NOTE: {@link resolveAddressBarInputType} is a deliberate, self-contained
8 > * APPROXIMATION of Chromium's omnibox parser (`AutocompleteInput::Parse`), not
9 > * a faithful port. It intentionally diverges in places — most notably it uses a
10 > * lightweight "any 2+ letter last label is a TLD" heuristic instead of a Public
11 > * Suffix List lookup — to avoid maintaining large data tables for an address
12 > * bar. Please treat the unit tests in `browserSearch.test.ts` as the
13 > * specification: do not "fix" this to byte-match Chromium. If Chromium's
14 > * behavior changes in a way we care about, re-sync deliberately and update the
15 > * tests.
16 > */
17 >
18 > import { localize } from '../../../../nls.js';
19 >
20 > /**
21 > * Identifier of the integrated browser address bar search engine.
22 > */
23 > export enum BrowserSearchEngineId {
24 > Bing = 'bing',
25 > Google = 'google',
26 > Yahoo = 'yahoo',
27 > DuckDuckGo = 'duckduckgo',
28 > }
29 >
30 > export const BrowserSearchEngineSettingId =
31 > 'workbench.browser.searchEngine';
32 >
33 > /**
34 > * Value of {@link BrowserSearchEngineSettingId} when no search engine is
35 > * selected (address bar search disabled). Selecting any other value both
36 > * enables search and picks the engine.
37 > */
38 > export const BROWSER_SEARCH_NONE = 'none';
39 >
40 > /**
41 > * The address bar search setting value: either `'none'` (search disabled) or a
42 > * specific {@link BrowserSearchEngineId}.
43 > */
44 > export type BrowserSearchEngineValue = BrowserSearchEngineId | typeof BROWSER_SEARCH_NONE;
45 >
46 > /**
47 > * A search engine that can be selected as the integrated browser's default.
48 > */
49 > export interface IBrowserSearchEngine {
50 > readonly id: BrowserSearchEngineId;
51 > /** Human-readable label shown in the settings UI. */
52 > readonly label: string;
53 > /**
54 > * Build a search URL for the given query string. The query is the raw
55 > * (already trimmed) user input; implementations are responsible for
56 > * URL-encoding it.
57 > */
58 > buildSearchUrl(query: string): string;
59 > }
60 >
61 > /**
62 > * Encode a search query for use in a search-engine URL. Matches the encoding
63 > * used by popular browsers: `encodeURIComponent` then replace `%20` with `+`.
64 > */
65 > function encodeQuery(query: string): string { browserSearch.ts ×3
66 > return encodeURIComponent(query).replace(/%20/g, '+');
67 > }
69 > /**
70 > * Ordered list of supported search engines.
71 > */
72 > export const BROWSER_SEARCH_ENGINES: readonly IBrowserSearchEngine[] = [
73 > {
74 > id: BrowserSearchEngineId.Bing,
75 > label: localize('browser.search.engine.bing', "Bing"),
76 > buildSearchUrl: (q) => `https://www.bing.com/search?q=${encodeQuery(q)}`,
77 > },
78 > {
79 > id: BrowserSearchEngineId.Google,
80 > label: localize('browser.search.engine.google', "Google"),
81 > buildSearchUrl: (q) => `https://www.google.com/search?q=${encodeQuery(q)}`,
82 > },
83 > {
84 > id: BrowserSearchEngineId.Yahoo,
85 > label: localize('browser.search.engine.yahoo', "Yahoo!"),
86 > buildSearchUrl: (q) =>
87 > `https://search.yahoo.com/search?p=${encodeQuery(q)}`, browserSearch.ts ×1
89 > {
90 > id: BrowserSearchEngineId.DuckDuckGo,
91 > label: localize('browser.search.engine.duckduckgo', "DuckDuckGo"),
92 > buildSearchUrl: (q) => `https://duckduckgo.com/?q=${encodeQuery(q)}`,
93 > },
94 > ];
95 >
96 > /**
97 > * Classification of an address bar input. Mirrors the four non-deprecated
98 > * values of Chromium's `metrics::OmniboxInputType`:
99 > * - `'empty'`: input is whitespace-only.
100 > * - `'url'`: input is recognized as a navigable URL.
101 > * - `'query'`: input is recognized as a search query (or an invalid URL that
102 > * can only reasonably be treated as a query).
103 > * - `'unknown'`: input is ambiguous — could be a URL (e.g. an intranet host
104 > * or new TLD) or a search; callers should default to search but may offer
105 > * a "did you mean to navigate?" affordance.
106 > */
107 > export type AddressBarInputKind = 'empty' | 'url' | 'query' | 'unknown';
108 >
109 > /**
110 > * Known URL schemes other than http/https and javascript. Anything in this
111 > * set is classified as URL when typed as a leading `scheme:` prefix.
112 > */
113 > const KNOWN_URL_SCHEMES = new Set([
114 > 'file',
115 > 'ftp',
116 > 'ftps',
117 > 'about',
118 > 'data',
119 > 'view-source',
120 > 'mailto',
121 > 'chrome',
122 > 'edge',
123 > 'vscode',
124 > 'vscode-insiders',
125 > ]);
126 >
127 > /**
128 > * All schemes that we recognize as actual URL schemes (used to disambiguate
129 > * `scheme:operand` from `host:port` — e.g. `localhost:3000` looks like a
130 > * scheme syntactically but `localhost` is not a known scheme).
131 > */
132 > const ALL_KNOWN_SCHEMES = new Set<string>([...KNOWN_URL_SCHEMES, 'http', 'https', 'javascript']);
133 >
134 > /**
135 > * Special-cased TLDs from RFC 6761 / RFC 6762 / ICANN that are treated as
136 > * known only when a subdomain is present. `.invalid` is reserved as
137 > * non-navigable.
138 > */
139 > const SUBDOMAIN_REQUIRED_TLDS = new Set(['example', 'test', 'local', 'internal']);
140 >
141 > const SCHEME_REGEX = /^([a-z][a-z0-9+\-.]*):/i;
142 > const JAVASCRIPT_QUERY_REGEX = /^javascript:[^;=().\"]*$/i;
143 > const USERINFO_WITH_PASSWORD_REGEX = /^[^\s:@/?#]+:[^\s@/?#]+@/;
144 > const HOST_CHARS_REGEX = /^[a-zA-Z0-9\-._~%]+$/;
145 > const PORT_REGEX = /^\d+$/;
146 > const IPV4_REGEX = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
147 >
148 > /**
149 > * Canonicalize a hostname using the platform's URL parser. Converts
150 > * non-ASCII (IDN) hostnames to their punycode (`xn--`) form, and validates
151 > * and canonicalizes bracketed IPv6 literals (e.g. `[2001:0db8::0001]` →
152 > * `[2001:db8::1]`). Returns `undefined` if the host can't be canonicalized.
153 > * ASCII non-bracket hosts are returned unchanged (validation happens via
154 > * `HOST_CHARS_REGEX` at the call site).
155 > */
156 > function toAsciiHost(host: string): string | undefined { browserSearch.ts ×12
157 > const needsUrlParse = host.startsWith('[') || !/^[\x00-\x7F]*$/.test(host);
158 > if (!needsUrlParse) {
159 > return host;
160 > }
161 > try { browserSearch.ts ×1
162 > return new URL(`http://${host}`).hostname;
163 > } catch {
164 > return undefined; browserSearch.ts ×4
165 > }
168 > interface IParsedAuthority {
169 > readonly userinfo: string | undefined;
170 > readonly host: string;
171 > readonly port: string | undefined;
172 > readonly pathAndRest: string;
173 > }
174 >
175 > function parseHostAndPath(rest: string): IParsedAuthority { browserSearch.ts ×12
176 > const sepMatch = /[/?#]/.exec(rest);
177 > const authority = sepMatch ? rest.slice(0, sepMatch.index) : rest;
178 > const pathAndRest = sepMatch ? rest.slice(sepMatch.index) : '';
179 >
180 > let userinfo: string | undefined;
181 > let hostport = authority;
182 > const atIdx = authority.lastIndexOf('@');
183 > if (atIdx >= 0) {
184 > userinfo = authority.slice(0, atIdx); browserSearch.ts ×1
185 > hostport = authority.slice(atIdx + 1);
186 > }
188 > let host = hostport;
189 > let port: string | undefined;
190 > if (host.startsWith('[')) {
191 > const end = host.indexOf(']'); browserSearch.ts ×4
192 > if (end >= 0) {
193 > const after = host.slice(end + 1);
194 > if (after.startsWith(':') && PORT_REGEX.test(after.slice(1))) {
195 > port = after.slice(1); browserSearch.ts ×4
196 > host = host.slice(0, end + 1);
197 > } else if (after.length === 0) { browserSearch.ts ×4
198 > host = host.slice(0, end + 1);
199 > }
200 > }
201 > } else { browserSearch.ts ×12
202 > const colonIdx = host.lastIndexOf(':');
203 > if (colonIdx >= 0) {
204 > const maybePort = host.slice(colonIdx + 1); browserSearch.ts ×4
205 > if (PORT_REGEX.test(maybePort)) {
206 > port = maybePort;
207 > host = host.slice(0, colonIdx);
208 > }
209 > }
211 >
212 > return { userinfo, host, port, pathAndRest };
213 > }
215 > function hasKnownTld(host: string): boolean { browserSearch.ts ×6
216 > const trimmed = host.toLowerCase().replace(/\.$/, '');
217 > const labels = trimmed.split('.');
218 > if (labels.length < 2) {
219 > return false; browserSearch.ts ×6
220 > }
221 > const last = labels[labels.length - 1]; browserSearch.ts ×6
222 > if (last === 'invalid') {
223 > return false; browserSearch.ts ×6
224 > }
225 > // Any all-letter last label of length >= 2 is treated as a TLD. This is a browserSearch.ts ×4
226 > // lightweight stand-in for Chromium's Public Suffix List lookup that
227 > // covers ccTLDs, gTLDs, and newer/brand TLDs without maintaining a list.
228 > if (/^[a-z]{2,}$/.test(last)) {
229 > return true;
230 > }
231 // Punycode IDN TLDs.
232 > if (last.startsWith('xn--') && last.length >= 5) { browserSearch.ts ×6
233 return true;
234 }
235 if (SUBDOMAIN_REQUIRED_TLDS.has(last)) {
236 // A subdomain is required (host length must exceed `${tld}.`).
237 return trimmed.length > last.length + 1;
238 }
239 return false;
240 }
242 > /**
243 > * Classify a raw address bar input as one of the four non-deprecated
244 > * `metrics::OmniboxInputType` values: `empty`, `url`, `query`, or `unknown`.
245 > *
246 > * Adapted from Chromium's `AutocompleteInput::Parse`.
247 > * Reference: https://chromium.googlesource.com/chromium/src/+/1a40eab3d2faacd167cc3d78d20f9da98d55b78e/components/omnibox/browser/autocomplete_input.cc#250
248 > *
249 > * - Empty / whitespace-only input → `empty`.
250 > * - Recognized non-http(s) scheme (`file:`, `ftp:`, `about:`, `data:`,
251 > * `view-source:`, `mailto:`, `chrome:`, `edge:`, `vscode:`, …) → `url`.
252 > * - `javascript:` followed by something that doesn't look like code → `unknown`.
253 > * - Unknown scheme that looks like `user:password@host…` → `url`. Other
254 > * unknown schemes (e.g. `site:foo`) → `unknown`.
255 > * - http(s) or scheme-less input is then parsed into authority + path:
256 > * - Whitespace in the host → `query`; whitespace in the userinfo → `unknown`
257 > * (unless an explicit http(s) scheme is present). Whitespace in the
258 > * path/query/fragment is allowed — it is percent-encoded at navigation
259 > * time, matching Chromium (which only rejects whitespace inside the
260 > * host/username, not the rest of the URL).
261 > * - Invalid host characters → `query`.
262 > * - Bracketed IPv6 literal → `url`.
263 > * - Dotted-quad IPv4 with first octet != 0 (or exactly `0.0.0.0`) → `url`;
264 > * other "IPv4-ish" inputs (e.g. `0.1.2.3`, single component like `13.5`)
265 > * fall through to the heuristics below.
266 > * - `localhost` (with optional port/path) → `url`.
267 > * - Explicit http/https scheme → `url`.
268 > * - Trailing slash on the path → `url` (intranet shortcut).
269 > * - Explicit port → `url`.
270 > * - Host with a known TLD (any 2+ letter last label, punycode IDN, or a
271 > * subdomain of `example`/`test`/`local`/`internal`) → `url`.
272 > * - `user@host` (without explicit TLD) → `unknown` (more likely an email).
273 > * - More than one non-host component present → `url`.
274 > * - Anything else (single word, host with unknown TLD) → `unknown`.
275 > *
276 > * Callers typically map `url` → navigate, and `query` / `unknown` → search.
277 > * `empty` is returned for whitespace-only input so callers can short-circuit.
278 > */
279 > export function resolveAddressBarInputType(rawInput: string): AddressBarInputKind {
280 > const trimmed = rawInput.trim(); browserSearch.ts ×8
281 > if (trimmed.length === 0) {
282 > return 'empty'; browserSearch.ts ×1
283 > }
285 > const schemeMatch = SCHEME_REGEX.exec(trimmed);
286 > const candidateScheme = schemeMatch?.[1].toLowerCase(); browserSearch.ts ×8
287 > const afterScheme = schemeMatch ? trimmed.slice(schemeMatch[0].length) : '';
288 > const hasSchemeSeparator = afterScheme.startsWith('//');
289 > // Only treat the leading `xxx:` as a scheme if it's a recognized scheme
290 > // or is followed by `//`. This avoids mis-parsing inputs like
291 > // `localhost:3000` or `sub.example.com:8080/path`, which Chromium's
292 > // URLFixerUpper resolves as host:port URLs rather than scheme operands.
293 > const scheme = candidateScheme && (ALL_KNOWN_SCHEMES.has(candidateScheme) || hasSchemeSeparator)
294 > ? candidateScheme browserSearch.ts ×1
295 > : undefined; browserSearch.ts ×1
296 > const isHttpScheme = scheme === 'http' || scheme === 'https'; browserSearch.ts ×8
297 >
298 > if (scheme && !isHttpScheme) {
299 > if (scheme === 'file') { browserSearch.ts ×3
300 > return 'url'; browserSearch.ts ×2
301 > }
302 > if (scheme === 'javascript') { browserSearch.ts ×3
303 > return JAVASCRIPT_QUERY_REGEX.test(trimmed) ? 'unknown' : 'url'; browserSearch.ts ×1
304 > }
305 > if (KNOWN_URL_SCHEMES.has(scheme)) { browserSearch.ts ×2
306 > return 'url';
307 > }
308 // Recognized as a scheme only because of `//`, but not in our known
309 // set. Treat as URL only if it looks like userinfo with a password.
310 > if (USERINFO_WITH_PASSWORD_REGEX.test(trimmed) && !/\s/.test(trimmed)) { browserSearch.ts ×3
311 return 'url';
312 }
313 return 'unknown';
314 }
316 > // Handle unrecognized scheme that's NOT followed by `//` and NOT a
317 > // plausible host:port (`localhost:3000`). E.g. `site:foo`,
318 > // `unknownscheme:bar` — search operators, classified as `unknown`.
319 > if (candidateScheme && !scheme && !/^\d+(?:[/?#]|$)/.test(afterScheme)) { browserSearch.ts ×8
320 > if (USERINFO_WITH_PASSWORD_REGEX.test(trimmed) && !/\s/.test(trimmed)) { browserSearch.ts ×1
321 > return 'url'; browserSearch.ts ×1
322 > }
323 > return 'unknown'; browserSearch.ts ×6
324 > }
326 > // http / https / scheme-less from here on. Strip the scheme prefix (and
327 > // optional `//`) for authority parsing — but only if we actually
328 > // recognized a scheme above. For inputs like `localhost:3000` where
329 > // `candidateScheme` is set but `scheme` is undefined, we leave the
330 > // colon in place so it's parsed as host:port.
331 > let rest = trimmed;
332 > if (scheme) {
333 > rest = trimmed.slice(schemeMatch![0].length); browserSearch.ts ×2
334 > if (rest.startsWith('//')) {
335 > rest = rest.slice(2);
336 > }
337 > }
339 > const { userinfo, host: rawHost, port, pathAndRest } = parseHostAndPath(rest);
340 >
341 > // Host-less input that starts with `/` is treated as an absolute path URL
342 > // (e.g. `/usr/local/bin`, `//example.com`).
343 > if (rawHost.length === 0) {
344 > return pathAndRest.startsWith('/') ? 'url' : 'query'; browserSearch.ts ×4
345 > }
347 > // Canonicalize the host via the WHATWG URL parser: converts Unicode
348 > // hostnames to punycode/IDN and validates/canonicalizes bracketed IPv6
349 > // literals. Falls back to `query` if the host can't be canonicalized.
350 > const host = toAsciiHost(rawHost);
351 > if (host === undefined) {
352 > return 'query'; browserSearch.ts ×4
353 > }
355 > // A canonicalized bracketed IPv6 literal is a URL.
356 > if (host.startsWith('[') && host.endsWith(']')) { browserSearch.ts ×8
357 > return 'url'; browserSearch.ts ×2
358 > }
360 > // Validate host characters.
361 > if (!HOST_CHARS_REGEX.test(host)) {
362 > return 'query'; browserSearch.ts ×4
363 > }
365 > // IPv4 dotted-quad.
366 > const ipv4Match = IPV4_REGEX.exec(host);
367 > if (ipv4Match) {
368 > const octets = ipv4Match.slice(1, 5).map(Number); browserSearch.ts ×4
369 > if (octets.every(o => o <= 255)) {
370 > const allZero = octets.every(o => o === 0);
371 > if (octets[0] !== 0 || allZero) {
372 > return 'url'; browserSearch.ts ×2
373 > }
374 > // First octet is zero and not 0.0.0.0 — "source IP", not navigable. browserSearch.ts ×4
375 > return 'query';
376 > }
379 > // A space in the userinfo (e.g. "dep missing: @test/") isn't real credentials,
380 > // so treat it as not-a-URL — unless an explicit http(s) scheme is present,
381 > // which wins. Deliberately placed *after* the IPv4/IPv6 returns above:
382 > // Chromium's `AutocompleteInput::Parse` classifies IP-literal hosts as URL
383 > // before this username-space heuristic, so `user [email protected]` and
384 > // `user name@[::1]` stay URLs.
385 > if (userinfo !== undefined && /\s/.test(userinfo) && !isHttpScheme) { browserSearch.ts ×8
386 > return 'unknown'; browserSearch.ts ×1
387 > }
389 > if (host.toLowerCase() === 'localhost') {
390 > return 'url'; browserSearch.ts ×4
391 > }
393 > // Explicit http/https scheme: with a parseable host, we're done.
394 > if (isHttpScheme) {
395 > return 'url'; browserSearch.ts ×2
396 > }
398 > // Trailing slash on the path forces URL (intranet shortcut).
399 > if (pathAndRest.length > 0 && (pathAndRest.endsWith('/') || pathAndRest.endsWith('\\'))) { browserSearch.ts ×8
400 > return 'url'; browserSearch.ts ×4
401 > }
403 > if (port !== undefined) {
404 > return 'url'; browserSearch.ts ×4
405 > }
407 > if (hasKnownTld(host)) {
408 > return 'url'; browserSearch.ts ×4
409 > }
411 > if (userinfo !== undefined) {
412 return 'unknown';
413 }
415 > const hasPath = pathAndRest.startsWith('/');
416 > const hasQuery = pathAndRest.includes('?');
417 > const hasFragment = pathAndRest.includes('#');
418 > const nonHostComponents = (hasPath ? 1 : 0) + (hasQuery ? 1 : 0) + (hasFragment ? 1 : 0); browserSearch.ts ×8
419 > if (nonHostComponents > 1) {
420 return 'url';
421 }
423 > return 'unknown';
424 > }
426 > /**
427 > * Build a search URL for the given query using the specified engine. The
428 > * query is trimmed and collapses internal whitespace before encoding.
429 > */
430 > export function buildSearchUrl(
431 > query: string, browserSearch.ts ×3
432 > engineId: BrowserSearchEngineId,
433 > ): string {
434 > const engine =
435 > BROWSER_SEARCH_ENGINES.find((e) => e.id === engineId) ??
436 > BROWSER_SEARCH_ENGINES[0]; browserSearch.ts ×1
437 > return engine.buildSearchUrl(query.trim().replace(/\s+/g, ' ')); browserSearch.ts ×3
438 > }
440 > /**
441 > * Human-readable label for the given search engine (e.g. "Bing"). Falls back
442 > * to the default engine's label for an unknown id.
443 > */
444 > export function getBrowserSearchEngineLabel(engineId: BrowserSearchEngineId): string {
445 > const engine = browserSearch.ts ×1
446 > BROWSER_SEARCH_ENGINES.find((e) => e.id === engineId) ??
447 > BROWSER_SEARCH_ENGINES[0];
448 > return engine.label;
449 > }