@@ -25,13 +25,13 @@ const {
2525 isDeepEqual,
2626 isDeepStrictEqual
2727} = require ( 'internal/util/comparisons' ) ;
28- const { AssertionError, TypeError } = require ( 'internal/errors' ) ;
28+ const { AssertionError, TypeError, errorCache } = require ( 'internal/errors' ) ;
2929const { openSync, closeSync, readSync } = require ( 'fs' ) ;
3030const { parseExpressionAt } = require ( 'internal/deps/acorn/dist/acorn' ) ;
3131const { inspect } = require ( 'util' ) ;
3232const { EOL } = require ( 'os' ) ;
33+ const nativeModule = require ( 'native_module' ) ;
3334
34- const codeCache = new Map ( ) ;
3535// Escape control characters but not \n and \t to keep the line breaks and
3636// indentation intact.
3737// eslint-disable-next-line no-control-regex
@@ -146,6 +146,60 @@ function getBuffer(fd, assertLine) {
146146 return buffers ;
147147}
148148
149+ function getErrMessage ( call ) {
150+ const filename = call . getFileName ( ) ;
151+ const line = call . getLineNumber ( ) - 1 ;
152+ const column = call . getColumnNumber ( ) - 1 ;
153+ const identifier = `${ filename } ${ line } ${ column } ` ;
154+
155+ if ( errorCache . has ( identifier ) ) {
156+ return errorCache . get ( identifier ) ;
157+ }
158+
159+ // Skip Node.js modules!
160+ if ( filename . endsWith ( '.js' ) && nativeModule . exists ( filename . slice ( 0 , - 3 ) ) ) {
161+ errorCache . set ( identifier , undefined ) ;
162+ return ;
163+ }
164+
165+ var fd ;
166+ try {
167+ fd = openSync ( filename , 'r' , 0o666 ) ;
168+ const buffers = getBuffer ( fd , line ) ;
169+ const code = Buffer . concat ( buffers ) . toString ( 'utf8' ) ;
170+ const nodes = parseExpressionAt ( code , column ) ;
171+ // Node type should be "CallExpression" and some times
172+ // "SequenceExpression".
173+ const node = nodes . type === 'CallExpression' ? nodes : nodes . expressions [ 0 ] ;
174+ const name = node . callee . name ;
175+ // Calling `ok` with .apply or .call is uncommon but we use a simple
176+ // safeguard nevertheless.
177+ if ( name !== 'apply' && name !== 'call' ) {
178+ // Only use `assert` and `assert.ok` to reference the "real API" and
179+ // not user defined function names.
180+ const ok = name === 'ok' ? '.ok' : '' ;
181+ const args = node . arguments ;
182+ var message = code
183+ . slice ( args [ 0 ] . start , args [ args . length - 1 ] . end )
184+ . replace ( escapeSequencesRegExp , escapeFn ) ;
185+ message = 'The expression evaluated to a falsy value:' +
186+ `${ EOL } ${ EOL } assert${ ok } (${ message } )${ EOL } ` ;
187+ }
188+ // Make sure to always set the cache! No matter if the message is
189+ // undefined or not
190+ errorCache . set ( identifier , message ) ;
191+
192+ return message ;
193+
194+ } catch ( e ) {
195+ // Invalidate cache to prevent trying to read this part again.
196+ errorCache . set ( identifier , undefined ) ;
197+ } finally {
198+ if ( fd !== undefined )
199+ closeSync ( fd ) ;
200+ }
201+ }
202+
149203function innerOk ( args , fn ) {
150204 var [ value , message ] = args ;
151205
@@ -168,54 +222,12 @@ function innerOk(args, fn) {
168222 const call = err . stack [ 0 ] ;
169223 Error . prepareStackTrace = tmpPrepare ;
170224
171- const filename = call . getFileName ( ) ;
172- const line = call . getLineNumber ( ) - 1 ;
173- const column = call . getColumnNumber ( ) - 1 ;
174- const identifier = `${ filename } ${ line } ${ column } ` ;
225+ // TODO(BridgeAR): fix the "generatedMessage property"
226+ // Since this is actually a generated message, it has to be
227+ // determined differently from now on.
175228
176- if ( codeCache . has ( identifier ) ) {
177- message = codeCache . get ( identifier ) ;
178- } else {
179- var fd ;
180- try {
181- fd = openSync ( filename , 'r' , 0o666 ) ;
182- const buffers = getBuffer ( fd , line ) ;
183- const code = Buffer . concat ( buffers ) . toString ( 'utf8' ) ;
184- const nodes = parseExpressionAt ( code , column ) ;
185- // Node type should be "CallExpression" and some times
186- // "SequenceExpression".
187- const node = nodes . type === 'CallExpression' ?
188- nodes :
189- nodes . expressions [ 0 ] ;
190- // TODO: fix the "generatedMessage property"
191- // Since this is actually a generated message, it has to be
192- // determined differently from now on.
193-
194- const name = node . callee . name ;
195- // Calling `ok` with .apply or .call is uncommon but we use a simple
196- // safeguard nevertheless.
197- if ( name !== 'apply' && name !== 'call' ) {
198- // Only use `assert` and `assert.ok` to reference the "real API" and
199- // not user defined function names.
200- const ok = name === 'ok' ? '.ok' : '' ;
201- const args = node . arguments ;
202- message = code
203- . slice ( args [ 0 ] . start , args [ args . length - 1 ] . end )
204- . replace ( escapeSequencesRegExp , escapeFn ) ;
205- message = 'The expression evaluated to a falsy value:' +
206- `${ EOL } ${ EOL } assert${ ok } (${ message } )${ EOL } ` ;
207- }
208- // Make sure to always set the cache! No matter if the message is
209- // undefined or not
210- codeCache . set ( identifier , message ) ;
211- } catch ( e ) {
212- // Invalidate cache to prevent trying to read this part again.
213- codeCache . set ( identifier , undefined ) ;
214- } finally {
215- if ( fd !== undefined )
216- closeSync ( fd ) ;
217- }
218- }
229+ // Make sure it would be "null" in case that is used.
230+ message = getErrMessage ( call ) || message ;
219231 }
220232 innerFail ( {
221233 actual : value ,
0 commit comments