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 }  ; 
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 }  ; 
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