@agoric/assert
Advanced tools
Comparing version 0.0.7 to 0.0.8
@@ -6,2 +6,13 @@ # Change Log | ||
## [0.0.8](https://github.com/Agoric/agoric-sdk/compare/@agoric/assert@0.0.7...@agoric/assert@0.0.8) (2020-06-30) | ||
### Bug Fixes | ||
* replace openDetail with quoting q ([#1134](https://github.com/Agoric/agoric-sdk/issues/1134)) ([67808a4](https://github.com/Agoric/agoric-sdk/commit/67808a4df515630ef7dc77c59054382f626ece96)) | ||
## [0.0.7](https://github.com/Agoric/agoric-sdk/compare/@agoric/assert@0.0.6...@agoric/assert@0.0.7) (2020-05-17) | ||
@@ -8,0 +19,0 @@ |
{ | ||
"name": "@agoric/assert", | ||
"version": "0.0.7", | ||
"version": "0.0.8", | ||
"description": "Assert expression support that protects sensitive data", | ||
@@ -87,3 +87,3 @@ "main": "src/assert.js", | ||
}, | ||
"gitHead": "4cbbf2146ff4b47eaffd1bdf22f3fde8f184cc38" | ||
"gitHead": "d74ea289800c2fc52c005674a55b2412385f57d9" | ||
} |
@@ -28,9 +28,36 @@ // Copyright (C) 2019 Agoric, under Apache License 2.0 | ||
/** | ||
* Like `JSON.stringify` but does not blow up if given a cycle. This is not | ||
* intended to be a serialization to support any useful unserialization, | ||
* or any programmatic use of the resulting string. The string is intended | ||
* only for showing a human, in order to be informative enough for some | ||
* logging purposes. As such, this `cycleTolerantStringify` has an | ||
* imprecise specification and may change over time. | ||
* | ||
* The current `cycleTolerantStringify` possibly emits too many "seen" | ||
* markings: Not only for cycles, but also for repeated subtrees by | ||
* object identity. | ||
*/ | ||
function cycleTolerantStringify(payload) { | ||
const seenSet = new Set(); | ||
const replacer = (_, val) => { | ||
if (typeof val === 'object' && val !== null) { | ||
if (seenSet.has(val)) { | ||
return '<**seen**>'; | ||
} | ||
seenSet.add(val); | ||
} | ||
return val; | ||
}; | ||
return JSON.stringify(payload, replacer); | ||
} | ||
const declassifiers = new WeakSet(); | ||
/** | ||
* To "declassify" a substitution value used in a details`...` template literal, | ||
* enclose that substitution expression in a call to openDetail. This states | ||
* that the argument should appear, stringified, in the error message of the | ||
* thrown error. | ||
* To "declassify" and quote a substitution value used in a | ||
* details`...` template literal, enclose that substitution expression | ||
* in a call to `q`. This states that the argument should appear quoted (with | ||
* `JSON.stringify`), in the error message of the thrown error. The payload | ||
* itself is still passed unquoted to the console as it would be without q. | ||
* | ||
@@ -45,3 +72,3 @@ * Starting from the example in the `details` comment, say instead that the | ||
* color, | ||
* details`${sky.color} should be ${openDetail(color)}`, | ||
* details`${sky.color} should be ${q(color)}`, | ||
* ); | ||
@@ -57,8 +84,7 @@ * ``` | ||
*/ | ||
function openDetail(payload) { | ||
const result = harden({ | ||
function q(payload) { | ||
// Don't harden the payload | ||
const result = Object.freeze({ | ||
payload, | ||
toString() { | ||
return payload.toString(); | ||
}, | ||
toString: Object.freeze(() => cycleTolerantStringify(payload)), | ||
}); | ||
@@ -68,3 +94,3 @@ declassifiers.add(result); | ||
} | ||
harden(openDetail); | ||
harden(q); | ||
@@ -76,3 +102,3 @@ /** | ||
* ```js | ||
* assert(sky.isBlue(), details`${sky.color} should be blue`); | ||
* assert(sky.isBlue(), details`${sky.color} should be "blue"`); | ||
* ``` | ||
@@ -120,4 +146,4 @@ * The details template tag returns an object that can print itself with the | ||
if (declassifiers.has(arg)) { | ||
argStr = `${arg}`; | ||
arg = arg.payload; | ||
argStr = `${arg}`; | ||
} else { | ||
@@ -167,3 +193,5 @@ argStr = `(${an(typeof arg)})`; | ||
if (typeof optDetails === 'string') { | ||
optDetails = details`${openDetail(optDetails)}`; | ||
// If it is a string, use it as the literal part of the template so | ||
// it doesn't get quoted. | ||
optDetails = details([optDetails]); | ||
} | ||
@@ -195,3 +223,3 @@ throw optDetails.complain(); | ||
*/ | ||
function assert(flag, optDetails = details`check failed`) { | ||
function assert(flag, optDetails = details`Check failed`) { | ||
if (!flag) { | ||
@@ -203,3 +231,3 @@ fail(optDetails); | ||
/** | ||
* Assert that two values must be `===`. | ||
* Assert that two values must be `Object.is`. | ||
* @param {*} actual The value we received | ||
@@ -212,5 +240,5 @@ * @param {*} expected What we wanted | ||
expected, | ||
optDetails = details`Expected ${actual} === ${expected}`, | ||
optDetails = details`Expected ${actual} is same as ${expected}`, | ||
) { | ||
assert(actual === expected, optDetails); | ||
assert(Object.is(actual, expected), optDetails); | ||
} | ||
@@ -225,8 +253,16 @@ | ||
*/ | ||
function assertTypeof( | ||
specimen, | ||
typename, | ||
optDetails = details`${specimen} must be ${openDetail(an(typename))}`, | ||
) { | ||
assert(typeof typename === 'string', details`${typename} must be a string`); | ||
function assertTypeof(specimen, typename, optDetails) { | ||
assert( | ||
typeof typename === 'string', | ||
details`${q(typename)} must be a string`, | ||
); | ||
if (optDetails === undefined) { | ||
// Like | ||
// ```js | ||
// optDetails = details`${specimen} must be ${q(an(typename))}`; | ||
// ``` | ||
// except it puts the typename into the literal part of the template | ||
// so it doesn't get quoted. | ||
optDetails = details(['', ` must be ${an(typename)}`], specimen); | ||
} | ||
equal(typeof specimen, typename, optDetails); | ||
@@ -240,2 +276,2 @@ } | ||
export { assert, details, openDetail, an }; | ||
export { assert, details, q, an }; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
14794
248