| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -436,7 +436,7 @@ corresponding argument. Supported specifiers are: | |||
| 436 | 436 | ||
| 437 | 437 | * `%s`: `String` will be used to convert all values except `BigInt`, `Object` | |
| 438 | 438 | and `-0`. `BigInt` values will be represented with an `n` and Objects that | |
| 439 | - have no user defined `toString` function are inspected using `util.inspect()` | ||
| 439 | + have neither a user defined `toString` function nor `Symbol.toPrimitive` function are inspected using `util.inspect()` | ||
| 440 | 440 | with options `{ depth: 0, colors: false, compact: 3 }`. | |
| 441 | 441 | * `%d`: `Number` will be used to convert all values except `BigInt` and | |
| 442 | 442 | `Symbol`. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2166,27 +2166,32 @@ function hasBuiltInToString(value) { | |||
| 2166 | 2166 | value = proxyTarget; | |
| 2167 | 2167 | } | |
| 2168 | 2168 | ||
| 2169 | - // Check if value has a custom Symbol.toPrimitive transformation. | ||
| 2170 | - if (typeof value[SymbolToPrimitive] === 'function') { | ||
| 2171 | - return false; | ||
| 2172 | - } | ||
| 2169 | + let hasOwnToString = ObjectPrototypeHasOwnProperty; | ||
| 2170 | + let hasOwnToPrimitive = ObjectPrototypeHasOwnProperty; | ||
| 2173 | 2171 | ||
| 2174 | - // Count objects that have no `toString` function as built-in. | ||
| 2172 | + // Count objects without `toString` and `Symbol.toPrimitive` function as built-in. | ||
| 2175 | 2173 | if (typeof value.toString !== 'function') { | |
| 2176 | - return true; | ||
| 2177 | - } | ||
| 2178 | - | ||
| 2179 | - // The object has a own `toString` property. Thus it's not not a built-in one. | ||
| 2180 | - if (ObjectPrototypeHasOwnProperty(value, 'toString')) { | ||
| 2174 | + if (typeof value[SymbolToPrimitive] !== 'function') { | ||
| 2175 | + return true; | ||
| 2176 | + } else if (ObjectPrototypeHasOwnProperty(value, SymbolToPrimitive)) { | ||
| 2177 | + return false; | ||
| 2178 | + } | ||
| 2179 | + hasOwnToString = returnFalse; | ||
| 2180 | + } else if (ObjectPrototypeHasOwnProperty(value, 'toString')) { | ||
| 2181 | + return false; | ||
| 2182 | + } else if (typeof value[SymbolToPrimitive] !== 'function') { | ||
| 2183 | + hasOwnToPrimitive = returnFalse; | ||
| 2184 | + } else if (ObjectPrototypeHasOwnProperty(value, SymbolToPrimitive)) { | ||
| 2181 | 2185 | return false; | |
| 2182 | 2186 | } | |
| 2183 | 2187 | ||
| 2184 | - // Find the object that has the `toString` property as own property in the | ||
| 2185 | - // prototype chain. | ||
| 2188 | + // Find the object that has the `toString` property or `Symbol.toPrimitive` property | ||
| 2189 | + // as own property in the prototype chain. | ||
| 2186 | 2190 | let pointer = value; | |
| 2187 | 2191 | do { | |
| 2188 | 2192 | pointer = ObjectGetPrototypeOf(pointer); | |
| 2189 | - } while (!ObjectPrototypeHasOwnProperty(pointer, 'toString')); | ||
| 2193 | + } while (!hasOwnToString(pointer, 'toString') && | ||
| 2194 | + !hasOwnToPrimitive(pointer, SymbolToPrimitive)); | ||
| 2190 | 2195 | ||
| 2191 | 2196 | // Check closer if the object is a built-in. | |
| 2192 | 2197 | const descriptor = ObjectGetOwnPropertyDescriptor(pointer, 'constructor'); | |
@@ -2195,6 +2200,10 @@ function hasBuiltInToString(value) { | |||
| 2195 | 2200 | builtInObjects.has(descriptor.value.name); | |
| 2196 | 2201 | } | |
| 2197 | 2202 | ||
| 2203 | + function returnFalse() { | ||
| 2204 | + return false; | ||
| 2205 | + } | ||
| 2206 | + | ||
| 2198 | 2207 | const firstErrorLine = (error) => StringPrototypeSplit(error.message, '\n', 1)[0]; | |
| 2199 | 2208 | let CIRCULAR_ERROR_MESSAGE; | |
| 2200 | 2209 | function tryStringify(arg) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -290,6 +290,68 @@ assert.strictEqual(util.format('%s', -Infinity), '-Infinity'); | |||
| 290 | 290 | assert.strictEqual(util.format('%s', objectWithToPrimitive + ''), 'default context'); | |
| 291 | 291 | } | |
| 292 | 292 | ||
| 293 | + // built-in toPrimitive is the same behavior as inspect | ||
| 294 | + { | ||
| 295 | + const date = new Date('2023-10-01T00:00:00Z'); | ||
| 296 | + assert.strictEqual(util.format('%s', date), util.inspect(date)); | ||
| 297 | + | ||
| 298 | + const symbol = Symbol('foo'); | ||
| 299 | + assert.strictEqual(util.format('%s', symbol), util.inspect(symbol)); | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + // Prototype chain handling for toString | ||
| 303 | + { | ||
| 304 | + function hasToStringButNoToPrimitive() {} | ||
| 305 | + | ||
| 306 | + hasToStringButNoToPrimitive.prototype.toString = function() { | ||
| 307 | + return 'hasToStringButNoToPrimitive'; | ||
| 308 | + }; | ||
| 309 | + | ||
| 310 | + let obj = new hasToStringButNoToPrimitive(); | ||
| 311 | + assert.strictEqual(util.format('%s', obj.toString()), 'hasToStringButNoToPrimitive'); | ||
| 312 | + | ||
| 313 | + function inheritsFromHasToStringButNoToPrimitive() {} | ||
| 314 | + Object.setPrototypeOf(inheritsFromHasToStringButNoToPrimitive.prototype, | ||
| 315 | + hasToStringButNoToPrimitive.prototype); | ||
| 316 | + obj = new inheritsFromHasToStringButNoToPrimitive(); | ||
| 317 | + assert.strictEqual(util.format('%s', obj.toString()), 'hasToStringButNoToPrimitive'); | ||
| 318 | + } | ||
| 319 | + | ||
| 320 | + // Prototype chain handling for Symbol.toPrimitive | ||
| 321 | + { | ||
| 322 | + function hasToPrimitiveButNoToString() {} | ||
| 323 | + | ||
| 324 | + hasToPrimitiveButNoToString.prototype[Symbol.toPrimitive] = function() { | ||
| 325 | + return 'hasToPrimitiveButNoToString'; | ||
| 326 | + }; | ||
| 327 | + | ||
| 328 | + let obj = new hasToPrimitiveButNoToString(); | ||
| 329 | + assert.strictEqual(util.format('%s', obj[Symbol.toPrimitive]()), 'hasToPrimitiveButNoToString'); | ||
| 330 | + function inheritsFromHasToPrimitiveButNoToString() {} | ||
| 331 | + Object.setPrototypeOf(inheritsFromHasToPrimitiveButNoToString.prototype, | ||
| 332 | + hasToPrimitiveButNoToString.prototype); | ||
| 333 | + obj = new inheritsFromHasToPrimitiveButNoToString(); | ||
| 334 | + assert.strictEqual(util.format('%s', obj[Symbol.toPrimitive]()), 'hasToPrimitiveButNoToString'); | ||
| 335 | + } | ||
| 336 | + | ||
| 337 | + // Prototype chain handling for both toString and Symbol.toPrimitive | ||
| 338 | + { | ||
| 339 | + function hasBothToStringAndToPrimitive() {} | ||
| 340 | + hasBothToStringAndToPrimitive.prototype.toString = function() { | ||
| 341 | + return 'toString'; | ||
| 342 | + }; | ||
| 343 | + hasBothToStringAndToPrimitive.prototype[Symbol.toPrimitive] = function() { | ||
| 344 | + return 'toPrimitive'; | ||
| 345 | + }; | ||
| 346 | + let obj = new hasBothToStringAndToPrimitive(); | ||
| 347 | + assert.strictEqual(util.format('%s', obj.toString()), 'toString'); | ||
| 348 | + function inheritsFromHasBothToStringAndToPrimitive() {} | ||
| 349 | + Object.setPrototypeOf(inheritsFromHasBothToStringAndToPrimitive.prototype, | ||
| 350 | + hasBothToStringAndToPrimitive.prototype); | ||
| 351 | + obj = new inheritsFromHasBothToStringAndToPrimitive(); | ||
| 352 | + assert.strictEqual(util.format('%s', obj.toString()), 'toString'); | ||
| 353 | + } | ||
| 354 | + | ||
| 293 | 355 | // JSON format specifier | |
| 294 | 356 | assert.strictEqual(util.format('%j'), '%j'); | |
| 295 | 357 | assert.strictEqual(util.format('%j', 42), '42'); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments