@stellar/js-xdr
Advanced tools
Comparing version 3.1.1 to 3.1.2
@@ -6,6 +6,11 @@ # Changelog | ||
## Unreleased | ||
## [v3.1.2](https://github.com/stellar/js-xdr/compare/v3.1.1...v3.1.2) | ||
### Fixed | ||
* Increase robustness of compatibility across multiple `js-xdr` instances in an environment ([#122](https://github.com/stellar/js-xdr/pull/122)). | ||
## [v3.1.1](https://github.com/stellar/js-xdr/compare/v3.1.0...v3.1.1) | ||
@@ -12,0 +17,0 @@ |
{ | ||
"name": "@stellar/js-xdr", | ||
"version": "3.1.1", | ||
"version": "3.1.2", | ||
"description": "Read/write XDR encoded data structures (RFC 4506)", | ||
@@ -51,6 +51,6 @@ "main": "lib/xdr.js", | ||
"devDependencies": { | ||
"@babel/core": "^7.24.1", | ||
"@babel/eslint-parser": "^7.24.1", | ||
"@babel/preset-env": "^7.24.1", | ||
"@babel/register": "^7.23.7", | ||
"@babel/core": "^7.24.9", | ||
"@babel/eslint-parser": "^7.24.8", | ||
"@babel/preset-env": "^7.24.8", | ||
"@babel/register": "^7.24.6", | ||
"babel-loader": "^9.1.3", | ||
@@ -74,3 +74,3 @@ "buffer": "^6.0.3", | ||
"lint-staged": "13.2.2", | ||
"mocha": "^10.3.0", | ||
"mocha": "^10.6.0", | ||
"prettier": "^2.8.7", | ||
@@ -80,5 +80,5 @@ "sinon": "^15.2.0", | ||
"terser-webpack-plugin": "^5.3.10", | ||
"webpack": "^5.90.3", | ||
"webpack": "^5.93.0", | ||
"webpack-cli": "^5.0.2" | ||
} | ||
} |
@@ -28,3 +28,3 @@ import { XdrCompositeType } from './xdr-type'; | ||
write(value, writer) { | ||
if (!(value instanceof global.Array)) | ||
if (!global.Array.isArray(value)) | ||
throw new XdrWriterError(`value is not array`); | ||
@@ -31,0 +31,0 @@ |
import { Int } from './int'; | ||
import { XdrPrimitiveType } from './xdr-type'; | ||
import { XdrPrimitiveType, isSerializableIsh } from './xdr-type'; | ||
import { XdrReaderError, XdrWriterError } from './errors'; | ||
@@ -29,4 +29,9 @@ | ||
static write(value, writer) { | ||
if (!(value instanceof this)) | ||
throw new XdrWriterError(`unknown ${value} is not a ${this.enumName}`); | ||
if (!this.isValid(value)) { | ||
throw new XdrWriterError( | ||
`${value} has enum name ${value?.enumName}, not ${ | ||
this.enumName | ||
}: ${JSON.stringify(value)}` | ||
); | ||
} | ||
@@ -40,3 +45,6 @@ Int.write(value.value, writer); | ||
static isValid(value) { | ||
return value instanceof this; | ||
return ( | ||
value?.constructor?.enumName === this.enumName || | ||
isSerializableIsh(value, this) | ||
); | ||
} | ||
@@ -43,0 +51,0 @@ |
import { Reference } from './reference'; | ||
import { XdrPrimitiveType } from './xdr-type'; | ||
import { XdrCompositeType, isSerializableIsh } from './xdr-type'; | ||
import { XdrWriterError } from './errors'; | ||
export class Struct extends XdrPrimitiveType { | ||
export class Struct extends XdrCompositeType { | ||
constructor(attributes) { | ||
@@ -26,4 +26,9 @@ super(); | ||
static write(value, writer) { | ||
if (!(value instanceof this)) | ||
throw new XdrWriterError(`${value} is not a ${this.structName}`); | ||
if (!this.isValid(value)) { | ||
throw new XdrWriterError( | ||
`${value} has struct name ${value?.constructor?.structName}, not ${ | ||
this.structName | ||
}: ${JSON.stringify(value)}` | ||
); | ||
} | ||
@@ -40,3 +45,6 @@ for (const [fieldName, type] of this._fields) { | ||
static isValid(value) { | ||
return value instanceof this; | ||
return ( | ||
value?.constructor?.structName === this.structName || | ||
isSerializableIsh(value, this) | ||
); | ||
} | ||
@@ -43,0 +51,0 @@ |
import { Void } from './void'; | ||
import { Reference } from './reference'; | ||
import { XdrCompositeType } from './xdr-type'; | ||
import { XdrCompositeType, isSerializableIsh } from './xdr-type'; | ||
import { XdrWriterError } from './errors'; | ||
@@ -84,4 +84,9 @@ | ||
static write(value, writer) { | ||
if (!(value instanceof this)) | ||
throw new XdrWriterError(`${value} is not a ${this.unionName}`); | ||
if (!this.isValid(value)) { | ||
throw new XdrWriterError( | ||
`${value} has union name ${value?.unionName}, not ${ | ||
this.unionName | ||
}: ${JSON.stringify(value)}` | ||
); | ||
} | ||
@@ -96,3 +101,6 @@ this._switchOn.write(value.switch(), writer); | ||
static isValid(value) { | ||
return value instanceof this; | ||
return ( | ||
value?.constructor?.unionName === this.unionName || | ||
isSerializableIsh(value, this) | ||
); | ||
} | ||
@@ -99,0 +107,0 @@ |
@@ -174,3 +174,45 @@ import { XdrReader } from './serialization/xdr-reader'; | ||
/** | ||
* Provides a "duck typed" version of the native `instanceof` for read/write. | ||
* | ||
* "Duck typing" means if the parameter _looks like_ and _acts like_ a duck | ||
* (i.e. the type we're checking), it will be treated as that type. | ||
* | ||
* In this case, the "type" we're looking for is "like XdrType" but also "like | ||
* XdrCompositeType|XdrPrimitiveType" (i.e. serializable), but also conditioned | ||
* on a particular subclass of "XdrType" (e.g. {@link Union} which extends | ||
* XdrType). | ||
* | ||
* This makes the package resilient to downstream systems that may be combining | ||
* many versions of a package across its stack that are technically compatible | ||
* but fail `instanceof` checks due to cross-pollination. | ||
*/ | ||
export function isSerializableIsh(value, subtype) { | ||
return ( | ||
value !== undefined && | ||
value !== null && // prereqs, otherwise `getPrototypeOf` pops | ||
(value instanceof subtype || // quickest check | ||
// Do an initial constructor check (anywhere is fine so that children of | ||
// `subtype` still work), then | ||
(hasConstructor(value, subtype) && | ||
// ensure it has read/write methods, then | ||
typeof value.constructor.read === 'function' && | ||
typeof value.constructor.write === 'function' && | ||
// ensure XdrType is in the prototype chain | ||
hasConstructor(value, 'XdrType'))) | ||
); | ||
} | ||
/** Tries to find `subtype` in any of the constructors or meta of `instance`. */ | ||
export function hasConstructor(instance, subtype) { | ||
do { | ||
const ctor = instance.constructor; | ||
if (ctor.name === subtype) { | ||
return true; | ||
} | ||
} while ((instance = Object.getPrototypeOf(instance))); | ||
return false; | ||
} | ||
/** | ||
* @typedef {'raw'|'hex'|'base64'} XdrEncodingFormat | ||
*/ |
import { XdrReader } from '../../src/serialization/xdr-reader'; | ||
import { XdrWriter } from '../../src/serialization/xdr-writer'; | ||
import { Enum } from '../../src/enum'; | ||
@@ -90,2 +91,20 @@ /* jshint -W030 */ | ||
it('works for "enum-like" objects', function () { | ||
class FakeEnum extends Enum {} | ||
FakeEnum.enumName = 'Color'; | ||
let r = new FakeEnum(); | ||
expect(Color.isValid(r)).to.be.true; | ||
FakeEnum.enumName = 'NotColor'; | ||
r = new FakeEnum(); | ||
expect(Color.isValid(r)).to.be.false; | ||
// make sure you can't fool it | ||
FakeEnum.enumName = undefined; | ||
FakeEnum.unionName = 'Color'; | ||
r = new FakeEnum(); | ||
expect(Color.isValid(r)).to.be.false; | ||
}); | ||
it('returns false for arrays of the wrong size', function () { | ||
@@ -92,0 +111,0 @@ expect(Color.isValid(null)).to.be.false; |
import { XdrReader } from '../../src/serialization/xdr-reader'; | ||
import { XdrWriter } from '../../src/serialization/xdr-writer'; | ||
import { XdrPrimitiveType } from '../../src/xdr-type'; | ||
@@ -133,2 +134,20 @@ /* jshint -W030 */ | ||
it('works for "union-like" objects', function () { | ||
class FakeUnion extends XdrPrimitiveType {} | ||
FakeUnion.unionName = 'Result'; | ||
let r = new FakeUnion(); | ||
expect(Result.isValid(r)).to.be.true; | ||
FakeUnion.unionName = 'NotResult'; | ||
r = new FakeUnion(); | ||
expect(Result.isValid(r)).to.be.false; | ||
// make sure you can't fool it | ||
FakeUnion.unionName = undefined; | ||
FakeUnion.structName = 'Result'; | ||
r = new FakeUnion(); | ||
expect(Result.isValid(r)).to.be.false; | ||
}); | ||
it('returns false for anything else', function () { | ||
@@ -141,3 +160,4 @@ expect(Result.isValid(null)).to.be.false; | ||
expect(Result.isValid(true)).to.be.false; | ||
expect(Result.isValid('ok')).to.be.false; | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
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
562292
86
6241