@bufbuild/protobuf
Advanced tools
Comparing version 2.2.2 to 2.2.3
import type { MessageShape } from "./types.js"; | ||
import type { DescMessage } from "./descriptors.js"; | ||
import { type DescMessage } from "./descriptors.js"; | ||
import type { Registry } from "./registry.js"; | ||
interface EqualsOptions { | ||
/** | ||
* A registry to look up extensions, and messages packed in Any. | ||
* | ||
* @private Experimental API, does not follow semantic versioning. | ||
*/ | ||
registry: Registry; | ||
/** | ||
* Unpack google.protobuf.Any before comparing. | ||
* If a type is not in the registry, comparison falls back to comparing the | ||
* fields of Any. | ||
* | ||
* @private Experimental API, does not follow semantic versioning. | ||
*/ | ||
unpackAny?: boolean; | ||
/** | ||
* Consider extensions when comparing. | ||
* | ||
* @private Experimental API, does not follow semantic versioning. | ||
*/ | ||
extensions?: boolean; | ||
/** | ||
* Consider unknown fields when comparing. | ||
* The registry is used to distinguish between extensions, and unknown fields | ||
* caused by schema changes. | ||
* | ||
* @private Experimental API, does not follow semantic versioning. | ||
*/ | ||
unknown?: boolean; | ||
} | ||
/** | ||
@@ -9,2 +40,3 @@ * Compare two messages of the same type. | ||
*/ | ||
export declare function equals<Desc extends DescMessage>(schema: Desc, a: MessageShape<Desc>, b: MessageShape<Desc>): boolean; | ||
export declare function equals<Desc extends DescMessage>(schema: Desc, a: MessageShape<Desc>, b: MessageShape<Desc>, options?: EqualsOptions): boolean; | ||
export {}; |
@@ -19,2 +19,5 @@ "use strict"; | ||
const reflect_js_1 = require("./reflect/reflect.js"); | ||
const descriptors_js_1 = require("./descriptors.js"); | ||
const index_js_1 = require("./wkt/index.js"); | ||
const extensions_js_1 = require("./extensions.js"); | ||
/** | ||
@@ -26,3 +29,3 @@ * Compare two messages of the same type. | ||
*/ | ||
function equals(schema, a, b) { | ||
function equals(schema, a, b, options) { | ||
if (a.$typeName != schema.typeName || b.$typeName != schema.typeName) { | ||
@@ -34,13 +37,23 @@ return false; | ||
} | ||
return reflectEquals((0, reflect_js_1.reflect)(schema, a), (0, reflect_js_1.reflect)(schema, b)); | ||
return reflectEquals((0, reflect_js_1.reflect)(schema, a), (0, reflect_js_1.reflect)(schema, b), options); | ||
} | ||
function reflectEquals(a, b) { | ||
function reflectEquals(a, b, opts) { | ||
if (a.desc.typeName === "google.protobuf.Any" && (opts === null || opts === void 0 ? void 0 : opts.unpackAny) == true) { | ||
return anyUnpackedEquals(a.message, b.message, opts); | ||
} | ||
for (const f of a.fields) { | ||
if (!fieldEquals(f, a, b)) { | ||
if (!fieldEquals(f, a, b, opts)) { | ||
return false; | ||
} | ||
} | ||
if ((opts === null || opts === void 0 ? void 0 : opts.unknown) == true && !unknownEquals(a, b, opts.registry)) { | ||
return false; | ||
} | ||
if ((opts === null || opts === void 0 ? void 0 : opts.extensions) == true && !extensionsEquals(a, b, opts)) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
function fieldEquals(f, a, b) { | ||
// TODO(tstamm) add an option to consider NaN equal to NaN? | ||
function fieldEquals(f, a, b, opts) { | ||
if (!a.isSet(f) && !b.isSet(f)) { | ||
@@ -58,21 +71,22 @@ return true; | ||
case "message": | ||
return reflectEquals(a.get(f), b.get(f)); | ||
return reflectEquals(a.get(f), b.get(f), opts); | ||
case "map": { | ||
const ma = a.get(f); | ||
const mb = b.get(f); | ||
const keysA = []; | ||
for (const k of ma.keys()) { | ||
if (!mb.has(k)) { | ||
// TODO(tstamm) can't we compare sizes first? | ||
const mapA = a.get(f); | ||
const mapB = b.get(f); | ||
const keys = []; | ||
for (const k of mapA.keys()) { | ||
if (!mapB.has(k)) { | ||
return false; | ||
} | ||
keysA.push(k); | ||
keys.push(k); | ||
} | ||
for (const k of mb.keys()) { | ||
if (!ma.has(k)) { | ||
for (const k of mapB.keys()) { | ||
if (!mapA.has(k)) { | ||
return false; | ||
} | ||
} | ||
for (const key of keysA) { | ||
const va = ma.get(key); | ||
const vb = mb.get(key); | ||
for (const key of keys) { | ||
const va = mapA.get(key); | ||
const vb = mapB.get(key); | ||
if (va === vb) { | ||
@@ -85,3 +99,3 @@ continue; | ||
case "message": | ||
if (!reflectEquals(va, vb)) { | ||
if (!reflectEquals(va, vb, opts)) { | ||
return false; | ||
@@ -100,10 +114,10 @@ } | ||
case "list": { | ||
const la = a.get(f); | ||
const lb = b.get(f); | ||
if (la.size != lb.size) { | ||
const listA = a.get(f); | ||
const listB = b.get(f); | ||
if (listA.size != listB.size) { | ||
return false; | ||
} | ||
for (let i = 0; i < la.size; i++) { | ||
const va = la.get(i); | ||
const vb = lb.get(i); | ||
for (let i = 0; i < listA.size; i++) { | ||
const va = listA.get(i); | ||
const vb = listB.get(i); | ||
if (va === vb) { | ||
@@ -116,3 +130,3 @@ continue; | ||
case "message": | ||
if (!reflectEquals(va, vb)) { | ||
if (!reflectEquals(va, vb, opts)) { | ||
return false; | ||
@@ -133,1 +147,65 @@ } | ||
} | ||
function anyUnpackedEquals(a, b, opts) { | ||
if (a.typeUrl !== b.typeUrl) { | ||
return false; | ||
} | ||
const unpackedA = (0, index_js_1.anyUnpack)(a, opts.registry); | ||
const unpackedB = (0, index_js_1.anyUnpack)(b, opts.registry); | ||
if (unpackedA && unpackedB) { | ||
const schema = opts.registry.getMessage(unpackedA.$typeName); | ||
if (schema) { | ||
return equals(schema, unpackedA, unpackedB, opts); | ||
} | ||
} | ||
return (0, scalar_js_1.scalarEquals)(descriptors_js_1.ScalarType.BYTES, a.value, b.value); | ||
} | ||
function unknownEquals(a, b, registry) { | ||
function getTrulyUnknown(msg, registry) { | ||
var _a; | ||
const u = (_a = msg.getUnknown()) !== null && _a !== void 0 ? _a : []; | ||
return registry | ||
? u.filter((uf) => !registry.getExtensionFor(msg.desc, uf.no)) | ||
: u; | ||
} | ||
const unknownA = getTrulyUnknown(a, registry); | ||
const unknownB = getTrulyUnknown(b, registry); | ||
if (unknownA.length != unknownB.length) { | ||
return false; | ||
} | ||
for (let i = 0; i < unknownA.length; i++) { | ||
const a = unknownA[i], b = unknownB[i]; | ||
if (a.no != b.no) { | ||
return false; | ||
} | ||
if (a.wireType != b.wireType) { | ||
return false; | ||
} | ||
if (!(0, scalar_js_1.scalarEquals)(descriptors_js_1.ScalarType.BYTES, a.data, b.data)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
function extensionsEquals(a, b, opts) { | ||
function getSetExtensions(msg, registry) { | ||
var _a; | ||
return ((_a = msg.getUnknown()) !== null && _a !== void 0 ? _a : []) | ||
.map((uf) => registry.getExtensionFor(msg.desc, uf.no)) | ||
.filter((e) => e != undefined) | ||
.filter((e, index, arr) => arr.indexOf(e) === index); | ||
} | ||
const extensionsA = getSetExtensions(a, opts.registry); | ||
const extensionsB = getSetExtensions(b, opts.registry); | ||
if (extensionsA.length != extensionsB.length || | ||
extensionsA.some((e) => !extensionsB.includes(e))) { | ||
return false; | ||
} | ||
for (const extension of extensionsA) { | ||
const [containerA, field] = (0, extensions_js_1.createExtensionContainer)(extension, (0, extensions_js_1.getExtension)(a.message, extension)); | ||
const [containerB] = (0, extensions_js_1.createExtensionContainer)(extension, (0, extensions_js_1.getExtension)(b.message, extension)); | ||
if (!fieldEquals(field, containerA, containerB, opts)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} |
@@ -26,3 +26,3 @@ "use strict"; | ||
var g = generator.apply(thisArg, _arguments || []), i, q = []; | ||
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; | ||
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; | ||
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; } | ||
@@ -29,0 +29,0 @@ function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } } |
@@ -51,3 +51,3 @@ "use strict"; | ||
: registryOrMessageDesc.getMessage(typeUrlToName(any.typeUrl)); | ||
if (!desc) { | ||
if (!desc || !anyIs(any, desc)) { | ||
return undefined; | ||
@@ -61,3 +61,3 @@ } | ||
function anyUnpackTo(any, schema, message) { | ||
if (any.typeUrl === "") { | ||
if (!anyIs(any, schema)) { | ||
return undefined; | ||
@@ -64,0 +64,0 @@ } |
import type { MessageShape } from "./types.js"; | ||
import type { DescMessage } from "./descriptors.js"; | ||
import { type DescMessage } from "./descriptors.js"; | ||
import type { Registry } from "./registry.js"; | ||
interface EqualsOptions { | ||
/** | ||
* A registry to look up extensions, and messages packed in Any. | ||
* | ||
* @private Experimental API, does not follow semantic versioning. | ||
*/ | ||
registry: Registry; | ||
/** | ||
* Unpack google.protobuf.Any before comparing. | ||
* If a type is not in the registry, comparison falls back to comparing the | ||
* fields of Any. | ||
* | ||
* @private Experimental API, does not follow semantic versioning. | ||
*/ | ||
unpackAny?: boolean; | ||
/** | ||
* Consider extensions when comparing. | ||
* | ||
* @private Experimental API, does not follow semantic versioning. | ||
*/ | ||
extensions?: boolean; | ||
/** | ||
* Consider unknown fields when comparing. | ||
* The registry is used to distinguish between extensions, and unknown fields | ||
* caused by schema changes. | ||
* | ||
* @private Experimental API, does not follow semantic versioning. | ||
*/ | ||
unknown?: boolean; | ||
} | ||
/** | ||
@@ -9,2 +40,3 @@ * Compare two messages of the same type. | ||
*/ | ||
export declare function equals<Desc extends DescMessage>(schema: Desc, a: MessageShape<Desc>, b: MessageShape<Desc>): boolean; | ||
export declare function equals<Desc extends DescMessage>(schema: Desc, a: MessageShape<Desc>, b: MessageShape<Desc>, options?: EqualsOptions): boolean; | ||
export {}; |
@@ -16,2 +16,5 @@ // Copyright 2021-2024 Buf Technologies, Inc. | ||
import { reflect } from "./reflect/reflect.js"; | ||
import { ScalarType, } from "./descriptors.js"; | ||
import { anyUnpack } from "./wkt/index.js"; | ||
import { createExtensionContainer, getExtension } from "./extensions.js"; | ||
/** | ||
@@ -23,3 +26,3 @@ * Compare two messages of the same type. | ||
*/ | ||
export function equals(schema, a, b) { | ||
export function equals(schema, a, b, options) { | ||
if (a.$typeName != schema.typeName || b.$typeName != schema.typeName) { | ||
@@ -31,13 +34,23 @@ return false; | ||
} | ||
return reflectEquals(reflect(schema, a), reflect(schema, b)); | ||
return reflectEquals(reflect(schema, a), reflect(schema, b), options); | ||
} | ||
function reflectEquals(a, b) { | ||
function reflectEquals(a, b, opts) { | ||
if (a.desc.typeName === "google.protobuf.Any" && (opts === null || opts === void 0 ? void 0 : opts.unpackAny) == true) { | ||
return anyUnpackedEquals(a.message, b.message, opts); | ||
} | ||
for (const f of a.fields) { | ||
if (!fieldEquals(f, a, b)) { | ||
if (!fieldEquals(f, a, b, opts)) { | ||
return false; | ||
} | ||
} | ||
if ((opts === null || opts === void 0 ? void 0 : opts.unknown) == true && !unknownEquals(a, b, opts.registry)) { | ||
return false; | ||
} | ||
if ((opts === null || opts === void 0 ? void 0 : opts.extensions) == true && !extensionsEquals(a, b, opts)) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
function fieldEquals(f, a, b) { | ||
// TODO(tstamm) add an option to consider NaN equal to NaN? | ||
function fieldEquals(f, a, b, opts) { | ||
if (!a.isSet(f) && !b.isSet(f)) { | ||
@@ -55,21 +68,22 @@ return true; | ||
case "message": | ||
return reflectEquals(a.get(f), b.get(f)); | ||
return reflectEquals(a.get(f), b.get(f), opts); | ||
case "map": { | ||
const ma = a.get(f); | ||
const mb = b.get(f); | ||
const keysA = []; | ||
for (const k of ma.keys()) { | ||
if (!mb.has(k)) { | ||
// TODO(tstamm) can't we compare sizes first? | ||
const mapA = a.get(f); | ||
const mapB = b.get(f); | ||
const keys = []; | ||
for (const k of mapA.keys()) { | ||
if (!mapB.has(k)) { | ||
return false; | ||
} | ||
keysA.push(k); | ||
keys.push(k); | ||
} | ||
for (const k of mb.keys()) { | ||
if (!ma.has(k)) { | ||
for (const k of mapB.keys()) { | ||
if (!mapA.has(k)) { | ||
return false; | ||
} | ||
} | ||
for (const key of keysA) { | ||
const va = ma.get(key); | ||
const vb = mb.get(key); | ||
for (const key of keys) { | ||
const va = mapA.get(key); | ||
const vb = mapB.get(key); | ||
if (va === vb) { | ||
@@ -82,3 +96,3 @@ continue; | ||
case "message": | ||
if (!reflectEquals(va, vb)) { | ||
if (!reflectEquals(va, vb, opts)) { | ||
return false; | ||
@@ -97,10 +111,10 @@ } | ||
case "list": { | ||
const la = a.get(f); | ||
const lb = b.get(f); | ||
if (la.size != lb.size) { | ||
const listA = a.get(f); | ||
const listB = b.get(f); | ||
if (listA.size != listB.size) { | ||
return false; | ||
} | ||
for (let i = 0; i < la.size; i++) { | ||
const va = la.get(i); | ||
const vb = lb.get(i); | ||
for (let i = 0; i < listA.size; i++) { | ||
const va = listA.get(i); | ||
const vb = listB.get(i); | ||
if (va === vb) { | ||
@@ -113,3 +127,3 @@ continue; | ||
case "message": | ||
if (!reflectEquals(va, vb)) { | ||
if (!reflectEquals(va, vb, opts)) { | ||
return false; | ||
@@ -130,1 +144,65 @@ } | ||
} | ||
function anyUnpackedEquals(a, b, opts) { | ||
if (a.typeUrl !== b.typeUrl) { | ||
return false; | ||
} | ||
const unpackedA = anyUnpack(a, opts.registry); | ||
const unpackedB = anyUnpack(b, opts.registry); | ||
if (unpackedA && unpackedB) { | ||
const schema = opts.registry.getMessage(unpackedA.$typeName); | ||
if (schema) { | ||
return equals(schema, unpackedA, unpackedB, opts); | ||
} | ||
} | ||
return scalarEquals(ScalarType.BYTES, a.value, b.value); | ||
} | ||
function unknownEquals(a, b, registry) { | ||
function getTrulyUnknown(msg, registry) { | ||
var _a; | ||
const u = (_a = msg.getUnknown()) !== null && _a !== void 0 ? _a : []; | ||
return registry | ||
? u.filter((uf) => !registry.getExtensionFor(msg.desc, uf.no)) | ||
: u; | ||
} | ||
const unknownA = getTrulyUnknown(a, registry); | ||
const unknownB = getTrulyUnknown(b, registry); | ||
if (unknownA.length != unknownB.length) { | ||
return false; | ||
} | ||
for (let i = 0; i < unknownA.length; i++) { | ||
const a = unknownA[i], b = unknownB[i]; | ||
if (a.no != b.no) { | ||
return false; | ||
} | ||
if (a.wireType != b.wireType) { | ||
return false; | ||
} | ||
if (!scalarEquals(ScalarType.BYTES, a.data, b.data)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
function extensionsEquals(a, b, opts) { | ||
function getSetExtensions(msg, registry) { | ||
var _a; | ||
return ((_a = msg.getUnknown()) !== null && _a !== void 0 ? _a : []) | ||
.map((uf) => registry.getExtensionFor(msg.desc, uf.no)) | ||
.filter((e) => e != undefined) | ||
.filter((e, index, arr) => arr.indexOf(e) === index); | ||
} | ||
const extensionsA = getSetExtensions(a, opts.registry); | ||
const extensionsB = getSetExtensions(b, opts.registry); | ||
if (extensionsA.length != extensionsB.length || | ||
extensionsA.some((e) => !extensionsB.includes(e))) { | ||
return false; | ||
} | ||
for (const extension of extensionsA) { | ||
const [containerA, field] = createExtensionContainer(extension, getExtension(a.message, extension)); | ||
const [containerB] = createExtensionContainer(extension, getExtension(b.message, extension)); | ||
if (!fieldEquals(field, containerA, containerB, opts)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} |
@@ -25,3 +25,3 @@ // Copyright 2021-2024 Buf Technologies, Inc. | ||
var g = generator.apply(thisArg, _arguments || []), i, q = []; | ||
return i = {}, verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; | ||
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; | ||
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; } | ||
@@ -28,0 +28,0 @@ function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } } |
@@ -45,3 +45,3 @@ // Copyright 2021-2024 Buf Technologies, Inc. | ||
: registryOrMessageDesc.getMessage(typeUrlToName(any.typeUrl)); | ||
if (!desc) { | ||
if (!desc || !anyIs(any, desc)) { | ||
return undefined; | ||
@@ -55,3 +55,3 @@ } | ||
export function anyUnpackTo(any, schema, message) { | ||
if (any.typeUrl === "") { | ||
if (!anyIs(any, schema)) { | ||
return undefined; | ||
@@ -58,0 +58,0 @@ } |
{ | ||
"name": "@bufbuild/protobuf", | ||
"version": "2.2.2", | ||
"version": "2.2.3", | ||
"license": "(Apache-2.0 AND BSD-3-Clause)", | ||
@@ -5,0 +5,0 @@ "description": "A complete implementation of Protocol Buffers in TypeScript, suitable for web browsers and Node.js.", |
1386617
36259