@fluidframework/runtime-utils
Advanced tools
@@ -8,3 +8,3 @@ /*! | ||
| export declare const pkgName = "@fluidframework/runtime-utils"; | ||
| export declare const pkgVersion = "0.40.0-25719"; | ||
| export declare const pkgVersion = "0.40.0-25851"; | ||
| //# sourceMappingURL=packageVersion.d.ts.map |
@@ -11,3 +11,3 @@ "use strict"; | ||
| exports.pkgName = "@fluidframework/runtime-utils"; | ||
| exports.pkgVersion = "0.40.0-25719"; | ||
| exports.pkgVersion = "0.40.0-25851"; | ||
| //# sourceMappingURL=packageVersion.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,+BAA+B,CAAC;AAC1C,QAAA,UAAU,GAAG,cAAc,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/runtime-utils\";\nexport const pkgVersion = \"0.40.0-25719\";\n"]} | ||
| {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,+BAA+B,CAAC;AAC1C,QAAA,UAAU,GAAG,cAAc,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/runtime-utils\";\nexport const pkgVersion = \"0.40.0-25851\";\n"]} |
+22
-1
@@ -14,6 +14,27 @@ /*! | ||
| get IFluidSerializer(): this; | ||
| /** | ||
| * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a | ||
| * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * Any unbound handles encountered are bound to the provided IFluidHandle. | ||
| */ | ||
| replaceHandles(input: any, bind: IFluidHandle): any; | ||
| /** | ||
| * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an | ||
| * equivalent object tree where any encoded IFluidHandles have been replaced with thier decoded form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * The decoded handles are implicitly bound to the handle context of this serializer. | ||
| */ | ||
| decode(input: any): any; | ||
| stringify(input: any, bind: IFluidHandle): string; | ||
| parse(input: string): any; | ||
| private recursivelyReplaceHandles; | ||
| private readonly encodeValue; | ||
| private readonly decodeValue; | ||
| private recursivelyReplace; | ||
| protected serializeHandle(handle: IFluidHandle, bind: IFluidHandle): { | ||
@@ -20,0 +41,0 @@ type: string; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACH,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EACnB,MAAM,iCAAiC,CAAC;AAKzC;;GAEG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAGjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAEP,OAAO,EAAE,mBAAmB;IAOhE,IAAW,gBAAgB,SAAmB;IAEvC,cAAc,CACjB,KAAK,EAAE,GAAG,EACV,IAAI,EAAE,YAAY;IAUf,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY;IAgBxC,KAAK,CAAC,KAAK,EAAE,MAAM;IAqB1B,OAAO,CAAC,yBAAyB;IA2CjC,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY;;;;CAOrE"} | ||
| {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EACH,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EACnB,MAAM,iCAAiC,CAAC;AAKzC;;GAEG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAGjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAEP,OAAO,EAAE,mBAAmB;IAOhE,IAAW,gBAAgB,SAAmB;IAE9C;;;;;;;;OAQG;IACK,cAAc,CAClB,KAAK,EAAE,GAAG,EACV,IAAI,EAAE,YAAY;IAUtB;;;;;;;;OAQG;IACK,MAAM,CAAC,KAAK,EAAE,GAAG;IASlB,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY;IAKxC,KAAK,CAAC,KAAK,EAAE,MAAM;IAM1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAQ1B;IAIF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAa1B;IAKF,OAAO,CAAC,kBAAkB;IAgD1B,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY;;;;CAOrE"} |
+72
-39
@@ -17,2 +17,28 @@ "use strict"; | ||
| this.context = context; | ||
| // If the given 'value' is an IFluidHandle, returns the encoded IFluidHandle. | ||
| // Otherwise returns the original 'value'. Used by 'replaceHandles()' and 'stringify()'. | ||
| this.encodeValue = (value, bind) => { | ||
| // Detect if 'value' is an IFluidHandle. | ||
| const handle = value === null || value === void 0 ? void 0 : value.IFluidHandle; | ||
| // If 'value' is an IFluidHandle return its encoded form. | ||
| return handle !== undefined | ||
| ? this.serializeHandle(handle, bind) | ||
| : value; | ||
| }; | ||
| // If the given 'value' is an encoded IFluidHandle, returns the decoded IFluidHandle. | ||
| // Otherwise returns the original 'value'. Used by 'decode()' and 'parse()'. | ||
| this.decodeValue = (value) => { | ||
| // If 'value' is a serialized IFluidHandle return the deserialized result. | ||
| if (utils_1.isSerializedHandle(value)) { | ||
| // Old documents may have handles with relative path in their summaries. Convert these to absolute | ||
| // paths. This will ensure that future summaries will have absolute paths for these handles. | ||
| const absolutePath = value.url.startsWith("/") | ||
| ? value.url | ||
| : dataStoreHandleContextUtils_1.generateHandleContextPath(value.url, this.context); | ||
| return new remoteObjectHandle_1.RemoteFluidObjectHandle(absolutePath, this.root); | ||
| } | ||
| else { | ||
| return value; | ||
| } | ||
| }; | ||
| this.root = this.context; | ||
@@ -24,50 +50,58 @@ while (this.root.routeContext !== undefined) { | ||
| get IFluidSerializer() { return this; } | ||
| /** | ||
| * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a | ||
| * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * Any unbound handles encountered are bound to the provided IFluidHandle. | ||
| */ | ||
| replaceHandles(input, bind) { | ||
| // If the given 'input' cannot contain handles, return it immediately. Otherwise, | ||
| // return the result of 'recursivelyReplaceHandles()'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return | ||
| // return the result of 'recursivelyReplace()'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
| return !!input && typeof input === "object" | ||
| ? this.recursivelyReplaceHandles(input, bind) | ||
| ? this.recursivelyReplace(input, this.encodeValue, bind) | ||
| : input; | ||
| } | ||
| /** | ||
| * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an | ||
| * equivalent object tree where any encoded IFluidHandles have been replaced with thier decoded form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * The decoded handles are implicitly bound to the handle context of this serializer. | ||
| */ | ||
| decode(input) { | ||
| // If the given 'input' cannot contain handles, return it immediately. Otherwise, | ||
| // return the result of 'recursivelyReplace()'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
| return !!input && typeof input === "object" | ||
| ? this.recursivelyReplace(input, this.decodeValue) | ||
| : input; | ||
| } | ||
| stringify(input, bind) { | ||
| return JSON.stringify(input, (key, value) => { | ||
| // If the current 'value' is not a handle, return it unmodified. Otherwise, | ||
| // return the result of 'serializeHandle'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
| const handle = !!value && value.IFluidHandle; | ||
| // TODO - understand why handle === false in some of our tests | ||
| // eslint-disable-next-line max-len | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return | ||
| return handle | ||
| ? this.serializeHandle(handle, bind) | ||
| : value; | ||
| }); | ||
| return JSON.stringify(input, (key, value) => this.encodeValue(value, bind)); | ||
| } | ||
| // Parses the serialized data - context must match the context with which the JSON was stringified | ||
| parse(input) { | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
| return JSON.parse(input, (key, value) => { | ||
| if (!utils_1.isSerializedHandle(value)) { | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
| return value; | ||
| } | ||
| // Old documents may have handles with relative path in their summaries. Convert these to absolute | ||
| // paths. This will ensure that future summaries will have absolute paths for these handles. | ||
| const absolutePath = value.url.startsWith("/") | ||
| ? value.url | ||
| : dataStoreHandleContextUtils_1.generateHandleContextPath(value.url, this.context); | ||
| return new remoteObjectHandle_1.RemoteFluidObjectHandle(absolutePath, this.root); | ||
| }); | ||
| return JSON.parse(input, (key, value) => this.decodeValue(value)); | ||
| } | ||
| // Invoked by `replaceHandles()` for non-null objects to recursively replace IFluidHandle references | ||
| // with serialized handles (cloning as-needed to avoid mutating the original `input` object.) | ||
| recursivelyReplaceHandles(input, bind) { | ||
| // If the current input is an IFluidHandle instance, replace this leaf in the object graph with | ||
| // the handle's serialized from. | ||
| // Note: Caller is responsible for ensuring that `input` is a non-null object. | ||
| const handle = input.IFluidHandle; | ||
| if (handle !== undefined) { | ||
| return this.serializeHandle(handle, bind); | ||
| // Invoked for non-null objects to recursively replace references to IFluidHandles. | ||
| // Clones as-needed to avoid mutating the `input` object. If no IFluidHandes are present, | ||
| // returns the original `input`. | ||
| recursivelyReplace(input, replacer, context) { | ||
| // Note: Caller is responsible for ensuring that `input` is defined / non-null. | ||
| // (Required for Object.keys() below.) | ||
| // Execute the `replace` on the current input. Note that Caller is responsible for ensuring that `input` | ||
| // is a non-null object. | ||
| const maybeReplaced = replacer(input, context); | ||
| // If the replacer made a substitution there is no need to decscend further. IFluidHandles are always | ||
| // leaves in the object graph. | ||
| if (maybeReplaced !== input) { | ||
| return maybeReplaced; | ||
| } | ||
| // Otherwise descend into the object graph looking for IFluidHandle instances. | ||
| // eslint-disable-next-line @typescript-eslint/ban-types | ||
@@ -82,3 +116,3 @@ let clone; | ||
| // lead to a later error when attempting to stringify(). | ||
| const replaced = this.recursivelyReplaceHandles(value, bind); | ||
| const replaced = this.recursivelyReplace(value, replacer, context); | ||
| // If the `replaced` object is different than the original `value` then the subgraph contained one | ||
@@ -98,3 +132,2 @@ // or more handles. If this happens, we need to return a clone of the `input` object where the | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
| return clone !== null && clone !== void 0 ? clone : input; | ||
@@ -101,0 +134,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAOH,6DAA+D;AAC/D,+EAA0E;AAC1E,mCAA6C;AAE7C;;GAEG;AACH,MAAa,eAAe;IAGxB,YAAoC,OAA4B;QAA5B,YAAO,GAAP,OAAO,CAAqB;QAC5D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,EAAE;YACzC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC;SACtC;IACL,CAAC;IAED,IAAW,gBAAgB,KAAK,OAAO,IAAI,CAAC,CAAC,CAAC;IAEvC,cAAc,CACjB,KAAU,EACV,IAAkB;QAElB,kFAAkF;QAClF,sDAAsD;QACtD,6GAA6G;QAC7G,OAAO,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YACvC,CAAC,CAAC,IAAI,CAAC,yBAAyB,CAAC,KAAK,EAAE,IAAI,CAAC;YAC7C,CAAC,CAAC,KAAK,CAAC;IAChB,CAAC;IAEM,SAAS,CAAC,KAAU,EAAE,IAAkB;QAC3C,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACxC,4EAA4E;YAC5E,0CAA0C;YAC1C,yEAAyE;YACzE,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,YAAY,CAAC;YAC7C,8DAA8D;YAC9D,mCAAmC;YACnC,6GAA6G;YAC7G,OAAO,MAAM;gBACT,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC;gBACpC,CAAC,CAAC,KAAK,CAAC;QAChB,CAAC,CAAC,CAAC;IACP,CAAC;IAED,kGAAkG;IAC3F,KAAK,CAAC,KAAa;QACtB,+DAA+D;QAC/D,OAAO,IAAI,CAAC,KAAK,CACb,KAAK,EACL,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACX,IAAI,CAAC,0BAAkB,CAAC,KAAK,CAAC,EAAE;gBAC5B,+DAA+D;gBAC/D,OAAO,KAAK,CAAC;aAChB;YAED,kGAAkG;YAClG,4FAA4F;YAC5F,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;gBAC1C,CAAC,CAAC,KAAK,CAAC,GAAG;gBACX,CAAC,CAAC,uDAAyB,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACzD,OAAO,IAAI,4CAAuB,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;IACX,CAAC;IAED,oGAAoG;IACpG,6FAA6F;IACrF,yBAAyB,CAC7B,KAAU,EACV,IAAkB;QAElB,+FAA+F;QAC/F,gCAAgC;QAEhC,8EAA8E;QAC9E,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC;QAClC,IAAI,MAAM,KAAK,SAAS,EAAE;YACtB,OAAO,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;SAC7C;QAED,wDAAwD;QACxD,IAAI,KAAyB,CAAC;QAC9B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;YAClC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;YACzB,yEAAyE;YACzE,IAAI,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;gBACtC,8FAA8F;gBAC9F,+FAA+F;gBAC/F,8DAA8D;gBAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,yBAAyB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;gBAE7D,kGAAkG;gBAClG,+FAA+F;gBAC/F,wDAAwD;gBACxD,IAAI,QAAQ,KAAK,KAAK,EAAE;oBACpB,qFAAqF;oBACrF,KAAK,GAAG,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;wBAClC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;wBACZ,CAAC,mBAAM,KAAK,CAAE,CAAC,CAAC;oBAEpB,+EAA+E;oBAC/E,oEAAoE;oBACpE,KAAM,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC;iBAC1B;aACJ;SACJ;QACD,+DAA+D;QAC/D,OAAO,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,KAAK,CAAC;IAC1B,CAAC;IAES,eAAe,CAAC,MAAoB,EAAE,IAAkB;QAC9D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClB,OAAO;YACH,IAAI,EAAE,kBAAkB;YACxB,GAAG,EAAE,MAAM,CAAC,YAAY;SAC3B,CAAC;IACN,CAAC;CACJ;AA/GD,0CA+GC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n IFluidHandle,\n IFluidHandleContext,\n IFluidSerializer,\n} from \"@fluidframework/core-interfaces\";\nimport { RemoteFluidObjectHandle } from \"./remoteObjectHandle\";\nimport { generateHandleContextPath } from \"./dataStoreHandleContextUtils\";\nimport { isSerializedHandle } from \"./utils\";\n\n/**\n * Data Store serializer implementation\n */\nexport class FluidSerializer implements IFluidSerializer {\n private readonly root: IFluidHandleContext;\n\n public constructor(private readonly context: IFluidHandleContext) {\n this.root = this.context;\n while (this.root.routeContext !== undefined) {\n this.root = this.root.routeContext;\n }\n }\n\n public get IFluidSerializer() { return this; }\n\n public replaceHandles(\n input: any,\n bind: IFluidHandle,\n ) {\n // If the given 'input' cannot contain handles, return it immediately. Otherwise,\n // return the result of 'recursivelyReplaceHandles()'.\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return\n return !!input && typeof input === \"object\"\n ? this.recursivelyReplaceHandles(input, bind)\n : input;\n }\n\n public stringify(input: any, bind: IFluidHandle) {\n return JSON.stringify(input, (key, value) => {\n // If the current 'value' is not a handle, return it unmodified. Otherwise,\n // return the result of 'serializeHandle'.\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n const handle = !!value && value.IFluidHandle;\n // TODO - understand why handle === false in some of our tests\n // eslint-disable-next-line max-len\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return\n return handle\n ? this.serializeHandle(handle, bind)\n : value;\n });\n }\n\n // Parses the serialized data - context must match the context with which the JSON was stringified\n public parse(input: string) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return JSON.parse(\n input,\n (key, value) => {\n if (!isSerializedHandle(value)) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n }\n\n // Old documents may have handles with relative path in their summaries. Convert these to absolute\n // paths. This will ensure that future summaries will have absolute paths for these handles.\n const absolutePath = value.url.startsWith(\"/\")\n ? value.url\n : generateHandleContextPath(value.url, this.context);\n return new RemoteFluidObjectHandle(absolutePath, this.root);\n });\n }\n\n // Invoked by `replaceHandles()` for non-null objects to recursively replace IFluidHandle references\n // with serialized handles (cloning as-needed to avoid mutating the original `input` object.)\n private recursivelyReplaceHandles(\n input: any,\n bind: IFluidHandle,\n ) {\n // If the current input is an IFluidHandle instance, replace this leaf in the object graph with\n // the handle's serialized from.\n\n // Note: Caller is responsible for ensuring that `input` is a non-null object.\n const handle = input.IFluidHandle;\n if (handle !== undefined) {\n return this.serializeHandle(handle, bind);\n }\n\n // eslint-disable-next-line @typescript-eslint/ban-types\n let clone: object | undefined;\n for (const key of Object.keys(input)) {\n const value = input[key];\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n if (!!value && typeof value === \"object\") {\n // Note: Except for IFluidHandle, `input` must not contain circular references (as object must\n // be JSON serializable.) Therefore, guarding against infinite recursion here would only\n // lead to a later error when attempting to stringify().\n const replaced = this.recursivelyReplaceHandles(value, bind);\n\n // If the `replaced` object is different than the original `value` then the subgraph contained one\n // or more handles. If this happens, we need to return a clone of the `input` object where the\n // current property is replaced by the `replaced` value.\n if (replaced !== value) {\n // Lazily create a shallow clone of the `input` object if we haven't done so already.\n clone = clone ?? (Array.isArray(input)\n ? [...input]\n : { ...input });\n\n // Overwrite the current property `key` in the clone with the `replaced` value.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n clone![key] = replaced;\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return clone ?? input;\n }\n\n protected serializeHandle(handle: IFluidHandle, bind: IFluidHandle) {\n bind.bind(handle);\n return {\n type: \"__fluid_handle__\",\n url: handle.absolutePath,\n };\n }\n}\n"]} | ||
| {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// RATIONALE: Many methods consume and return 'any' by necessity.\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n\nimport {\n IFluidHandle,\n IFluidHandleContext,\n IFluidSerializer,\n} from \"@fluidframework/core-interfaces\";\nimport { RemoteFluidObjectHandle } from \"./remoteObjectHandle\";\nimport { generateHandleContextPath } from \"./dataStoreHandleContextUtils\";\nimport { isSerializedHandle } from \"./utils\";\n\n/**\n * Data Store serializer implementation\n */\nexport class FluidSerializer implements IFluidSerializer {\n private readonly root: IFluidHandleContext;\n\n public constructor(private readonly context: IFluidHandleContext) {\n this.root = this.context;\n while (this.root.routeContext !== undefined) {\n this.root = this.root.routeContext;\n }\n }\n\n public get IFluidSerializer() { return this; }\n\n /**\n * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a\n * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form.\n *\n * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n * the root to any replaced handles. (If no handles are found, returns the original object.)\n *\n * Any unbound handles encountered are bound to the provided IFluidHandle.\n */\n public replaceHandles(\n input: any,\n bind: IFluidHandle,\n ) {\n // If the given 'input' cannot contain handles, return it immediately. Otherwise,\n // return the result of 'recursivelyReplace()'.\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n return !!input && typeof input === \"object\"\n ? this.recursivelyReplace(input, this.encodeValue, bind)\n : input;\n }\n\n /**\n * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n * equivalent object tree where any encoded IFluidHandles have been replaced with thier decoded form.\n *\n * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n * the root to any replaced handles. (If no handles are found, returns the original object.)\n *\n * The decoded handles are implicitly bound to the handle context of this serializer.\n */\n public decode(input: any) {\n // If the given 'input' cannot contain handles, return it immediately. Otherwise,\n // return the result of 'recursivelyReplace()'.\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n return !!input && typeof input === \"object\"\n ? this.recursivelyReplace(input, this.decodeValue)\n : input;\n }\n\n public stringify(input: any, bind: IFluidHandle) {\n return JSON.stringify(input, (key, value) => this.encodeValue(value, bind));\n }\n\n // Parses the serialized data - context must match the context with which the JSON was stringified\n public parse(input: string) {\n return JSON.parse(input, (key, value) => this.decodeValue(value));\n }\n\n // If the given 'value' is an IFluidHandle, returns the encoded IFluidHandle.\n // Otherwise returns the original 'value'. Used by 'replaceHandles()' and 'stringify()'.\n private readonly encodeValue = (value: any, bind: IFluidHandle) => {\n // Detect if 'value' is an IFluidHandle.\n const handle = value?.IFluidHandle;\n\n // If 'value' is an IFluidHandle return its encoded form.\n return handle !== undefined\n ? this.serializeHandle(handle, bind)\n : value;\n };\n\n // If the given 'value' is an encoded IFluidHandle, returns the decoded IFluidHandle.\n // Otherwise returns the original 'value'. Used by 'decode()' and 'parse()'.\n private readonly decodeValue = (value: any) => {\n // If 'value' is a serialized IFluidHandle return the deserialized result.\n if (isSerializedHandle(value)) {\n // Old documents may have handles with relative path in their summaries. Convert these to absolute\n // paths. This will ensure that future summaries will have absolute paths for these handles.\n const absolutePath = value.url.startsWith(\"/\")\n ? value.url\n : generateHandleContextPath(value.url, this.context);\n\n return new RemoteFluidObjectHandle(absolutePath, this.root);\n } else {\n return value;\n }\n };\n\n // Invoked for non-null objects to recursively replace references to IFluidHandles.\n // Clones as-needed to avoid mutating the `input` object. If no IFluidHandes are present,\n // returns the original `input`.\n private recursivelyReplace(\n input: any,\n replacer: (input: any, context: any) => any,\n context?: any,\n ) {\n // Note: Caller is responsible for ensuring that `input` is defined / non-null.\n // (Required for Object.keys() below.)\n\n // Execute the `replace` on the current input. Note that Caller is responsible for ensuring that `input`\n // is a non-null object.\n const maybeReplaced = replacer(input, context);\n\n // If the replacer made a substitution there is no need to decscend further. IFluidHandles are always\n // leaves in the object graph.\n if (maybeReplaced !== input) {\n return maybeReplaced;\n }\n\n // Otherwise descend into the object graph looking for IFluidHandle instances.\n // eslint-disable-next-line @typescript-eslint/ban-types\n let clone: object | undefined;\n for (const key of Object.keys(input)) {\n const value = input[key];\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n if (!!value && typeof value === \"object\") {\n // Note: Except for IFluidHandle, `input` must not contain circular references (as object must\n // be JSON serializable.) Therefore, guarding against infinite recursion here would only\n // lead to a later error when attempting to stringify().\n const replaced = this.recursivelyReplace(value, replacer, context);\n\n // If the `replaced` object is different than the original `value` then the subgraph contained one\n // or more handles. If this happens, we need to return a clone of the `input` object where the\n // current property is replaced by the `replaced` value.\n if (replaced !== value) {\n // Lazily create a shallow clone of the `input` object if we haven't done so already.\n clone = clone ?? (Array.isArray(input)\n ? [...input]\n : { ...input });\n\n // Overwrite the current property `key` in the clone with the `replaced` value.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n clone![key] = replaced;\n }\n }\n }\n return clone ?? input;\n }\n\n protected serializeHandle(handle: IFluidHandle, bind: IFluidHandle) {\n bind.bind(handle);\n return {\n type: \"__fluid_handle__\",\n url: handle.absolutePath,\n };\n }\n}\n"]} |
@@ -8,3 +8,3 @@ /*! | ||
| export declare const pkgName = "@fluidframework/runtime-utils"; | ||
| export declare const pkgVersion = "0.40.0-25719"; | ||
| export declare const pkgVersion = "0.40.0-25851"; | ||
| //# sourceMappingURL=packageVersion.d.ts.map |
@@ -8,3 +8,3 @@ /*! | ||
| export const pkgName = "@fluidframework/runtime-utils"; | ||
| export const pkgVersion = "0.40.0-25719"; | ||
| export const pkgVersion = "0.40.0-25851"; | ||
| //# sourceMappingURL=packageVersion.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,+BAA+B,CAAC;AACvD,MAAM,CAAC,MAAM,UAAU,GAAG,cAAc,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/runtime-utils\";\nexport const pkgVersion = \"0.40.0-25719\";\n"]} | ||
| {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,+BAA+B,CAAC;AACvD,MAAM,CAAC,MAAM,UAAU,GAAG,cAAc,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/runtime-utils\";\nexport const pkgVersion = \"0.40.0-25851\";\n"]} |
+22
-1
@@ -14,6 +14,27 @@ /*! | ||
| get IFluidSerializer(): this; | ||
| /** | ||
| * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a | ||
| * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * Any unbound handles encountered are bound to the provided IFluidHandle. | ||
| */ | ||
| replaceHandles(input: any, bind: IFluidHandle): any; | ||
| /** | ||
| * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an | ||
| * equivalent object tree where any encoded IFluidHandles have been replaced with thier decoded form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * The decoded handles are implicitly bound to the handle context of this serializer. | ||
| */ | ||
| decode(input: any): any; | ||
| stringify(input: any, bind: IFluidHandle): string; | ||
| parse(input: string): any; | ||
| private recursivelyReplaceHandles; | ||
| private readonly encodeValue; | ||
| private readonly decodeValue; | ||
| private recursivelyReplace; | ||
| protected serializeHandle(handle: IFluidHandle, bind: IFluidHandle): { | ||
@@ -20,0 +41,0 @@ type: string; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACH,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EACnB,MAAM,iCAAiC,CAAC;AAKzC;;GAEG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAGjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAEP,OAAO,EAAE,mBAAmB;IAOhE,IAAW,gBAAgB,SAAmB;IAEvC,cAAc,CACjB,KAAK,EAAE,GAAG,EACV,IAAI,EAAE,YAAY;IAUf,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY;IAgBxC,KAAK,CAAC,KAAK,EAAE,MAAM;IAqB1B,OAAO,CAAC,yBAAyB;IA2CjC,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY;;;;CAOrE"} | ||
| {"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EACH,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EACnB,MAAM,iCAAiC,CAAC;AAKzC;;GAEG;AACH,qBAAa,eAAgB,YAAW,gBAAgB;IAGjC,OAAO,CAAC,QAAQ,CAAC,OAAO;IAF3C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAsB;gBAEP,OAAO,EAAE,mBAAmB;IAOhE,IAAW,gBAAgB,SAAmB;IAE9C;;;;;;;;OAQG;IACK,cAAc,CAClB,KAAK,EAAE,GAAG,EACV,IAAI,EAAE,YAAY;IAUtB;;;;;;;;OAQG;IACK,MAAM,CAAC,KAAK,EAAE,GAAG;IASlB,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY;IAKxC,KAAK,CAAC,KAAK,EAAE,MAAM;IAM1B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAQ1B;IAIF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAa1B;IAKF,OAAO,CAAC,kBAAkB;IAgD1B,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY;;;;CAOrE"} |
+72
-39
@@ -14,2 +14,28 @@ /*! | ||
| this.context = context; | ||
| // If the given 'value' is an IFluidHandle, returns the encoded IFluidHandle. | ||
| // Otherwise returns the original 'value'. Used by 'replaceHandles()' and 'stringify()'. | ||
| this.encodeValue = (value, bind) => { | ||
| // Detect if 'value' is an IFluidHandle. | ||
| const handle = value === null || value === void 0 ? void 0 : value.IFluidHandle; | ||
| // If 'value' is an IFluidHandle return its encoded form. | ||
| return handle !== undefined | ||
| ? this.serializeHandle(handle, bind) | ||
| : value; | ||
| }; | ||
| // If the given 'value' is an encoded IFluidHandle, returns the decoded IFluidHandle. | ||
| // Otherwise returns the original 'value'. Used by 'decode()' and 'parse()'. | ||
| this.decodeValue = (value) => { | ||
| // If 'value' is a serialized IFluidHandle return the deserialized result. | ||
| if (isSerializedHandle(value)) { | ||
| // Old documents may have handles with relative path in their summaries. Convert these to absolute | ||
| // paths. This will ensure that future summaries will have absolute paths for these handles. | ||
| const absolutePath = value.url.startsWith("/") | ||
| ? value.url | ||
| : generateHandleContextPath(value.url, this.context); | ||
| return new RemoteFluidObjectHandle(absolutePath, this.root); | ||
| } | ||
| else { | ||
| return value; | ||
| } | ||
| }; | ||
| this.root = this.context; | ||
@@ -21,50 +47,58 @@ while (this.root.routeContext !== undefined) { | ||
| get IFluidSerializer() { return this; } | ||
| /** | ||
| * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a | ||
| * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * Any unbound handles encountered are bound to the provided IFluidHandle. | ||
| */ | ||
| replaceHandles(input, bind) { | ||
| // If the given 'input' cannot contain handles, return it immediately. Otherwise, | ||
| // return the result of 'recursivelyReplaceHandles()'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return | ||
| // return the result of 'recursivelyReplace()'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
| return !!input && typeof input === "object" | ||
| ? this.recursivelyReplaceHandles(input, bind) | ||
| ? this.recursivelyReplace(input, this.encodeValue, bind) | ||
| : input; | ||
| } | ||
| /** | ||
| * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an | ||
| * equivalent object tree where any encoded IFluidHandles have been replaced with thier decoded form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * The decoded handles are implicitly bound to the handle context of this serializer. | ||
| */ | ||
| decode(input) { | ||
| // If the given 'input' cannot contain handles, return it immediately. Otherwise, | ||
| // return the result of 'recursivelyReplace()'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
| return !!input && typeof input === "object" | ||
| ? this.recursivelyReplace(input, this.decodeValue) | ||
| : input; | ||
| } | ||
| stringify(input, bind) { | ||
| return JSON.stringify(input, (key, value) => { | ||
| // If the current 'value' is not a handle, return it unmodified. Otherwise, | ||
| // return the result of 'serializeHandle'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
| const handle = !!value && value.IFluidHandle; | ||
| // TODO - understand why handle === false in some of our tests | ||
| // eslint-disable-next-line max-len | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return | ||
| return handle | ||
| ? this.serializeHandle(handle, bind) | ||
| : value; | ||
| }); | ||
| return JSON.stringify(input, (key, value) => this.encodeValue(value, bind)); | ||
| } | ||
| // Parses the serialized data - context must match the context with which the JSON was stringified | ||
| parse(input) { | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
| return JSON.parse(input, (key, value) => { | ||
| if (!isSerializedHandle(value)) { | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
| return value; | ||
| } | ||
| // Old documents may have handles with relative path in their summaries. Convert these to absolute | ||
| // paths. This will ensure that future summaries will have absolute paths for these handles. | ||
| const absolutePath = value.url.startsWith("/") | ||
| ? value.url | ||
| : generateHandleContextPath(value.url, this.context); | ||
| return new RemoteFluidObjectHandle(absolutePath, this.root); | ||
| }); | ||
| return JSON.parse(input, (key, value) => this.decodeValue(value)); | ||
| } | ||
| // Invoked by `replaceHandles()` for non-null objects to recursively replace IFluidHandle references | ||
| // with serialized handles (cloning as-needed to avoid mutating the original `input` object.) | ||
| recursivelyReplaceHandles(input, bind) { | ||
| // If the current input is an IFluidHandle instance, replace this leaf in the object graph with | ||
| // the handle's serialized from. | ||
| // Note: Caller is responsible for ensuring that `input` is a non-null object. | ||
| const handle = input.IFluidHandle; | ||
| if (handle !== undefined) { | ||
| return this.serializeHandle(handle, bind); | ||
| // Invoked for non-null objects to recursively replace references to IFluidHandles. | ||
| // Clones as-needed to avoid mutating the `input` object. If no IFluidHandes are present, | ||
| // returns the original `input`. | ||
| recursivelyReplace(input, replacer, context) { | ||
| // Note: Caller is responsible for ensuring that `input` is defined / non-null. | ||
| // (Required for Object.keys() below.) | ||
| // Execute the `replace` on the current input. Note that Caller is responsible for ensuring that `input` | ||
| // is a non-null object. | ||
| const maybeReplaced = replacer(input, context); | ||
| // If the replacer made a substitution there is no need to decscend further. IFluidHandles are always | ||
| // leaves in the object graph. | ||
| if (maybeReplaced !== input) { | ||
| return maybeReplaced; | ||
| } | ||
| // Otherwise descend into the object graph looking for IFluidHandle instances. | ||
| // eslint-disable-next-line @typescript-eslint/ban-types | ||
@@ -79,3 +113,3 @@ let clone; | ||
| // lead to a later error when attempting to stringify(). | ||
| const replaced = this.recursivelyReplaceHandles(value, bind); | ||
| const replaced = this.recursivelyReplace(value, replacer, context); | ||
| // If the `replaced` object is different than the original `value` then the subgraph contained one | ||
@@ -95,3 +129,2 @@ // or more handles. If this happens, we need to return a clone of the `input` object where the | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
| return clone !== null && clone !== void 0 ? clone : input; | ||
@@ -98,0 +131,0 @@ } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n IFluidHandle,\n IFluidHandleContext,\n IFluidSerializer,\n} from \"@fluidframework/core-interfaces\";\nimport { RemoteFluidObjectHandle } from \"./remoteObjectHandle\";\nimport { generateHandleContextPath } from \"./dataStoreHandleContextUtils\";\nimport { isSerializedHandle } from \"./utils\";\n\n/**\n * Data Store serializer implementation\n */\nexport class FluidSerializer implements IFluidSerializer {\n private readonly root: IFluidHandleContext;\n\n public constructor(private readonly context: IFluidHandleContext) {\n this.root = this.context;\n while (this.root.routeContext !== undefined) {\n this.root = this.root.routeContext;\n }\n }\n\n public get IFluidSerializer() { return this; }\n\n public replaceHandles(\n input: any,\n bind: IFluidHandle,\n ) {\n // If the given 'input' cannot contain handles, return it immediately. Otherwise,\n // return the result of 'recursivelyReplaceHandles()'.\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return\n return !!input && typeof input === \"object\"\n ? this.recursivelyReplaceHandles(input, bind)\n : input;\n }\n\n public stringify(input: any, bind: IFluidHandle) {\n return JSON.stringify(input, (key, value) => {\n // If the current 'value' is not a handle, return it unmodified. Otherwise,\n // return the result of 'serializeHandle'.\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n const handle = !!value && value.IFluidHandle;\n // TODO - understand why handle === false in some of our tests\n // eslint-disable-next-line max-len\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return\n return handle\n ? this.serializeHandle(handle, bind)\n : value;\n });\n }\n\n // Parses the serialized data - context must match the context with which the JSON was stringified\n public parse(input: string) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return JSON.parse(\n input,\n (key, value) => {\n if (!isSerializedHandle(value)) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return value;\n }\n\n // Old documents may have handles with relative path in their summaries. Convert these to absolute\n // paths. This will ensure that future summaries will have absolute paths for these handles.\n const absolutePath = value.url.startsWith(\"/\")\n ? value.url\n : generateHandleContextPath(value.url, this.context);\n return new RemoteFluidObjectHandle(absolutePath, this.root);\n });\n }\n\n // Invoked by `replaceHandles()` for non-null objects to recursively replace IFluidHandle references\n // with serialized handles (cloning as-needed to avoid mutating the original `input` object.)\n private recursivelyReplaceHandles(\n input: any,\n bind: IFluidHandle,\n ) {\n // If the current input is an IFluidHandle instance, replace this leaf in the object graph with\n // the handle's serialized from.\n\n // Note: Caller is responsible for ensuring that `input` is a non-null object.\n const handle = input.IFluidHandle;\n if (handle !== undefined) {\n return this.serializeHandle(handle, bind);\n }\n\n // eslint-disable-next-line @typescript-eslint/ban-types\n let clone: object | undefined;\n for (const key of Object.keys(input)) {\n const value = input[key];\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n if (!!value && typeof value === \"object\") {\n // Note: Except for IFluidHandle, `input` must not contain circular references (as object must\n // be JSON serializable.) Therefore, guarding against infinite recursion here would only\n // lead to a later error when attempting to stringify().\n const replaced = this.recursivelyReplaceHandles(value, bind);\n\n // If the `replaced` object is different than the original `value` then the subgraph contained one\n // or more handles. If this happens, we need to return a clone of the `input` object where the\n // current property is replaced by the `replaced` value.\n if (replaced !== value) {\n // Lazily create a shallow clone of the `input` object if we haven't done so already.\n clone = clone ?? (Array.isArray(input)\n ? [...input]\n : { ...input });\n\n // Overwrite the current property `key` in the clone with the `replaced` value.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n clone![key] = replaced;\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return clone ?? input;\n }\n\n protected serializeHandle(handle: IFluidHandle, bind: IFluidHandle) {\n bind.bind(handle);\n return {\n type: \"__fluid_handle__\",\n url: handle.absolutePath,\n };\n }\n}\n"]} | ||
| {"version":3,"file":"serializer.js","sourceRoot":"","sources":["../src/serializer.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// RATIONALE: Many methods consume and return 'any' by necessity.\n/* eslint-disable @typescript-eslint/no-unsafe-return */\n\nimport {\n IFluidHandle,\n IFluidHandleContext,\n IFluidSerializer,\n} from \"@fluidframework/core-interfaces\";\nimport { RemoteFluidObjectHandle } from \"./remoteObjectHandle\";\nimport { generateHandleContextPath } from \"./dataStoreHandleContextUtils\";\nimport { isSerializedHandle } from \"./utils\";\n\n/**\n * Data Store serializer implementation\n */\nexport class FluidSerializer implements IFluidSerializer {\n private readonly root: IFluidHandleContext;\n\n public constructor(private readonly context: IFluidHandleContext) {\n this.root = this.context;\n while (this.root.routeContext !== undefined) {\n this.root = this.root.routeContext;\n }\n }\n\n public get IFluidSerializer() { return this; }\n\n /**\n * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a\n * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form.\n *\n * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n * the root to any replaced handles. (If no handles are found, returns the original object.)\n *\n * Any unbound handles encountered are bound to the provided IFluidHandle.\n */\n public replaceHandles(\n input: any,\n bind: IFluidHandle,\n ) {\n // If the given 'input' cannot contain handles, return it immediately. Otherwise,\n // return the result of 'recursivelyReplace()'.\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n return !!input && typeof input === \"object\"\n ? this.recursivelyReplace(input, this.encodeValue, bind)\n : input;\n }\n\n /**\n * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an\n * equivalent object tree where any encoded IFluidHandles have been replaced with thier decoded form.\n *\n * The original `input` object is not mutated. This method will shallowly clones all objects in the path from\n * the root to any replaced handles. (If no handles are found, returns the original object.)\n *\n * The decoded handles are implicitly bound to the handle context of this serializer.\n */\n public decode(input: any) {\n // If the given 'input' cannot contain handles, return it immediately. Otherwise,\n // return the result of 'recursivelyReplace()'.\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n return !!input && typeof input === \"object\"\n ? this.recursivelyReplace(input, this.decodeValue)\n : input;\n }\n\n public stringify(input: any, bind: IFluidHandle) {\n return JSON.stringify(input, (key, value) => this.encodeValue(value, bind));\n }\n\n // Parses the serialized data - context must match the context with which the JSON was stringified\n public parse(input: string) {\n return JSON.parse(input, (key, value) => this.decodeValue(value));\n }\n\n // If the given 'value' is an IFluidHandle, returns the encoded IFluidHandle.\n // Otherwise returns the original 'value'. Used by 'replaceHandles()' and 'stringify()'.\n private readonly encodeValue = (value: any, bind: IFluidHandle) => {\n // Detect if 'value' is an IFluidHandle.\n const handle = value?.IFluidHandle;\n\n // If 'value' is an IFluidHandle return its encoded form.\n return handle !== undefined\n ? this.serializeHandle(handle, bind)\n : value;\n };\n\n // If the given 'value' is an encoded IFluidHandle, returns the decoded IFluidHandle.\n // Otherwise returns the original 'value'. Used by 'decode()' and 'parse()'.\n private readonly decodeValue = (value: any) => {\n // If 'value' is a serialized IFluidHandle return the deserialized result.\n if (isSerializedHandle(value)) {\n // Old documents may have handles with relative path in their summaries. Convert these to absolute\n // paths. This will ensure that future summaries will have absolute paths for these handles.\n const absolutePath = value.url.startsWith(\"/\")\n ? value.url\n : generateHandleContextPath(value.url, this.context);\n\n return new RemoteFluidObjectHandle(absolutePath, this.root);\n } else {\n return value;\n }\n };\n\n // Invoked for non-null objects to recursively replace references to IFluidHandles.\n // Clones as-needed to avoid mutating the `input` object. If no IFluidHandes are present,\n // returns the original `input`.\n private recursivelyReplace(\n input: any,\n replacer: (input: any, context: any) => any,\n context?: any,\n ) {\n // Note: Caller is responsible for ensuring that `input` is defined / non-null.\n // (Required for Object.keys() below.)\n\n // Execute the `replace` on the current input. Note that Caller is responsible for ensuring that `input`\n // is a non-null object.\n const maybeReplaced = replacer(input, context);\n\n // If the replacer made a substitution there is no need to decscend further. IFluidHandles are always\n // leaves in the object graph.\n if (maybeReplaced !== input) {\n return maybeReplaced;\n }\n\n // Otherwise descend into the object graph looking for IFluidHandle instances.\n // eslint-disable-next-line @typescript-eslint/ban-types\n let clone: object | undefined;\n for (const key of Object.keys(input)) {\n const value = input[key];\n // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n if (!!value && typeof value === \"object\") {\n // Note: Except for IFluidHandle, `input` must not contain circular references (as object must\n // be JSON serializable.) Therefore, guarding against infinite recursion here would only\n // lead to a later error when attempting to stringify().\n const replaced = this.recursivelyReplace(value, replacer, context);\n\n // If the `replaced` object is different than the original `value` then the subgraph contained one\n // or more handles. If this happens, we need to return a clone of the `input` object where the\n // current property is replaced by the `replaced` value.\n if (replaced !== value) {\n // Lazily create a shallow clone of the `input` object if we haven't done so already.\n clone = clone ?? (Array.isArray(input)\n ? [...input]\n : { ...input });\n\n // Overwrite the current property `key` in the clone with the `replaced` value.\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n clone![key] = replaced;\n }\n }\n }\n return clone ?? input;\n }\n\n protected serializeHandle(handle: IFluidHandle, bind: IFluidHandle) {\n bind.bind(handle);\n return {\n type: \"__fluid_handle__\",\n url: handle.absolutePath,\n };\n }\n}\n"]} |
+5
-5
| { | ||
| "name": "@fluidframework/runtime-utils", | ||
| "version": "0.40.0-25719", | ||
| "version": "0.40.0-25851", | ||
| "description": "Collection of utility functions for Fluid Runtime", | ||
@@ -62,7 +62,7 @@ "homepage": "https://fluidframework.com", | ||
| "@fluidframework/core-interfaces": "^0.39.0", | ||
| "@fluidframework/datastore-definitions": "0.40.0-25719", | ||
| "@fluidframework/garbage-collector": "0.40.0-25719", | ||
| "@fluidframework/datastore-definitions": "0.40.0-25851", | ||
| "@fluidframework/garbage-collector": "0.40.0-25851", | ||
| "@fluidframework/protocol-base": "^0.1025.0-0", | ||
| "@fluidframework/protocol-definitions": "^0.1024.0", | ||
| "@fluidframework/runtime-definitions": "0.40.0-25719", | ||
| "@fluidframework/runtime-definitions": "0.40.0-25851", | ||
| "assert": "^2.0.0" | ||
@@ -73,3 +73,3 @@ }, | ||
| "@fluidframework/eslint-config-fluid": "^0.23.0", | ||
| "@fluidframework/mocha-test-setup": "0.40.0-25719", | ||
| "@fluidframework/mocha-test-setup": "0.40.0-25851", | ||
| "@microsoft/api-extractor": "^7.13.1", | ||
@@ -76,0 +76,0 @@ "@types/assert": "^1.5.2", |
@@ -9,2 +9,2 @@ /*! | ||
| export const pkgName = "@fluidframework/runtime-utils"; | ||
| export const pkgVersion = "0.40.0-25719"; | ||
| export const pkgVersion = "0.40.0-25851"; |
+83
-44
@@ -6,2 +6,5 @@ /*! | ||
| // RATIONALE: Many methods consume and return 'any' by necessity. | ||
| /* eslint-disable @typescript-eslint/no-unsafe-return */ | ||
| import { | ||
@@ -31,3 +34,12 @@ IFluidHandle, | ||
| public replaceHandles( | ||
| /** | ||
| * Given a mostly-jsonable object tree that may have handle objects embedded within, will return a | ||
| * fully-jsonable object tree where any embedded IFluidHandles have been replaced with a serializable form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * Any unbound handles encountered are bound to the provided IFluidHandle. | ||
| */ | ||
| public replaceHandles( | ||
| input: any, | ||
@@ -37,22 +49,29 @@ bind: IFluidHandle, | ||
| // If the given 'input' cannot contain handles, return it immediately. Otherwise, | ||
| // return the result of 'recursivelyReplaceHandles()'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return | ||
| // return the result of 'recursivelyReplace()'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
| return !!input && typeof input === "object" | ||
| ? this.recursivelyReplaceHandles(input, bind) | ||
| ? this.recursivelyReplace(input, this.encodeValue, bind) | ||
| : input; | ||
| } | ||
| /** | ||
| * Given a fully-jsonable object tree that may have encoded handle objects embedded within, will return an | ||
| * equivalent object tree where any encoded IFluidHandles have been replaced with thier decoded form. | ||
| * | ||
| * The original `input` object is not mutated. This method will shallowly clones all objects in the path from | ||
| * the root to any replaced handles. (If no handles are found, returns the original object.) | ||
| * | ||
| * The decoded handles are implicitly bound to the handle context of this serializer. | ||
| */ | ||
| public decode(input: any) { | ||
| // If the given 'input' cannot contain handles, return it immediately. Otherwise, | ||
| // return the result of 'recursivelyReplace()'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
| return !!input && typeof input === "object" | ||
| ? this.recursivelyReplace(input, this.decodeValue) | ||
| : input; | ||
| } | ||
| public stringify(input: any, bind: IFluidHandle) { | ||
| return JSON.stringify(input, (key, value) => { | ||
| // If the current 'value' is not a handle, return it unmodified. Otherwise, | ||
| // return the result of 'serializeHandle'. | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions | ||
| const handle = !!value && value.IFluidHandle; | ||
| // TODO - understand why handle === false in some of our tests | ||
| // eslint-disable-next-line max-len | ||
| // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions,@typescript-eslint/no-unsafe-return | ||
| return handle | ||
| ? this.serializeHandle(handle, bind) | ||
| : value; | ||
| }); | ||
| return JSON.stringify(input, (key, value) => this.encodeValue(value, bind)); | ||
| } | ||
@@ -62,35 +81,56 @@ | ||
| public parse(input: string) { | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
| return JSON.parse( | ||
| input, | ||
| (key, value) => { | ||
| if (!isSerializedHandle(value)) { | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
| return value; | ||
| } | ||
| // Old documents may have handles with relative path in their summaries. Convert these to absolute | ||
| // paths. This will ensure that future summaries will have absolute paths for these handles. | ||
| const absolutePath = value.url.startsWith("/") | ||
| ? value.url | ||
| : generateHandleContextPath(value.url, this.context); | ||
| return new RemoteFluidObjectHandle(absolutePath, this.root); | ||
| }); | ||
| return JSON.parse(input, (key, value) => this.decodeValue(value)); | ||
| } | ||
| // Invoked by `replaceHandles()` for non-null objects to recursively replace IFluidHandle references | ||
| // with serialized handles (cloning as-needed to avoid mutating the original `input` object.) | ||
| private recursivelyReplaceHandles( | ||
| // If the given 'value' is an IFluidHandle, returns the encoded IFluidHandle. | ||
| // Otherwise returns the original 'value'. Used by 'replaceHandles()' and 'stringify()'. | ||
| private readonly encodeValue = (value: any, bind: IFluidHandle) => { | ||
| // Detect if 'value' is an IFluidHandle. | ||
| const handle = value?.IFluidHandle; | ||
| // If 'value' is an IFluidHandle return its encoded form. | ||
| return handle !== undefined | ||
| ? this.serializeHandle(handle, bind) | ||
| : value; | ||
| }; | ||
| // If the given 'value' is an encoded IFluidHandle, returns the decoded IFluidHandle. | ||
| // Otherwise returns the original 'value'. Used by 'decode()' and 'parse()'. | ||
| private readonly decodeValue = (value: any) => { | ||
| // If 'value' is a serialized IFluidHandle return the deserialized result. | ||
| if (isSerializedHandle(value)) { | ||
| // Old documents may have handles with relative path in their summaries. Convert these to absolute | ||
| // paths. This will ensure that future summaries will have absolute paths for these handles. | ||
| const absolutePath = value.url.startsWith("/") | ||
| ? value.url | ||
| : generateHandleContextPath(value.url, this.context); | ||
| return new RemoteFluidObjectHandle(absolutePath, this.root); | ||
| } else { | ||
| return value; | ||
| } | ||
| }; | ||
| // Invoked for non-null objects to recursively replace references to IFluidHandles. | ||
| // Clones as-needed to avoid mutating the `input` object. If no IFluidHandes are present, | ||
| // returns the original `input`. | ||
| private recursivelyReplace( | ||
| input: any, | ||
| bind: IFluidHandle, | ||
| replacer: (input: any, context: any) => any, | ||
| context?: any, | ||
| ) { | ||
| // If the current input is an IFluidHandle instance, replace this leaf in the object graph with | ||
| // the handle's serialized from. | ||
| // Note: Caller is responsible for ensuring that `input` is defined / non-null. | ||
| // (Required for Object.keys() below.) | ||
| // Note: Caller is responsible for ensuring that `input` is a non-null object. | ||
| const handle = input.IFluidHandle; | ||
| if (handle !== undefined) { | ||
| return this.serializeHandle(handle, bind); | ||
| // Execute the `replace` on the current input. Note that Caller is responsible for ensuring that `input` | ||
| // is a non-null object. | ||
| const maybeReplaced = replacer(input, context); | ||
| // If the replacer made a substitution there is no need to decscend further. IFluidHandles are always | ||
| // leaves in the object graph. | ||
| if (maybeReplaced !== input) { | ||
| return maybeReplaced; | ||
| } | ||
| // Otherwise descend into the object graph looking for IFluidHandle instances. | ||
| // eslint-disable-next-line @typescript-eslint/ban-types | ||
@@ -105,3 +145,3 @@ let clone: object | undefined; | ||
| // lead to a later error when attempting to stringify(). | ||
| const replaced = this.recursivelyReplaceHandles(value, bind); | ||
| const replaced = this.recursivelyReplace(value, replacer, context); | ||
@@ -123,3 +163,2 @@ // If the `replaced` object is different than the original `value` then the subgraph contained one | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
| return clone ?? input; | ||
@@ -126,0 +165,0 @@ } |
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
651908
2.05%7149
2.01%10
-23.08%+ Added
+ Added
+ Added
- Removed
- Removed
- Removed