| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent d11a663 commit 5a0d226
1 file changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -21,6 +21,16 @@ const IGNORE_LIST_ID = 'x_google_ignoreList'; | |||
| 21 | 21 | */ | |
| 22 | 22 | const NODE_MODULE_BYTES = Buffer.from('node_modules/', 'utf-8'); | |
| 23 | 23 | ||
| 24 | + /** | ||
| 25 | + * The UTF-8 bytes for the "sources" property key used to locate the sources array. | ||
| 26 | + */ | ||
| 27 | + const SOURCES_KEY_BYTES = Buffer.from('"sources"', 'utf-8'); | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * The UTF-8 bytes for the ignore list identifier to check if already present. | ||
| 31 | + */ | ||
| 32 | + const IGNORE_LIST_BYTES = Buffer.from(`"${IGNORE_LIST_ID}"`, 'utf-8'); | ||
| 33 | + | ||
| 24 | 34 | /** | |
| 25 | 35 | * Minimal sourcemap object required to create the ignore list. | |
| 26 | 36 | */ | |
@@ -29,6 +39,83 @@ interface SourceMap { | |||
| 29 | 39 | [IGNORE_LIST_ID]?: number[]; | |
| 30 | 40 | } | |
| 31 | 41 | ||
| 42 | + function extractSources(contents: Buffer): string[] | undefined { | ||
| 43 | + const sourcesKeyIndex = contents.indexOf(SOURCES_KEY_BYTES); | ||
| 44 | + if (sourcesKeyIndex === -1) { | ||
| 45 | + return undefined; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + // Find the ':' after "sources" | ||
| 49 | + let colonIndex = sourcesKeyIndex + SOURCES_KEY_BYTES.length; | ||
| 50 | + while (colonIndex < contents.length && contents[colonIndex] <= 0x20) { | ||
| 51 | + colonIndex++; | ||
| 52 | + } | ||
| 53 | + if (contents[colonIndex] !== 0x3a /* : */) { | ||
| 54 | + return undefined; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + // Find the '[' for the array | ||
| 58 | + let arrayStartIndex = colonIndex + 1; | ||
| 59 | + while (arrayStartIndex < contents.length && contents[arrayStartIndex] <= 0x20) { | ||
| 60 | + arrayStartIndex++; | ||
| 61 | + } | ||
| 62 | + if (contents[arrayStartIndex] !== 0x5b /* [ */) { | ||
| 63 | + return undefined; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + // Scan until matching ']' | ||
| 67 | + let depth = 0; | ||
| 68 | + let inString = false; | ||
| 69 | + for (let i = arrayStartIndex; i < contents.length; i++) { | ||
| 70 | + const byte = contents[i]; | ||
| 71 | + if (inString) { | ||
| 72 | + if (byte === 0x5c /* \ */) { | ||
| 73 | + i++; // skip escaped character | ||
| 74 | + } else if (byte === 0x22 /* " */) { | ||
| 75 | + inString = false; | ||
| 76 | + } | ||
| 77 | + } else if (byte === 0x22 /* " */) { | ||
| 78 | + inString = true; | ||
| 79 | + } else if (byte === 0x5b /* [ */) { | ||
| 80 | + depth++; | ||
| 81 | + } else if (byte === 0x5d /* ] */) { | ||
| 82 | + depth--; | ||
| 83 | + if (depth === 0) { | ||
| 84 | + try { | ||
| 85 | + const slice = contents.toString('utf-8', arrayStartIndex, i + 1); | ||
| 86 | + const parsed = JSON.parse(slice); | ||
| 87 | + | ||
| 88 | + return Array.isArray(parsed) && parsed.every((s) => typeof s === 'string') | ||
| 89 | + ? (parsed as string[]) | ||
| 90 | + : undefined; | ||
| 91 | + } catch { | ||
| 92 | + return undefined; | ||
| 93 | + } | ||
| 94 | + } | ||
| 95 | + } | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + return undefined; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + function updateSourcemapFast(contents: Buffer, ignoreList: readonly number[]): Buffer | undefined { | ||
| 102 | + let braceIndex = 0; | ||
| 103 | + while (braceIndex < contents.length && contents[braceIndex] <= 0x20) { | ||
| 104 | + braceIndex++; | ||
| 105 | + } | ||
| 106 | + if (contents[braceIndex] !== 0x7b /* { */) { | ||
| 107 | + return undefined; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + const injection = Buffer.from(`"${IGNORE_LIST_ID}":${JSON.stringify(ignoreList)},`, 'utf-8'); | ||
| 111 | + | ||
| 112 | + return Buffer.concat([ | ||
| 113 | + contents.subarray(0, braceIndex + 1), | ||
| 114 | + injection, | ||
| 115 | + contents.subarray(braceIndex + 1), | ||
| 116 | + ]); | ||
| 117 | + } | ||
| 118 | + | ||
| 32 | 119 | /** | |
| 33 | 120 | * Creates an esbuild plugin that updates generated sourcemaps to include the Chrome | |
| 34 | 121 | * DevTools ignore list extension. All source files that originate from a node modules | |
@@ -68,7 +155,40 @@ export function createSourcemapIgnorelistPlugin(): Plugin { | |||
| 68 | 155 | continue; | |
| 69 | 156 | } | |
| 70 | 157 | ||
| 158 | + let fastPathSuccess = false; | ||
| 159 | + if (!contents.includes(IGNORE_LIST_BYTES)) { | ||
| 160 | + const sources = extractSources(contents); | ||
| 161 | + if (sources) { | ||
| 162 | + const ignoreList: number[] = []; | ||
| 163 | + for (let index = 0; index < sources.length; ++index) { | ||
| 164 | + const location = sources[index].indexOf('node_modules/'); | ||
| 165 | + if (location === 0 || (location > 0 && sources[index][location - 1] === '/')) { | ||
| 166 | + ignoreList.push(index); | ||
| 167 | + } | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + if (ignoreList.length === 0) { | ||
| 171 | + continue; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + const updated = updateSourcemapFast(contents, ignoreList); | ||
| 175 | + if (updated) { | ||
| 176 | + file.contents = updated; | ||
| 177 | + fastPathSuccess = true; | ||
| 178 | + } | ||
| 179 | + } | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + if (fastPathSuccess) { | ||
| 183 | + continue; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + // Fallback to full JSON parse/stringify if fast scanning or splicing fails | ||
| 71 | 187 | const map = JSON.parse(contents.toString('utf-8')) as SourceMap; | |
| 188 | + if (map[IGNORE_LIST_ID]) { | ||
| 189 | + continue; | ||
| 190 | + } | ||
| 191 | + | ||
| 72 | 192 | const ignoreList = []; | |
| 73 | 193 | ||
| 74 | 194 | // Check and store the index of each source originating from a node modules directory | |
| Back | FazBrowse Home | New Git URL |
0 commit comments