11'use strict' ; 
22
33const  { 
4-   ArrayPrototypeShift, 
54  Error, 
65  ErrorCaptureStackTrace, 
7-   FunctionPrototypeBind, 
8-   RegExpPrototypeSymbolReplace, 
9-   SafeMap, 
106  StringPrototypeCharCodeAt, 
11-   StringPrototypeIncludes, 
127  StringPrototypeReplace, 
13-   StringPrototypeSlice, 
14-   StringPrototypeSplit, 
15-   StringPrototypeStartsWith, 
168}  =  primordials ; 
179
18- const  {  Buffer }  =  require ( 'buffer' ) ; 
1910const  { 
2011  isErrorStackTraceLimitWritable, 
21-   overrideStackTrace, 
2212}  =  require ( 'internal/errors' ) ; 
2313const  AssertionError  =  require ( 'internal/assert/assertion_error' ) ; 
24- const  {  openSync,  closeSync,  readSync }  =  require ( 'fs' ) ; 
25- const  {  EOL  }  =  require ( 'internal/constants' ) ; 
26- const  {  BuiltinModule }  =  require ( 'internal/bootstrap/realm' ) ; 
2714const  {  isError }  =  require ( 'internal/util' ) ; 
2815
29- const  errorCache  =  new  SafeMap ( ) ; 
30- const  {  fileURLToPath }  =  require ( 'internal/url' ) ; 
31- 
32- let  parseExpressionAt ; 
33- let  findNodeAround ; 
34- let  tokenizer ; 
35- let  decoder ; 
16+ const  { 
17+   getErrorSourceExpression, 
18+ }  =  require ( 'internal/errors/error_source' ) ; 
3619
3720// Escape control characters but not \n and \t to keep the line breaks and 
3821// indentation intact. 
@@ -50,111 +33,7 @@ const meta = [
5033
5134const  escapeFn  =  ( str )  =>  meta [ StringPrototypeCharCodeAt ( str ,  0 ) ] ; 
5235
53- function  findColumn ( fd ,  column ,  code )  { 
54-   if  ( code . length  >  column  +  100 )  { 
55-     try  { 
56-       return  parseCode ( code ,  column ) ; 
57-     }  catch  { 
58-       // End recursion in case no code could be parsed. The expression should 
59-       // have been found after 2500 characters, so stop trying. 
60-       if  ( code . length  -  column  >  2500 )  { 
61-         // eslint-disable-next-line no-throw-literal 
62-         throw  null ; 
63-       } 
64-     } 
65-   } 
66-   // Read up to 2500 bytes more than necessary in columns. That way we address 
67-   // multi byte characters and read enough data to parse the code. 
68-   const  bytesToRead  =  column  -  code . length  +  2500 ; 
69-   const  buffer  =  Buffer . allocUnsafe ( bytesToRead ) ; 
70-   const  bytesRead  =  readSync ( fd ,  buffer ,  0 ,  bytesToRead ) ; 
71-   code  +=  decoder . write ( buffer . slice ( 0 ,  bytesRead ) ) ; 
72-   // EOF: fast path. 
73-   if  ( bytesRead  <  bytesToRead )  { 
74-     return  parseCode ( code ,  column ) ; 
75-   } 
76-   // Read potentially missing code. 
77-   return  findColumn ( fd ,  column ,  code ) ; 
78- } 
79- 
80- function  getCode ( fd ,  line ,  column )  { 
81-   let  bytesRead  =  0 ; 
82-   if  ( line  ===  0 )  { 
83-     // Special handle line number one. This is more efficient and simplifies the 
84-     // rest of the algorithm. Read more than the regular column number in bytes 
85-     // to prevent multiple reads in case multi byte characters are used. 
86-     return  findColumn ( fd ,  column ,  '' ) ; 
87-   } 
88-   let  lines  =  0 ; 
89-   // Prevent blocking the event loop by limiting the maximum amount of 
90-   // data that may be read. 
91-   let  maxReads  =  32 ;  // bytesPerRead * maxReads = 512 KiB 
92-   const  bytesPerRead  =  16384 ; 
93-   // Use a single buffer up front that is reused until the call site is found. 
94-   let  buffer  =  Buffer . allocUnsafe ( bytesPerRead ) ; 
95-   while  ( maxReads --  !==  0 )  { 
96-     // Only allocate a new buffer in case the needed line is found. All data 
97-     // before that can be discarded. 
98-     buffer  =  lines  <  line  ? buffer  : Buffer . allocUnsafe ( bytesPerRead ) ; 
99-     bytesRead  =  readSync ( fd ,  buffer ,  0 ,  bytesPerRead ) ; 
100-     // Read the buffer until the required code line is found. 
101-     for  ( let  i  =  0 ;  i  <  bytesRead ;  i ++ )  { 
102-       if  ( buffer [ i ]  ===  10  &&  ++ lines  ===  line )  { 
103-         // If the end of file is reached, directly parse the code and return. 
104-         if  ( bytesRead  <  bytesPerRead )  { 
105-           return  parseCode ( buffer . toString ( 'utf8' ,  i  +  1 ,  bytesRead ) ,  column ) ; 
106-         } 
107-         // Check if the read code is sufficient or read more until the whole 
108-         // expression is read. Make sure multi byte characters are preserved 
109-         // properly by using the decoder. 
110-         const  code  =  decoder . write ( buffer . slice ( i  +  1 ,  bytesRead ) ) ; 
111-         return  findColumn ( fd ,  column ,  code ) ; 
112-       } 
113-     } 
114-   } 
115- } 
116- 
117- function  parseCode ( code ,  offset )  { 
118-   // Lazy load acorn. 
119-   if  ( parseExpressionAt  ===  undefined )  { 
120-     const  Parser  =  require ( 'internal/deps/acorn/acorn/dist/acorn' ) . Parser ; 
121-     ( {  findNodeAround }  =  require ( 'internal/deps/acorn/acorn-walk/dist/walk' ) ) ; 
122- 
123-     parseExpressionAt  =  FunctionPrototypeBind ( Parser . parseExpressionAt ,  Parser ) ; 
124-     tokenizer  =  FunctionPrototypeBind ( Parser . tokenizer ,  Parser ) ; 
125-   } 
126-   let  node ; 
127-   let  start ; 
128-   // Parse the read code until the correct expression is found. 
129-   for  ( const  token  of  tokenizer ( code ,  {  ecmaVersion : 'latest'  } ) )  { 
130-     start  =  token . start ; 
131-     if  ( start  >  offset )  { 
132-       // No matching expression found. This could happen if the assert 
133-       // expression is bigger than the provided buffer. 
134-       break ; 
135-     } 
136-     try  { 
137-       node  =  parseExpressionAt ( code ,  start ,  {  ecmaVersion : 'latest'  } ) ; 
138-       // Find the CallExpression in the tree. 
139-       node  =  findNodeAround ( node ,  offset ,  'CallExpression' ) ; 
140-       if  ( node ?. node . end  >=  offset )  { 
141-         return  [ 
142-           node . node . start , 
143-           StringPrototypeReplace ( StringPrototypeSlice ( code , 
144-                                                       node . node . start ,  node . node . end ) , 
145-                                  escapeSequencesRegExp ,  escapeFn ) , 
146-         ] ; 
147-       } 
148-     // eslint-disable-next-line no-unused-vars 
149-     }  catch  ( err )  { 
150-       continue ; 
151-     } 
152-   } 
153-   // eslint-disable-next-line no-throw-literal 
154-   throw  null ; 
155- } 
156- 
157- function  getErrMessage ( message ,  fn )  { 
36+ function  getErrMessage ( fn )  { 
15837  const  tmpLimit  =  Error . stackTraceLimit ; 
15938  const  errorStackTraceLimitIsWritable  =  isErrorStackTraceLimitWritable ( ) ; 
16039  // Make sure the limit is set to 1. Otherwise it could fail (<= 0) or it 
@@ -166,85 +45,10 @@ function getErrMessage(message, fn) {
16645  ErrorCaptureStackTrace ( err ,  fn ) ; 
16746  if  ( errorStackTraceLimitIsWritable )  Error . stackTraceLimit  =  tmpLimit ; 
16847
169-   overrideStackTrace . set ( err ,  ( _ ,  stack )  =>  stack ) ; 
170-   const  call  =  err . stack [ 0 ] ; 
171- 
172-   let  filename  =  call . getFileName ( ) ; 
173-   const  line  =  call . getLineNumber ( )  -  1 ; 
174-   let  column  =  call . getColumnNumber ( )  -  1 ; 
175-   let  identifier ; 
176- 
177-   if  ( filename )  { 
178-     identifier  =  `${ filename } ${ line } ${ column }  ` ; 
179- 
180-     // Skip Node.js modules! 
181-     if  ( StringPrototypeStartsWith ( filename ,  'node:' )  && 
182-         BuiltinModule . exists ( StringPrototypeSlice ( filename ,  5 ) ) )  { 
183-       errorCache . set ( identifier ,  undefined ) ; 
184-       return ; 
185-     } 
186-   }  else  { 
187-     return  message ; 
188-   } 
189- 
190-   if  ( errorCache . has ( identifier ) )  { 
191-     return  errorCache . get ( identifier ) ; 
192-   } 
193- 
194-   let  fd ; 
195-   try  { 
196-     // Set the stack trace limit to zero. This makes sure unexpected token 
197-     // errors are handled faster. 
198-     if  ( errorStackTraceLimitIsWritable )  Error . stackTraceLimit  =  0 ; 
199- 
200-     if  ( decoder  ===  undefined )  { 
201-       const  {  StringDecoder }  =  require ( 'string_decoder' ) ; 
202-       decoder  =  new  StringDecoder ( 'utf8' ) ; 
203-     } 
204- 
205-     // ESM file prop is a file proto. Convert that to path. 
206-     // This ensure opensync will not throw ENOENT for ESM files. 
207-     const  fileProtoPrefix  =  'file://' ; 
208-     if  ( StringPrototypeStartsWith ( filename ,  fileProtoPrefix ) )  { 
209-       filename  =  fileURLToPath ( filename ) ; 
210-     } 
211- 
212-     fd  =  openSync ( filename ,  'r' ,  0o666 ) ; 
213-     // Reset column and message. 
214-     ( {  0 : column ,  1 : message  }  =  getCode ( fd ,  line ,  column ) ) ; 
215-     // Flush unfinished multi byte characters. 
216-     decoder . end ( ) ; 
217- 
218-     // Always normalize indentation, otherwise the message could look weird. 
219-     if  ( StringPrototypeIncludes ( message ,  '\n' ) )  { 
220-       if  ( EOL  ===  '\r\n' )  { 
221-         message  =  RegExpPrototypeSymbolReplace ( / \r \n / g,  message ,  '\n' ) ; 
222-       } 
223-       const  frames  =  StringPrototypeSplit ( message ,  '\n' ) ; 
224-       message  =  ArrayPrototypeShift ( frames ) ; 
225-       for  ( let  i  =  0 ;  i  <  frames . length ;  i ++ )  { 
226-         const  frame  =  frames [ i ] ; 
227-         let  pos  =  0 ; 
228-         while  ( pos  <  column  &&  ( frame [ pos ]  ===  ' '  ||  frame [ pos ]  ===  '\t' ) )  { 
229-           pos ++ ; 
230-         } 
231-         message  +=  `\n  ${ StringPrototypeSlice ( frame ,  pos ) }  ` ; 
232-       } 
233-     } 
234-     message  =  `The expression evaluated to a falsy value:\n\n  ${ message }  \n` ; 
235-     // Make sure to always set the cache! No matter if the message is 
236-     // undefined or not 
237-     errorCache . set ( identifier ,  message ) ; 
238- 
239-     return  message ; 
240-   }  catch  { 
241-     // Invalidate cache to prevent trying to read this part again. 
242-     errorCache . set ( identifier ,  undefined ) ; 
243-   }  finally  { 
244-     // Reset limit. 
245-     if  ( errorStackTraceLimitIsWritable )  Error . stackTraceLimit  =  tmpLimit ; 
246-     if  ( fd  !==  undefined ) 
247-       closeSync ( fd ) ; 
48+   let  source  =  getErrorSourceExpression ( err ) ; 
49+   if  ( source )  { 
50+     source  =  StringPrototypeReplace ( source ,  escapeSequencesRegExp ,  escapeFn ) ; 
51+     return  `The expression evaluated to a falsy value:\n\n  ${ source }  \n` ; 
24852  } 
24953} 
25054
@@ -257,7 +61,7 @@ function innerOk(fn, argLen, value, message) {
25761      message  =  'No value argument passed to `assert.ok()`' ; 
25862    }  else  if  ( message  ==  null )  { 
25963      generatedMessage  =  true ; 
260-       message  =  getErrMessage ( message ,   fn ) ; 
64+       message  =  getErrMessage ( fn ) ; 
26165    }  else  if  ( isError ( message ) )  { 
26266      throw  message ; 
26367    } 
0 commit comments