| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent a983726 commit b048eae
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -24,31 +24,21 @@ const { | |||
| 24 | 24 | ArrayPrototypeIndexOf, | |
| 25 | 25 | ArrayPrototypeJoin, | |
| 26 | 26 | ArrayPrototypePush, | |
| 27 | - ArrayPrototypeShift, | ||
| 28 | 27 | ArrayPrototypeSlice, | |
| 29 | 28 | Error, | |
| 30 | - ErrorCaptureStackTrace, | ||
| 31 | - FunctionPrototypeBind, | ||
| 32 | 29 | NumberIsNaN, | |
| 33 | 30 | ObjectAssign, | |
| 34 | 31 | ObjectIs, | |
| 35 | 32 | ObjectKeys, | |
| 36 | 33 | ObjectPrototypeIsPrototypeOf, | |
| 37 | 34 | ReflectApply, | |
| 38 | 35 | RegExpPrototypeExec, | |
| 39 | - RegExpPrototypeSymbolReplace, | ||
| 40 | - SafeMap, | ||
| 41 | 36 | String, | |
| 42 | - StringPrototypeCharCodeAt, | ||
| 43 | - StringPrototypeIncludes, | ||
| 44 | 37 | StringPrototypeIndexOf, | |
| 45 | - StringPrototypeReplace, | ||
| 46 | 38 | StringPrototypeSlice, | |
| 47 | 39 | StringPrototypeSplit, | |
| 48 | - StringPrototypeStartsWith, | ||
| 49 | 40 | } = primordials; | |
| 50 | 41 | ||
| 51 | - const { Buffer } = require('buffer'); | ||
| 52 | 42 | const { | |
| 53 | 43 | codes: { | |
| 54 | 44 | ERR_AMBIGUOUS_ARGUMENT, | |
@@ -57,53 +47,27 @@ const { | |||
| 57 | 47 | ERR_INVALID_RETURN_VALUE, | |
| 58 | 48 | ERR_MISSING_ARGS, | |
| 59 | 49 | }, | |
| 60 | - isErrorStackTraceLimitWritable, | ||
| 61 | - overrideStackTrace, | ||
| 62 | 50 | } = require('internal/errors'); | |
| 63 | 51 | const AssertionError = require('internal/assert/assertion_error'); | |
| 64 | - const { openSync, closeSync, readSync } = require('fs'); | ||
| 65 | 52 | const { inspect } = require('internal/util/inspect'); | |
| 66 | 53 | const { isPromise, isRegExp } = require('internal/util/types'); | |
| 67 | - const { EOL } = require('internal/constants'); | ||
| 68 | - const { BuiltinModule } = require('internal/bootstrap/realm'); | ||
| 69 | 54 | const { isError, deprecate } = require('internal/util'); | |
| 55 | + const { innerOk } = require('internal/assert/utils'); | ||
| 70 | 56 | ||
| 71 | - const errorCache = new SafeMap(); | ||
| 72 | 57 | const CallTracker = require('internal/assert/calltracker'); | |
| 73 | 58 | const { | |
| 74 | 59 | validateFunction, | |
| 75 | 60 | } = require('internal/validators'); | |
| 76 | - const { fileURLToPath } = require('internal/url'); | ||
| 77 | 61 | ||
| 78 | 62 | let isDeepEqual; | |
| 79 | 63 | let isDeepStrictEqual; | |
| 80 | - let parseExpressionAt; | ||
| 81 | - let findNodeAround; | ||
| 82 | - let tokenizer; | ||
| 83 | - let decoder; | ||
| 84 | 64 | ||
| 85 | 65 | function lazyLoadComparison() { | |
| 86 | 66 | const comparison = require('internal/util/comparisons'); | |
| 87 | 67 | isDeepEqual = comparison.isDeepEqual; | |
| 88 | 68 | isDeepStrictEqual = comparison.isDeepStrictEqual; | |
| 89 | 69 | } | |
| 90 | 70 | ||
| 91 | - // Escape control characters but not \n and \t to keep the line breaks and | ||
| 92 | - // indentation intact. | ||
| 93 | - // eslint-disable-next-line no-control-regex | ||
| 94 | - const escapeSequencesRegExp = /[\x00-\x08\x0b\x0c\x0e-\x1f]/g; | ||
| 95 | - const meta = [ | ||
| 96 | - '\\u0000', '\\u0001', '\\u0002', '\\u0003', '\\u0004', | ||
| 97 | - '\\u0005', '\\u0006', '\\u0007', '\\b', '', | ||
| 98 | - '', '\\u000b', '\\f', '', '\\u000e', | ||
| 99 | - '\\u000f', '\\u0010', '\\u0011', '\\u0012', '\\u0013', | ||
| 100 | - '\\u0014', '\\u0015', '\\u0016', '\\u0017', '\\u0018', | ||
| 101 | - '\\u0019', '\\u001a', '\\u001b', '\\u001c', '\\u001d', | ||
| 102 | - '\\u001e', '\\u001f', | ||
| 103 | - ]; | ||
| 104 | - | ||
| 105 | - const escapeFn = (str) => meta[StringPrototypeCharCodeAt(str, 0)]; | ||
| 106 | - | ||
| 107 | 71 | let warned = false; | |
| 108 | 72 | ||
| 109 | 73 | // The assert module provides functions that throw | |
@@ -178,237 +142,6 @@ assert.fail = fail; | |||
| 178 | 142 | // The AssertionError is defined in internal/error. | |
| 179 | 143 | assert.AssertionError = AssertionError; | |
| 180 | 144 | ||
| 181 | - function findColumn(fd, column, code) { | ||
| 182 | - if (code.length > column + 100) { | ||
| 183 | - try { | ||
| 184 | - return parseCode(code, column); | ||
| 185 | - } catch { | ||
| 186 | - // End recursion in case no code could be parsed. The expression should | ||
| 187 | - // have been found after 2500 characters, so stop trying. | ||
| 188 | - if (code.length - column > 2500) { | ||
| 189 | - // eslint-disable-next-line no-throw-literal | ||
| 190 | - throw null; | ||
| 191 | - } | ||
| 192 | - } | ||
| 193 | - } | ||
| 194 | - // Read up to 2500 bytes more than necessary in columns. That way we address | ||
| 195 | - // multi byte characters and read enough data to parse the code. | ||
| 196 | - const bytesToRead = column - code.length + 2500; | ||
| 197 | - const buffer = Buffer.allocUnsafe(bytesToRead); | ||
| 198 | - const bytesRead = readSync(fd, buffer, 0, bytesToRead); | ||
| 199 | - code += decoder.write(buffer.slice(0, bytesRead)); | ||
| 200 | - // EOF: fast path. | ||
| 201 | - if (bytesRead < bytesToRead) { | ||
| 202 | - return parseCode(code, column); | ||
| 203 | - } | ||
| 204 | - // Read potentially missing code. | ||
| 205 | - return findColumn(fd, column, code); | ||
| 206 | - } | ||
| 207 | - | ||
| 208 | - function getCode(fd, line, column) { | ||
| 209 | - let bytesRead = 0; | ||
| 210 | - if (line === 0) { | ||
| 211 | - // Special handle line number one. This is more efficient and simplifies the | ||
| 212 | - // rest of the algorithm. Read more than the regular column number in bytes | ||
| 213 | - // to prevent multiple reads in case multi byte characters are used. | ||
| 214 | - return findColumn(fd, column, ''); | ||
| 215 | - } | ||
| 216 | - let lines = 0; | ||
| 217 | - // Prevent blocking the event loop by limiting the maximum amount of | ||
| 218 | - // data that may be read. | ||
| 219 | - let maxReads = 32; // bytesPerRead * maxReads = 512 KiB | ||
| 220 | - const bytesPerRead = 16384; | ||
| 221 | - // Use a single buffer up front that is reused until the call site is found. | ||
| 222 | - let buffer = Buffer.allocUnsafe(bytesPerRead); | ||
| 223 | - while (maxReads-- !== 0) { | ||
| 224 | - // Only allocate a new buffer in case the needed line is found. All data | ||
| 225 | - // before that can be discarded. | ||
| 226 | - buffer = lines < line ? buffer : Buffer.allocUnsafe(bytesPerRead); | ||
| 227 | - bytesRead = readSync(fd, buffer, 0, bytesPerRead); | ||
| 228 | - // Read the buffer until the required code line is found. | ||
| 229 | - for (let i = 0; i < bytesRead; i++) { | ||
| 230 | - if (buffer[i] === 10 && ++lines === line) { | ||
| 231 | - // If the end of file is reached, directly parse the code and return. | ||
| 232 | - if (bytesRead < bytesPerRead) { | ||
| 233 | - return parseCode(buffer.toString('utf8', i + 1, bytesRead), column); | ||
| 234 | - } | ||
| 235 | - // Check if the read code is sufficient or read more until the whole | ||
| 236 | - // expression is read. Make sure multi byte characters are preserved | ||
| 237 | - // properly by using the decoder. | ||
| 238 | - const code = decoder.write(buffer.slice(i + 1, bytesRead)); | ||
| 239 | - return findColumn(fd, column, code); | ||
| 240 | - } | ||
| 241 | - } | ||
| 242 | - } | ||
| 243 | - } | ||
| 244 | - | ||
| 245 | - function parseCode(code, offset) { | ||
| 246 | - // Lazy load acorn. | ||
| 247 | - if (parseExpressionAt === undefined) { | ||
| 248 | - const Parser = require('internal/deps/acorn/acorn/dist/acorn').Parser; | ||
| 249 | - ({ findNodeAround } = require('internal/deps/acorn/acorn-walk/dist/walk')); | ||
| 250 | - | ||
| 251 | - parseExpressionAt = FunctionPrototypeBind(Parser.parseExpressionAt, Parser); | ||
| 252 | - tokenizer = FunctionPrototypeBind(Parser.tokenizer, Parser); | ||
| 253 | - } | ||
| 254 | - let node; | ||
| 255 | - let start; | ||
| 256 | - // Parse the read code until the correct expression is found. | ||
| 257 | - for (const token of tokenizer(code, { ecmaVersion: 'latest' })) { | ||
| 258 | - start = token.start; | ||
| 259 | - if (start > offset) { | ||
| 260 | - // No matching expression found. This could happen if the assert | ||
| 261 | - // expression is bigger than the provided buffer. | ||
| 262 | - break; | ||
| 263 | - } | ||
| 264 | - try { | ||
| 265 | - node = parseExpressionAt(code, start, { ecmaVersion: 'latest' }); | ||
| 266 | - // Find the CallExpression in the tree. | ||
| 267 | - node = findNodeAround(node, offset, 'CallExpression'); | ||
| 268 | - if (node?.node.end >= offset) { | ||
| 269 | - return [ | ||
| 270 | - node.node.start, | ||
| 271 | - StringPrototypeReplace(StringPrototypeSlice(code, | ||
| 272 | - node.node.start, node.node.end), | ||
| 273 | - escapeSequencesRegExp, escapeFn), | ||
| 274 | - ]; | ||
| 275 | - } | ||
| 276 | - // eslint-disable-next-line no-unused-vars | ||
| 277 | - } catch (err) { | ||
| 278 | - continue; | ||
| 279 | - } | ||
| 280 | - } | ||
| 281 | - // eslint-disable-next-line no-throw-literal | ||
| 282 | - throw null; | ||
| 283 | - } | ||
| 284 | - | ||
| 285 | - function getErrMessage(message, fn) { | ||
| 286 | - const tmpLimit = Error.stackTraceLimit; | ||
| 287 | - const errorStackTraceLimitIsWritable = isErrorStackTraceLimitWritable(); | ||
| 288 | - // Make sure the limit is set to 1. Otherwise it could fail (<= 0) or it | ||
| 289 | - // does to much work. | ||
| 290 | - if (errorStackTraceLimitIsWritable) Error.stackTraceLimit = 1; | ||
| 291 | - // We only need the stack trace. To minimize the overhead use an object | ||
| 292 | - // instead of an error. | ||
| 293 | - const err = {}; | ||
| 294 | - ErrorCaptureStackTrace(err, fn); | ||
| 295 | - if (errorStackTraceLimitIsWritable) Error.stackTraceLimit = tmpLimit; | ||
| 296 | - | ||
| 297 | - overrideStackTrace.set(err, (_, stack) => stack); | ||
| 298 | - const call = err.stack[0]; | ||
| 299 | - | ||
| 300 | - let filename = call.getFileName(); | ||
| 301 | - const line = call.getLineNumber() - 1; | ||
| 302 | - let column = call.getColumnNumber() - 1; | ||
| 303 | - let identifier; | ||
| 304 | - let code; | ||
| 305 | - | ||
| 306 | - if (filename) { | ||
| 307 | - identifier = `${filename}${line}${column}`; | ||
| 308 | - | ||
| 309 | - // Skip Node.js modules! | ||
| 310 | - if (StringPrototypeStartsWith(filename, 'node:') && | ||
| 311 | - BuiltinModule.exists(StringPrototypeSlice(filename, 5))) { | ||
| 312 | - errorCache.set(identifier, undefined); | ||
| 313 | - return; | ||
| 314 | - } | ||
| 315 | - } else { | ||
| 316 | - return message; | ||
| 317 | - } | ||
| 318 | - | ||
| 319 | - if (errorCache.has(identifier)) { | ||
| 320 | - return errorCache.get(identifier); | ||
| 321 | - } | ||
| 322 | - | ||
| 323 | - let fd; | ||
| 324 | - try { | ||
| 325 | - // Set the stack trace limit to zero. This makes sure unexpected token | ||
| 326 | - // errors are handled faster. | ||
| 327 | - if (errorStackTraceLimitIsWritable) Error.stackTraceLimit = 0; | ||
| 328 | - | ||
| 329 | - if (filename) { | ||
| 330 | - if (decoder === undefined) { | ||
| 331 | - const { StringDecoder } = require('string_decoder'); | ||
| 332 | - decoder = new StringDecoder('utf8'); | ||
| 333 | - } | ||
| 334 | - | ||
| 335 | - // ESM file prop is a file proto. Convert that to path. | ||
| 336 | - // This ensure opensync will not throw ENOENT for ESM files. | ||
| 337 | - const fileProtoPrefix = 'file://'; | ||
| 338 | - if (StringPrototypeStartsWith(filename, fileProtoPrefix)) { | ||
| 339 | - filename = fileURLToPath(filename); | ||
| 340 | - } | ||
| 341 | - | ||
| 342 | - fd = openSync(filename, 'r', 0o666); | ||
| 343 | - // Reset column and message. | ||
| 344 | - ({ 0: column, 1: message } = getCode(fd, line, column)); | ||
| 345 | - // Flush unfinished multi byte characters. | ||
| 346 | - decoder.end(); | ||
| 347 | - } else { | ||
| 348 | - for (let i = 0; i < line; i++) { | ||
| 349 | - code = StringPrototypeSlice(code, | ||
| 350 | - StringPrototypeIndexOf(code, '\n') + 1); | ||
| 351 | - } | ||
| 352 | - ({ 0: column, 1: message } = parseCode(code, column)); | ||
| 353 | - } | ||
| 354 | - // Always normalize indentation, otherwise the message could look weird. | ||
| 355 | - if (StringPrototypeIncludes(message, '\n')) { | ||
| 356 | - if (EOL === '\r\n') { | ||
| 357 | - message = RegExpPrototypeSymbolReplace(/\r\n/g, message, '\n'); | ||
| 358 | - } | ||
| 359 | - const frames = StringPrototypeSplit(message, '\n'); | ||
| 360 | - message = ArrayPrototypeShift(frames); | ||
| 361 | - for (const frame of frames) { | ||
| 362 | - let pos = 0; | ||
| 363 | - while (pos < column && (frame[pos] === ' ' || frame[pos] === '\t')) { | ||
| 364 | - pos++; | ||
| 365 | - } | ||
| 366 | - message += `\n ${StringPrototypeSlice(frame, pos)}`; | ||
| 367 | - } | ||
| 368 | - } | ||
| 369 | - message = `The expression evaluated to a falsy value:\n\n ${message}\n`; | ||
| 370 | - // Make sure to always set the cache! No matter if the message is | ||
| 371 | - // undefined or not | ||
| 372 | - errorCache.set(identifier, message); | ||
| 373 | - | ||
| 374 | - return message; | ||
| 375 | - } catch { | ||
| 376 | - // Invalidate cache to prevent trying to read this part again. | ||
| 377 | - errorCache.set(identifier, undefined); | ||
| 378 | - } finally { | ||
| 379 | - // Reset limit. | ||
| 380 | - if (errorStackTraceLimitIsWritable) Error.stackTraceLimit = tmpLimit; | ||
| 381 | - if (fd !== undefined) | ||
| 382 | - closeSync(fd); | ||
| 383 | - } | ||
| 384 | - } | ||
| 385 | - | ||
| 386 | - function innerOk(fn, argLen, value, message) { | ||
| 387 | - if (!value) { | ||
| 388 | - let generatedMessage = false; | ||
| 389 | - | ||
| 390 | - if (argLen === 0) { | ||
| 391 | - generatedMessage = true; | ||
| 392 | - message = 'No value argument passed to `assert.ok()`'; | ||
| 393 | - } else if (message == null) { | ||
| 394 | - generatedMessage = true; | ||
| 395 | - message = getErrMessage(message, fn); | ||
| 396 | - } else if (isError(message)) { | ||
| 397 | - throw message; | ||
| 398 | - } | ||
| 399 | - | ||
| 400 | - const err = new AssertionError({ | ||
| 401 | - actual: value, | ||
| 402 | - expected: true, | ||
| 403 | - message, | ||
| 404 | - operator: '==', | ||
| 405 | - stackStartFn: fn, | ||
| 406 | - }); | ||
| 407 | - err.generatedMessage = generatedMessage; | ||
| 408 | - throw err; | ||
| 409 | - } | ||
| 410 | - } | ||
| 411 | - | ||
| 412 | 145 | /** | |
| 413 | 146 | * Pure assertion tests whether a value is truthy, as determined | |
| 414 | 147 | * by !!value. | |
| Back | FazBrowse Home | New Git URL |
0 commit comments