Skip to content

Commit 728ddb7

Browse files
perf: improve parse identifiers (#20184)
1 parent 04375e8 commit 728ddb7

File tree

2 files changed

+87
-17
lines changed

2 files changed

+87
-17
lines changed

.changeset/poor-hotels-sort.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@fake-scope/fake-pkg": patch
3+
---
4+
5+
The speed of identifier parsing has been improved

lib/util/identifier.js

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ const absolutify = makeCacheableWithContext(_absolutify);
321321
const PATH_QUERY_FRAGMENT_REGEXP =
322322
/^((?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/;
323323
const PATH_QUERY_REGEXP = /^((?:\0.|[^?\0])*)(\?.*)?$/;
324+
const ZERO_ESCAPE_REGEXP = /\0(.)/g;
324325

325326
/** @typedef {{ resource: string, path: string, query: string, fragment: string }} ParsedResource */
326327
/** @typedef {{ resource: string, path: string, query: string }} ParsedResourceWithoutFragment */
@@ -330,15 +331,56 @@ const PATH_QUERY_REGEXP = /^((?:\0.|[^?\0])*)(\?.*)?$/;
330331
* @returns {ParsedResource} parsed parts
331332
*/
332333
const _parseResource = (str) => {
333-
const match =
334-
/** @type {[string, string, string | undefined, string | undefined]} */
335-
(/** @type {unknown} */ (PATH_QUERY_FRAGMENT_REGEXP.exec(str)));
336-
return {
337-
resource: str,
338-
path: match[1].replace(/\0(.)/g, "$1"),
339-
query: match[2] ? match[2].replace(/\0(.)/g, "$1") : "",
340-
fragment: match[3] || ""
341-
};
334+
const firstEscape = str.indexOf("\0");
335+
336+
// Handle `\0`
337+
if (firstEscape !== -1) {
338+
const match =
339+
/** @type {[string, string, string | undefined, string | undefined]} */
340+
(/** @type {unknown} */ (PATH_QUERY_FRAGMENT_REGEXP.exec(str)));
341+
342+
return {
343+
resource: str,
344+
path: match[1].replace(ZERO_ESCAPE_REGEXP, "$1"),
345+
query: match[2] ? match[2].replace(ZERO_ESCAPE_REGEXP, "$1") : "",
346+
fragment: match[3] || ""
347+
};
348+
}
349+
350+
/** @type {ParsedResource} */
351+
const result = { resource: str, path: "", query: "", fragment: "" };
352+
const queryStart = str.indexOf("?");
353+
const fragmentStart = str.indexOf("#");
354+
355+
if (fragmentStart < 0) {
356+
if (queryStart < 0) {
357+
result.path = result.resource;
358+
359+
// No fragment, no query
360+
return result;
361+
}
362+
363+
result.path = str.slice(0, queryStart);
364+
result.query = str.slice(queryStart);
365+
366+
// Query, no fragment
367+
return result;
368+
}
369+
370+
if (queryStart < 0 || fragmentStart < queryStart) {
371+
result.path = str.slice(0, fragmentStart);
372+
result.fragment = str.slice(fragmentStart);
373+
374+
// Fragment, no query
375+
return result;
376+
}
377+
378+
result.path = str.slice(0, queryStart);
379+
result.query = str.slice(queryStart, fragmentStart);
380+
result.fragment = str.slice(fragmentStart);
381+
382+
// Query and fragment
383+
return result;
342384
};
343385

344386
/**
@@ -347,14 +389,37 @@ const _parseResource = (str) => {
347389
* @returns {ParsedResourceWithoutFragment} parsed parts
348390
*/
349391
const _parseResourceWithoutFragment = (str) => {
350-
const match =
351-
/** @type {[string, string, string | undefined]} */
352-
(/** @type {unknown} */ (PATH_QUERY_REGEXP.exec(str)));
353-
return {
354-
resource: str,
355-
path: match[1].replace(/\0(.)/g, "$1"),
356-
query: match[2] ? match[2].replace(/\0(.)/g, "$1") : ""
357-
};
392+
const firstEscape = str.indexOf("\0");
393+
394+
// Handle `\0`
395+
if (firstEscape !== -1) {
396+
const match =
397+
/** @type {[string, string, string | undefined]} */
398+
(/** @type {unknown} */ (PATH_QUERY_REGEXP.exec(str)));
399+
400+
return {
401+
resource: str,
402+
path: match[1].replace(ZERO_ESCAPE_REGEXP, "$1"),
403+
query: match[2] ? match[2].replace(ZERO_ESCAPE_REGEXP, "$1") : ""
404+
};
405+
}
406+
407+
/** @type {ParsedResourceWithoutFragment} */
408+
const result = { resource: str, path: "", query: "" };
409+
const queryStart = str.indexOf("?");
410+
411+
if (queryStart < 0) {
412+
result.path = result.resource;
413+
414+
// No query
415+
return result;
416+
}
417+
418+
result.path = str.slice(0, queryStart);
419+
result.query = str.slice(queryStart);
420+
421+
// Query
422+
return result;
358423
};
359424

360425
/**

0 commit comments

Comments
 (0)