@agoric/marshal
Advanced tools
Comparing version 0.2.3 to 0.2.4
@@ -12,4 +12,9 @@ /* global module */ | ||
strict: 'off', | ||
'prefer-destructuring': 'off', | ||
'no-else-return': 'off', | ||
'no-console': 'off', | ||
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], | ||
'no-unused-vars': ['error', { | ||
argsIgnorePattern: '^_', | ||
varsIgnorePattern: '^_', | ||
}], | ||
'no-return-assign': 'off', | ||
@@ -20,4 +25,5 @@ 'no-param-reassign': 'off', | ||
'no-loop-func': 'off', | ||
'import/prefer-default-export': 'off', // contrary to Agoric standard | ||
'no-inner-declarations': 'off', | ||
'import/prefer-default-export': 'off', | ||
}, | ||
}; |
@@ -6,2 +6,22 @@ # Change Log | ||
## [0.2.4](https://github.com/Agoric/agoric-sdk/compare/@agoric/marshal@0.2.3...@agoric/marshal@0.2.4) (2020-08-31) | ||
### Bug Fixes | ||
* add "TODO unimplemented"s ([#1580](https://github.com/Agoric/agoric-sdk/issues/1580)) ([7795f93](https://github.com/Agoric/agoric-sdk/commit/7795f9302843a2c94d4a2f42cb22affe1e91d41d)) | ||
* clean up E.when and E.resolve ([#1561](https://github.com/Agoric/agoric-sdk/issues/1561)) ([634046c](https://github.com/Agoric/agoric-sdk/commit/634046c0fc541fc1db258105a75c7313b5668aa0)) | ||
* excise @agoric/harden from the codebase ([eee6fe1](https://github.com/Agoric/agoric-sdk/commit/eee6fe1153730dec52841c9eb4c056a8c5438b0f)) | ||
* minor: rearrange asserts in Remotable ([#1642](https://github.com/Agoric/agoric-sdk/issues/1642)) ([c43a08f](https://github.com/Agoric/agoric-sdk/commit/c43a08fb1733596172a7dc5ca89353d837033e23)) | ||
* reduce inconsistency among our linting rules ([#1492](https://github.com/Agoric/agoric-sdk/issues/1492)) ([b6b675e](https://github.com/Agoric/agoric-sdk/commit/b6b675e2de110e2af19cad784a66220cab21dacf)) | ||
* rename producePromise to makePromiseKit ([#1329](https://github.com/Agoric/agoric-sdk/issues/1329)) ([1d2925a](https://github.com/Agoric/agoric-sdk/commit/1d2925ad640cce7b419751027b44737bd46a6d59)) | ||
* send and receive Remotable tags ([#1628](https://github.com/Agoric/agoric-sdk/issues/1628)) ([1bae122](https://github.com/Agoric/agoric-sdk/commit/1bae1220c2c35f48f279cb3aeab6012bce8ddb5a)) | ||
* stricter marshal requirements ([#1499](https://github.com/Agoric/agoric-sdk/issues/1499)) ([9d8ba97](https://github.com/Agoric/agoric-sdk/commit/9d8ba9763defb290de71668d08faa8619200d117)) | ||
* use REMOTE_STYLE rather than 'presence' to prepare ([#1577](https://github.com/Agoric/agoric-sdk/issues/1577)) ([6b97ae8](https://github.com/Agoric/agoric-sdk/commit/6b97ae8670303631313a65d12393d7ad226b941d)) | ||
* **marshal:** make toString and Symbol.toStringTag non-enumerable ([fc616ef](https://github.com/Agoric/agoric-sdk/commit/fc616eff1c3f61cd96e24644eeb76d8f8469a05c)) | ||
## [0.2.3](https://github.com/Agoric/agoric-sdk/compare/@agoric/marshal@0.2.2...@agoric/marshal@0.2.3) (2020-06-30) | ||
@@ -8,0 +28,0 @@ |
119
marshal.js
@@ -0,8 +1,13 @@ | ||
/* global harden */ | ||
// @ts-check | ||
import harden from '@agoric/harden'; | ||
// eslint-disable-next-line spaced-comment | ||
/// <reference types="ses"/> | ||
import Nat from '@agoric/nat'; | ||
import { isPromise } from '@agoric/produce-promise'; | ||
import { assert, details } from '@agoric/assert'; | ||
import { isPromise } from '@agoric/promise-kit'; | ||
// TODO: Use just 'remote' when we're willing to make a breaking change. | ||
const REMOTE_STYLE = 'presence'; | ||
export const REMOTE_STYLE = 'presence'; | ||
@@ -29,3 +34,4 @@ // TODO, remove the mustPassByPresence alias when we make a breaking change. | ||
* @param {*} maybeRemotable the value to check | ||
* @returns {InterfaceSpec} the interface specification, or undefined if not a Remotable | ||
* @returns {InterfaceSpec|undefined} the interface specification, or undefined | ||
* if not a Remotable | ||
*/ | ||
@@ -99,3 +105,3 @@ export function getInterfaceOf(maybeRemotable) { | ||
throw TypeError( | ||
`Input value ${passStyle} cannot be copied as must be passed by reference`, | ||
`Input value ${passStyle} cannot be copied as it must be passed by reference`, | ||
); | ||
@@ -155,11 +161,10 @@ } | ||
if (!EC || EC.prototype !== proto) { | ||
throw TypeError(`Must inherit from an error class .prototype ${val}`); | ||
throw TypeError( | ||
`Errors must inherit from an error class .prototype ${val}`, | ||
); | ||
} | ||
const { | ||
message: { value: messageStr } = { value: '' }, | ||
message: mDesc, | ||
// Allow but ignore only extraneous own `stack` property. | ||
// TODO: I began the variable below with "_". Why do I still need | ||
// to suppress the lint complaint? | ||
// eslint-disable-next-line no-unused-vars | ||
stack: _optStackDesc, | ||
@@ -172,4 +177,9 @@ ...restDescs | ||
} | ||
if (typeof messageStr !== 'string') { | ||
throw new TypeError(`malformed error object: ${val}`); | ||
if (mDesc) { | ||
if (typeof mDesc.value !== 'string') { | ||
throw new TypeError(`Malformed error object: ${val}`); | ||
} | ||
if (mDesc.enumerable) { | ||
throw new TypeError(`An error's .message must not be enumerable`); | ||
} | ||
} | ||
@@ -184,3 +194,3 @@ return true; | ||
if (Object.getPrototypeOf(val) !== Array.prototype) { | ||
throw new TypeError(`malformed array: ${val}`); | ||
throw new TypeError(`Malformed array: ${val}`); | ||
} | ||
@@ -192,13 +202,16 @@ const len = val.length; | ||
if (!desc) { | ||
throw new TypeError(`arrays must not contain holes`); | ||
throw new TypeError(`Arrays must not contain holes: ${i}`); | ||
} | ||
if (!('value' in desc)) { | ||
throw new TypeError(`arrays must not contain accessors`); | ||
throw new TypeError(`Arrays must not contain accessors: ${i}`); | ||
} | ||
if (typeof desc.value === 'function') { | ||
throw new TypeError(`arrays must not contain methods`); | ||
throw new TypeError(`Arrays must not contain methods: ${i}`); | ||
} | ||
if (!desc.enumerable) { | ||
throw new TypeError(`Array elements must be enumerable: ${i}`); | ||
} | ||
} | ||
if (Object.keys(descs).length !== len + 1) { | ||
throw new TypeError(`array must not have non-indexes ${val}`); | ||
throw new TypeError(`Arrays must not have non-indexes: ${val}`); | ||
} | ||
@@ -212,12 +225,8 @@ return true; | ||
} | ||
const descList = Object.values(Object.getOwnPropertyDescriptors(val)); | ||
if (descList.length === 0) { | ||
const descEntries = Object.entries(Object.getOwnPropertyDescriptors(val)); | ||
if (descEntries.length === 0) { | ||
// empty non-array objects are pass-by-remote, not pass-by-copy | ||
return false; | ||
} | ||
for (const desc of descList) { | ||
if (!('value' in desc)) { | ||
// Should we error if we see an accessor here? | ||
return false; | ||
} | ||
for (const [_key, desc] of descEntries) { | ||
if (typeof desc.value === 'function') { | ||
@@ -227,2 +236,15 @@ return false; | ||
} | ||
for (const [key, desc] of descEntries) { | ||
if (typeof key === 'symbol') { | ||
throw new TypeError( | ||
`Records must not have symbol-named properties: ${String(key)}`, | ||
); | ||
} | ||
if (!('value' in desc)) { | ||
throw new TypeError(`Records must not contain accessors: ${key}`); | ||
} | ||
if (!desc.enumerable) { | ||
throw new TypeError(`Record fields must be enumerable: ${key}`); | ||
} | ||
} | ||
return true; | ||
@@ -232,4 +254,5 @@ } | ||
/** | ||
* Ensure that val could become a legitimate remotable. This is used internally both | ||
* in the construction of a new remotable and mustPassByRemote. | ||
* Ensure that val could become a legitimate remotable. This is used | ||
* internally both in the construction of a new remotable and | ||
* mustPassByRemote. | ||
* | ||
@@ -432,8 +455,9 @@ * @param {*} val The remotable candidate to check | ||
const identityFn = x => x; | ||
const defaultSlotToValFn = (x, _) => x; | ||
export function makeMarshal( | ||
convertValToSlot = identityFn, | ||
convertSlotToVal = identityFn, | ||
convertSlotToVal = defaultSlotToValFn, | ||
) { | ||
function serializeSlot(val, slots, slotMap) { | ||
function serializeSlot(val, slots, slotMap, iface = undefined) { | ||
let slotIndex; | ||
@@ -450,2 +474,9 @@ if (slotMap.has(val)) { | ||
if (iface !== undefined) { | ||
return harden({ | ||
[QCLASS]: 'slot', | ||
iface, | ||
index: slotIndex, | ||
}); | ||
} | ||
return harden({ | ||
@@ -529,3 +560,7 @@ [QCLASS]: 'slot', | ||
} | ||
case REMOTE_STYLE: | ||
case REMOTE_STYLE: { | ||
const iface = getInterfaceOf(val); | ||
// console.log(`serializeSlot: ${val}`); | ||
return serializeSlot(val, slots, slotMap, iface); | ||
} | ||
case 'promise': { | ||
@@ -561,3 +596,3 @@ // console.log(`serializeSlot: ${val}`); | ||
// We stay close to the algorith at | ||
// We stay close to the algorithm at | ||
// https://tc39.github.io/ecma262/#sec-json.parse , where | ||
@@ -650,3 +685,3 @@ // fullRevive(JSON.parse(str)) is like JSON.parse(str, revive)) | ||
const slot = slots[Nat(rawTree.index)]; | ||
return ibidTable.register(convertSlotToVal(slot)); | ||
return ibidTable.register(convertSlotToVal(slot, rawTree.iface)); | ||
} | ||
@@ -703,3 +738,6 @@ | ||
* | ||
* @param {InterfaceSpec} [iface='Remotable'] The interface specification for the remotable | ||
* @param {InterfaceSpec} [iface='Remotable'] The interface specification for | ||
* the remotable. For now, a string iface must be "Remotable" or begin with | ||
* "Alleged: ", to serve as the alleged name. More general ifaces are not yet | ||
* implemented. This is temporary. | ||
* @param {object} [props={}] Own-properties are copied to the remotable | ||
@@ -710,10 +748,15 @@ * @param {object} [remotable={}] The object used as the remotable | ||
function Remotable(iface = 'Remotable', props = {}, remotable = {}) { | ||
// TODO unimplemented | ||
assert.typeof( | ||
iface, | ||
'string', | ||
details`Interface ${iface} must be a string; unimplemented`, | ||
); | ||
// TODO unimplemented | ||
assert( | ||
iface === 'Remotable' || iface.startsWith('Alleged: '), | ||
details`For now, iface ${iface} must be "Remotable" or begin with "Alleged: "; unimplemented`, | ||
); | ||
iface = pureCopy(harden(iface)); | ||
const ifaceType = typeof iface; | ||
// Find the alleged name. | ||
if (ifaceType !== 'string') { | ||
throw Error(`Interface must be a string, not ${ifaceType}; unimplemented`); | ||
} | ||
// TODO: When iface is richer than just string, we need to get the allegedName | ||
@@ -720,0 +763,0 @@ // in a different way. |
{ | ||
"name": "@agoric/marshal", | ||
"version": "0.2.3", | ||
"version": "0.2.4", | ||
"description": "marshal", | ||
@@ -11,7 +11,9 @@ "main": "marshal.js", | ||
"build": "exit 0", | ||
"test": "tape -r esm 'test/**/test*.js' | tap-spec", | ||
"test": "ava", | ||
"pretty-fix": "prettier --write '**/*.js'", | ||
"pretty-check": "prettier --check '**/*.js'", | ||
"lint-fix": "eslint --fix '**/*.js'", | ||
"lint-check": "eslint '**/*.js'" | ||
"lint-fix": "yarn lint --fix", | ||
"lint-check": "yarn lint", | ||
"lint": "yarn lint:types && eslint '**/*.js'", | ||
"lint:types": "tsc -p jsconfig.json" | ||
}, | ||
@@ -32,12 +34,11 @@ "repository": { | ||
"dependencies": { | ||
"@agoric/eventual-send": "^0.9.3", | ||
"@agoric/harden": "^0.0.8", | ||
"@agoric/assert": "^0.0.9", | ||
"@agoric/eventual-send": "^0.10.0", | ||
"@agoric/nat": "^2.0.1", | ||
"@agoric/produce-promise": "^0.1.3" | ||
"@agoric/promise-kit": "^0.1.4" | ||
}, | ||
"devDependencies": { | ||
"esm": "^3.2.25", | ||
"tap-spec": "^5.0.0", | ||
"tape": "^4.10.2", | ||
"tape-promise": "^4.0.0" | ||
"@agoric/install-ses": "^0.3.0", | ||
"ava": "^3.11.1", | ||
"esm": "^3.2.25" | ||
}, | ||
@@ -47,3 +48,11 @@ "publishConfig": { | ||
}, | ||
"gitHead": "d74ea289800c2fc52c005674a55b2412385f57d9" | ||
"ava": { | ||
"files": [ | ||
"test/**/test-*.js" | ||
], | ||
"require": [ | ||
"esm" | ||
], | ||
"timeout": "2m" | ||
} | ||
} |
@@ -29,3 +29,3 @@ # @agoric/marshal | ||
```js | ||
import harden from '@agoric/harden'; | ||
import '@agoric/install-ses'; | ||
import { makeMarshal } from '@agoric/marshal'; | ||
@@ -44,4 +44,4 @@ | ||
The entire object graph must be "hardened" (recursively frozen), such as done | ||
by the `@agoric/harden` module. The serialization function will refuse to | ||
marshal any graph that contains a non-frozen object. | ||
by the `ses` module (installed with `@agoric/install-ses`). The serialization | ||
function will refuse to marshal any graph that contains a non-frozen object. | ||
@@ -48,0 +48,0 @@ ## Beyond JSON |
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
50498
3
12
786
+ Added@agoric/assert@^0.0.9
+ Added@agoric/promise-kit@^0.1.4
+ Added@agoric/assert@0.0.9(transitive)
+ Added@agoric/eventual-send@0.10.00.12.0(transitive)
+ Added@agoric/promise-kit@0.1.7(transitive)
- Removed@agoric/harden@^0.0.8
- Removed@agoric/produce-promise@^0.1.3
- Removed@agoric/eventual-send@0.9.3(transitive)
- Removed@agoric/harden@0.0.8(transitive)
- Removed@agoric/make-hardener@0.0.8(transitive)
- Removed@agoric/produce-promise@0.1.3(transitive)