@fluidframework/core-interfaces 2.41.0 → 2.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/exposedInternalUtilityTypes.d.ts +56 -4
- package/dist/exposedInternalUtilityTypes.d.ts.map +1 -1
- package/dist/exposedInternalUtilityTypes.js.map +1 -1
- package/dist/exposedUtilityTypes.d.ts +1 -0
- package/dist/exposedUtilityTypes.d.ts.map +1 -1
- package/dist/exposedUtilityTypes.js.map +1 -1
- package/dist/internal.d.ts +10 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js.map +1 -1
- package/dist/jsonSerializable.d.ts +2 -2
- package/dist/jsonSerializable.js.map +1 -1
- package/dist/jsonUtils.d.ts +70 -0
- package/dist/jsonUtils.d.ts.map +1 -0
- package/dist/jsonUtils.js +7 -0
- package/dist/jsonUtils.js.map +1 -0
- package/dist/opaqueJson.d.ts +60 -0
- package/dist/opaqueJson.d.ts.map +1 -0
- package/dist/opaqueJson.js +8 -0
- package/dist/opaqueJson.js.map +1 -0
- package/lib/exposedInternalUtilityTypes.d.ts +56 -4
- package/lib/exposedInternalUtilityTypes.d.ts.map +1 -1
- package/lib/exposedInternalUtilityTypes.js.map +1 -1
- package/lib/exposedUtilityTypes.d.ts +1 -0
- package/lib/exposedUtilityTypes.d.ts.map +1 -1
- package/lib/exposedUtilityTypes.js.map +1 -1
- package/lib/internal.d.ts +10 -0
- package/lib/internal.d.ts.map +1 -1
- package/lib/internal.js.map +1 -1
- package/lib/jsonSerializable.d.ts +2 -2
- package/lib/jsonSerializable.js.map +1 -1
- package/lib/jsonUtils.d.ts +70 -0
- package/lib/jsonUtils.d.ts.map +1 -0
- package/lib/jsonUtils.js +6 -0
- package/lib/jsonUtils.js.map +1 -0
- package/lib/opaqueJson.d.ts +60 -0
- package/lib/opaqueJson.d.ts.map +1 -0
- package/lib/opaqueJson.js +6 -0
- package/lib/opaqueJson.js.map +1 -0
- package/package.json +2 -2
- package/src/exposedInternalUtilityTypes.ts +186 -80
- package/src/exposedUtilityTypes.ts +1 -0
- package/src/internal.ts +24 -0
- package/src/jsonSerializable.ts +2 -2
- package/src/jsonUtils.ts +90 -0
- package/src/opaqueJson.ts +87 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { BrandedType } from "./brandedType.js";
|
|
6
|
+
/**
|
|
7
|
+
* Placeholder for value that is known to be JSON because it has been
|
|
8
|
+
* deserialized (`T` filtered through {@link JsonDeserialized} as out value).
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Usage:
|
|
12
|
+
*
|
|
13
|
+
* - Cast to with `as unknown as OpaqueJsonDeserialized<T>` when value `T`
|
|
14
|
+
* has been filtered through {@link JsonDeserialized}.
|
|
15
|
+
*
|
|
16
|
+
* - Cast from with `as unknown as JsonDeserialized<T>` when "instance" will
|
|
17
|
+
* be read.
|
|
18
|
+
*
|
|
19
|
+
* @sealed
|
|
20
|
+
* @beta
|
|
21
|
+
*/
|
|
22
|
+
export declare class OpaqueJsonDeserialized<T, in out Option_AllowExactly extends unknown[] = [], out Option_AllowExtensionOf = never> extends BrandedType<"JsonDeserialized"> {
|
|
23
|
+
protected readonly JsonDeserialized: {
|
|
24
|
+
Type: T;
|
|
25
|
+
Options: {
|
|
26
|
+
AllowExactly: Option_AllowExactly;
|
|
27
|
+
AllowExtensionOf: Option_AllowExtensionOf;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
protected readonly Option_AllowExactly_Invariance: (Option_AllowExactly: Option_AllowExactly) => void;
|
|
31
|
+
private constructor();
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Placeholder for value that is known to be JSON because it will have been
|
|
35
|
+
* serialized checked (`T` filtered through {@link JsonSerializable} before "created").
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* Usage:
|
|
39
|
+
*
|
|
40
|
+
* - Cast to with `as unknown as OpaqueJsonSerializable<T>` when value `T`
|
|
41
|
+
* has been filtered through {@link JsonSerializable}.
|
|
42
|
+
*
|
|
43
|
+
* - Cast from with `as unknown as JsonSerializable<T>` or `as unknown as T`
|
|
44
|
+
* when "instance" will be forwarded along.
|
|
45
|
+
*
|
|
46
|
+
* @sealed
|
|
47
|
+
* @beta
|
|
48
|
+
*/
|
|
49
|
+
export declare class OpaqueJsonSerializable<T, in out Option_AllowExactly extends unknown[] = [], out Option_AllowExtensionOf = never> extends BrandedType<"JsonSerializable"> {
|
|
50
|
+
protected readonly JsonSerializable: {
|
|
51
|
+
Type: T;
|
|
52
|
+
Options: {
|
|
53
|
+
AllowExactly: Option_AllowExactly;
|
|
54
|
+
AllowExtensionOf: Option_AllowExtensionOf;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
protected readonly Option_AllowExactly_Invariance: (Option_AllowExactly: Option_AllowExactly) => void;
|
|
58
|
+
private constructor();
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=opaqueJson.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opaqueJson.d.ts","sourceRoot":"","sources":["../src/opaqueJson.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,OAAO,sBAAsB,CAC1C,CAAC,EAMD,EAAE,CAAC,GAAG,CAAC,mBAAmB,SAAS,OAAO,EAAE,GAAG,EAAE,EACjD,GAAG,CAAC,uBAAuB,GAAG,KAAK,CAClC,SAAQ,WAAW,CAAC,kBAAkB,CAAC;IACxC,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE;QACpC,IAAI,EAAE,CAAC,CAAC;QACR,OAAO,EAAE;YACR,YAAY,EAAE,mBAAmB,CAAC;YAClC,gBAAgB,EAAE,uBAAuB,CAAC;SAC1C,CAAC;KACF,CAAC;IAEF,SAAS,CAAC,QAAQ,CAAC,8BAA8B,EAAE,CAClD,mBAAmB,EAAE,mBAAmB,KACpC,IAAI,CAAC;IACV,OAAO;CACP;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,OAAO,sBAAsB,CAC1C,CAAC,EAMD,EAAE,CAAC,GAAG,CAAC,mBAAmB,SAAS,OAAO,EAAE,GAAG,EAAE,EACjD,GAAG,CAAC,uBAAuB,GAAG,KAAK,CAElC,SAAQ,WAAW,CAAC,kBAAkB,CAAC;IACxC,SAAS,CAAC,QAAQ,CAAC,gBAAgB,EAAE;QACpC,IAAI,EAAE,CAAC,CAAC;QACR,OAAO,EAAE;YACR,YAAY,EAAE,mBAAmB,CAAC;YAClC,gBAAgB,EAAE,uBAAuB,CAAC;SAC1C,CAAC;KACF,CAAC;IAEF,SAAS,CAAC,QAAQ,CAAC,8BAA8B,EAAE,CAClD,mBAAmB,EAAE,mBAAmB,KACpC,IAAI,CAAC;IACV,OAAO;CACP"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opaqueJson.js","sourceRoot":"","sources":["../src/opaqueJson.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { BrandedType } from \"./brandedType.js\";\n\n/**\n * Placeholder for value that is known to be JSON because it has been\n * deserialized (`T` filtered through {@link JsonDeserialized} as out value).\n *\n * @remarks\n * Usage:\n *\n * - Cast to with `as unknown as OpaqueJsonDeserialized<T>` when value `T`\n * has been filtered through {@link JsonDeserialized}.\n *\n * - Cast from with `as unknown as JsonDeserialized<T>` when \"instance\" will\n * be read.\n *\n * @sealed\n * @beta\n */\nexport declare class OpaqueJsonDeserialized<\n\tT,\n\t// These options are split from typical `JsonDeserializedOptions` as this type\n\t// requires correct variance per the two options and AllowExactly has special\n\t// variance and must be treated as invariant. In actuality, each member of the\n\t// AllowExactly tuple is invariant, but tuple as a set is covariant. This is not\n\t// expressible in TypeScript.\n\tin out Option_AllowExactly extends unknown[] = [],\n\tout Option_AllowExtensionOf = never,\n> extends BrandedType<\"JsonDeserialized\"> {\n\tprotected readonly JsonDeserialized: {\n\t\tType: T;\n\t\tOptions: {\n\t\t\tAllowExactly: Option_AllowExactly;\n\t\t\tAllowExtensionOf: Option_AllowExtensionOf;\n\t\t};\n\t};\n\t// Option_AllowExactly is covariant from above. This removes covariance, leaving only invariance.\n\tprotected readonly Option_AllowExactly_Invariance: (\n\t\tOption_AllowExactly: Option_AllowExactly,\n\t) => void;\n\tprivate constructor();\n}\n\n/**\n * Placeholder for value that is known to be JSON because it will have been\n * serialized checked (`T` filtered through {@link JsonSerializable} before \"created\").\n *\n * @remarks\n * Usage:\n *\n * - Cast to with `as unknown as OpaqueJsonSerializable<T>` when value `T`\n * has been filtered through {@link JsonSerializable}.\n *\n * - Cast from with `as unknown as JsonSerializable<T>` or `as unknown as T`\n * when \"instance\" will be forwarded along.\n *\n * @sealed\n * @beta\n */\nexport declare class OpaqueJsonSerializable<\n\tT,\n\t// These options are split from typical `JsonSerializableOptions` as this type\n\t// requires correct variance per the two options and AllowExactly has special\n\t// variance and must be treated as invariant. In actuality, each member of the\n\t// AllowExactly tuple is invariant, but tuple as a set is covariant. This is not\n\t// expressible in TypeScript.\n\tin out Option_AllowExactly extends unknown[] = [],\n\tout Option_AllowExtensionOf = never,\n\t// JsonSerializableOptions.IgnoreInaccessibleMembers is ignored\n> extends BrandedType<\"JsonSerializable\"> {\n\tprotected readonly JsonSerializable: {\n\t\tType: T;\n\t\tOptions: {\n\t\t\tAllowExactly: Option_AllowExactly;\n\t\t\tAllowExtensionOf: Option_AllowExtensionOf;\n\t\t};\n\t};\n\t// Option_AllowExactly is covariant from above. This removes covariance, leaving only invariance.\n\tprotected readonly Option_AllowExactly_Invariance: (\n\t\tOption_AllowExactly: Option_AllowExactly,\n\t) => void;\n\tprivate constructor();\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/core-interfaces",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.42.0",
|
|
4
4
|
"description": "Fluid object interfaces",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"@fluid-tools/build-cli": "^0.55.0",
|
|
77
77
|
"@fluidframework/build-common": "^2.0.3",
|
|
78
78
|
"@fluidframework/build-tools": "^0.55.0",
|
|
79
|
-
"@fluidframework/core-interfaces-previous": "npm:@fluidframework/core-interfaces@2.
|
|
79
|
+
"@fluidframework/core-interfaces-previous": "npm:@fluidframework/core-interfaces@2.41.0",
|
|
80
80
|
"@fluidframework/eslint-config-fluid": "^5.7.4",
|
|
81
81
|
"@microsoft/api-extractor": "7.52.8",
|
|
82
82
|
"@types/mocha": "^10.0.10",
|
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
SerializationErrorPerUndefinedArrayElement,
|
|
13
13
|
} from "./jsonSerializationErrors.js";
|
|
14
14
|
import type { JsonTypeWith, NonNullJsonObjectWith, ReadonlyJsonTypeWith } from "./jsonType.js";
|
|
15
|
+
import type { OpaqueJsonDeserialized, OpaqueJsonSerializable } from "./opaqueJson.js";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Unique symbol for recursion meta-typing.
|
|
@@ -557,6 +558,20 @@ export namespace InternalUtilityTypes {
|
|
|
557
558
|
}
|
|
558
559
|
: T;
|
|
559
560
|
|
|
561
|
+
/**
|
|
562
|
+
* Convenience constraint for any Opaque Json type.
|
|
563
|
+
*
|
|
564
|
+
* @remarks
|
|
565
|
+
* Use in extends check: `T extends AnyOpaqueJsonType`
|
|
566
|
+
*
|
|
567
|
+
* @system
|
|
568
|
+
*/
|
|
569
|
+
export type AnyOpaqueJsonType =
|
|
570
|
+
/* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */
|
|
571
|
+
| OpaqueJsonSerializable<unknown, any, unknown>
|
|
572
|
+
| OpaqueJsonDeserialized<unknown, any, unknown>;
|
|
573
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
574
|
+
|
|
560
575
|
/**
|
|
561
576
|
* Extracts Function portion from an intersection (&) type returning
|
|
562
577
|
* the extracted portion in the `function` property or `unknown` if
|
|
@@ -775,15 +790,23 @@ export namespace InternalUtilityTypes {
|
|
|
775
790
|
AllowExtensionOf: Options extends { AllowExtensionOf: unknown }
|
|
776
791
|
? Options["AllowExtensionOf"]
|
|
777
792
|
: never;
|
|
778
|
-
//
|
|
779
|
-
// to make JsonTypeWith show explicitly in results for
|
|
780
|
-
// than either the helper type name or a partially unrolled version.
|
|
781
|
-
DegenerateSubstitute:
|
|
782
|
-
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
793
|
+
// The Substitute type could be extracted to helper type, but is kept explicit here
|
|
794
|
+
// to make JsonTypeWith and OpaqueJsonSerializable show explicitly in results for
|
|
795
|
+
// users, rather than either the helper type name or a partially unrolled version.
|
|
796
|
+
DegenerateSubstitute:
|
|
797
|
+
| JsonTypeWith<
|
|
798
|
+
| (Options extends { AllowExactly: unknown[] }
|
|
799
|
+
? TupleToUnion<Options["AllowExactly"]>
|
|
800
|
+
: never)
|
|
801
|
+
| (Options extends { AllowExtensionOf: unknown }
|
|
802
|
+
? Options["AllowExtensionOf"]
|
|
803
|
+
: never)
|
|
804
|
+
>
|
|
805
|
+
| OpaqueJsonSerializable<
|
|
806
|
+
unknown,
|
|
807
|
+
Options extends { AllowExactly: unknown[] } ? Options["AllowExactly"] : [],
|
|
808
|
+
Options extends { AllowExtensionOf: unknown } ? Options["AllowExtensionOf"] : never
|
|
809
|
+
>;
|
|
787
810
|
} extends infer Controls
|
|
788
811
|
? /* Controls should always satisfy FilterControlsWithSubstitution, but Typescript wants a check */
|
|
789
812
|
Controls extends FilterControlsWithSubstitution
|
|
@@ -796,8 +819,14 @@ export namespace InternalUtilityTypes {
|
|
|
796
819
|
T,
|
|
797
820
|
{
|
|
798
821
|
AllowExactly: Controls["AllowExactly"];
|
|
799
|
-
|
|
800
|
-
|
|
822
|
+
AllowExtensionOf:
|
|
823
|
+
| Controls["AllowExtensionOf"]
|
|
824
|
+
// Add in primitives that may be branded to ignore intersection classes
|
|
825
|
+
| boolean
|
|
826
|
+
| number
|
|
827
|
+
| string
|
|
828
|
+
// Add in Opaque Json types
|
|
829
|
+
| AnyOpaqueJsonType;
|
|
801
830
|
DegenerateSubstitute: Controls["DegenerateSubstitute"];
|
|
802
831
|
},
|
|
803
832
|
"found non-publics",
|
|
@@ -825,6 +854,47 @@ export namespace InternalUtilityTypes {
|
|
|
825
854
|
: never /* FilterControlsWithSubstitution assert else; should never be reached */
|
|
826
855
|
: never /* unreachable else for infer */;
|
|
827
856
|
|
|
857
|
+
/**
|
|
858
|
+
* Handle Opaque Json types for {@link JsonSerializable}.
|
|
859
|
+
*
|
|
860
|
+
* @remarks
|
|
861
|
+
* {@link OpaqueJsonSerializable} and {@link OpaqueJsonDeserialized} instances
|
|
862
|
+
* are limited to `Controls` given context supports.
|
|
863
|
+
* `T` from the original Opaque type is preserved. In the case that this now
|
|
864
|
+
* produces an improper type such as a `bigint` being let through that is no
|
|
865
|
+
* longer supported, then the variance of `Controls` is expected to raise
|
|
866
|
+
* the incompatibility error.
|
|
867
|
+
*
|
|
868
|
+
* @privateRemarks
|
|
869
|
+
* Additional intersections beyond {@link OpaqueJsonSerializable},
|
|
870
|
+
* {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are
|
|
871
|
+
* not correctly filtered as need is not expected.
|
|
872
|
+
*
|
|
873
|
+
* @system
|
|
874
|
+
*/
|
|
875
|
+
export type JsonSerializableOpaqueAllowances<
|
|
876
|
+
T extends AnyOpaqueJsonType,
|
|
877
|
+
Controls extends FilterControlsWithSubstitution,
|
|
878
|
+
> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */
|
|
879
|
+
/* infer underlying data type */ T extends
|
|
880
|
+
| OpaqueJsonSerializable<infer TData, any, unknown>
|
|
881
|
+
| OpaqueJsonDeserialized<infer TData, any, unknown>
|
|
882
|
+
? T extends OpaqueJsonSerializable<TData, any, unknown> &
|
|
883
|
+
OpaqueJsonDeserialized<TData, any, unknown>
|
|
884
|
+
? OpaqueJsonSerializable<TData, Controls["AllowExactly"], Controls["AllowExtensionOf"]> &
|
|
885
|
+
OpaqueJsonDeserialized<TData, Controls["AllowExactly"], Controls["AllowExtensionOf"]>
|
|
886
|
+
: T extends OpaqueJsonSerializable<TData, any, unknown>
|
|
887
|
+
? OpaqueJsonSerializable<TData, Controls["AllowExactly"], Controls["AllowExtensionOf"]>
|
|
888
|
+
: T extends OpaqueJsonDeserialized<TData, any, unknown>
|
|
889
|
+
? OpaqueJsonDeserialized<
|
|
890
|
+
TData,
|
|
891
|
+
Controls["AllowExactly"],
|
|
892
|
+
Controls["AllowExtensionOf"]
|
|
893
|
+
>
|
|
894
|
+
: "internal error: failed to determine Opaque Json type"
|
|
895
|
+
: never;
|
|
896
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
897
|
+
|
|
828
898
|
/**
|
|
829
899
|
* Essentially a check for a template literal that has $\{string\} or
|
|
830
900
|
* $\{number\} in the pattern. Just `string` and/or `number` also match.
|
|
@@ -933,45 +1003,50 @@ export namespace InternalUtilityTypes {
|
|
|
933
1003
|
>
|
|
934
1004
|
: /* test for enum like types */ IfEnumLike<T> extends never
|
|
935
1005
|
? /* enum or similar simple type (return as-is) => */ T
|
|
936
|
-
: /*
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1006
|
+
: /* test for Opaque Json types */ T extends AnyOpaqueJsonType
|
|
1007
|
+
? /* Opaque Json type => */ JsonSerializableOpaqueAllowances<
|
|
1008
|
+
T,
|
|
1009
|
+
Controls
|
|
1010
|
+
>
|
|
1011
|
+
: /* property bag => */ FlattenIntersection<
|
|
1012
|
+
{
|
|
1013
|
+
/* required properties are recursed and may not have undefined values. */
|
|
1014
|
+
[K in keyof T as RequiredNonSymbolKeysOf<
|
|
1015
|
+
T,
|
|
1016
|
+
K
|
|
1017
|
+
>]-?: IfPossiblyUndefinedProperty<
|
|
1018
|
+
K,
|
|
1019
|
+
T[K],
|
|
1020
|
+
{
|
|
1021
|
+
IfPossiblyUndefined: {
|
|
1022
|
+
["error required property may not allow `undefined` value"]: never;
|
|
1023
|
+
};
|
|
1024
|
+
IfUnknownNonIndexed: {
|
|
1025
|
+
["error required property may not allow `unknown` value"]: never;
|
|
1026
|
+
};
|
|
1027
|
+
Otherwise: JsonSerializableFilter<
|
|
1028
|
+
T[K],
|
|
1029
|
+
Controls,
|
|
1030
|
+
[TNextAncestor, ...TAncestorTypes]
|
|
1031
|
+
>;
|
|
1032
|
+
}
|
|
1033
|
+
>;
|
|
1034
|
+
} & {
|
|
1035
|
+
/* optional properties are recursed and, when exactOptionalPropertyTypes is
|
|
961
1036
|
false, are allowed to preserve undefined value type. */
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1037
|
+
[K in keyof T as OptionalNonSymbolKeysOf<
|
|
1038
|
+
T,
|
|
1039
|
+
K
|
|
1040
|
+
>]?: JsonSerializableFilter<
|
|
1041
|
+
T[K],
|
|
1042
|
+
Controls,
|
|
1043
|
+
[TNextAncestor, ...TAncestorTypes]
|
|
1044
|
+
>;
|
|
1045
|
+
} & {
|
|
1046
|
+
/* symbol properties are rejected */
|
|
1047
|
+
[K in keyof T & symbol]: never;
|
|
1048
|
+
}
|
|
1049
|
+
>
|
|
975
1050
|
: /* not an object => */ never
|
|
976
1051
|
: /* function => */ never;
|
|
977
1052
|
|
|
@@ -1015,7 +1090,7 @@ export namespace InternalUtilityTypes {
|
|
|
1015
1090
|
AllowExtensionOf: Options extends { AllowExtensionOf: unknown }
|
|
1016
1091
|
? Options["AllowExtensionOf"]
|
|
1017
1092
|
: never;
|
|
1018
|
-
//
|
|
1093
|
+
// The Substitute types could be extracted to helper type, but are kept explicit here
|
|
1019
1094
|
// to make JsonTypeWith/NonNullJsonObjectWith show explicitly in results for users, rather
|
|
1020
1095
|
// than either the helper type name or a partially unrolled version.
|
|
1021
1096
|
DegenerateSubstitute: JsonTypeWith<
|
|
@@ -1109,6 +1184,35 @@ export namespace InternalUtilityTypes {
|
|
|
1109
1184
|
: Controls["DegenerateSubstitute"]
|
|
1110
1185
|
: JsonDeserializedFilter<T, Controls, RecurseLimit, TAncestorTypes | T>;
|
|
1111
1186
|
|
|
1187
|
+
/**
|
|
1188
|
+
* Handle Opaque Json types for {@link JsonDeserialized}.
|
|
1189
|
+
*
|
|
1190
|
+
* @remarks
|
|
1191
|
+
* {@link OpaqueJsonSerializable} instances are converted to {@link OpaqueJsonDeserialized}.
|
|
1192
|
+
* The `AllowExactly` and `AllowExtensionOf` properties are set to match the given `Controls`.
|
|
1193
|
+
* The data type is kept exactly as-is to avoid processing in generic contexts that can't
|
|
1194
|
+
* produce a meaningful result. The data type should always be filtered through
|
|
1195
|
+
* {@link JsonDeserialized} when {@link OpaqueJsonDeserialized} is cracked open. So, really
|
|
1196
|
+
* the filtering is just deferred.
|
|
1197
|
+
*
|
|
1198
|
+
* @privateRemarks
|
|
1199
|
+
* Additional intersections beyond {@link OpaqueJsonSerializable},
|
|
1200
|
+
* {@link OpaqueJsonDeserialized}, or intersected matching opaque pair are
|
|
1201
|
+
* not correctly filtered as need is not expected.
|
|
1202
|
+
*
|
|
1203
|
+
* @system
|
|
1204
|
+
*/
|
|
1205
|
+
export type JsonDeserializedOpaqueConversion<
|
|
1206
|
+
T extends AnyOpaqueJsonType,
|
|
1207
|
+
Controls extends FilterControls,
|
|
1208
|
+
> = /* eslint-disable @typescript-eslint/no-explicit-any -- must use `any` for invariant constraint override */
|
|
1209
|
+
T extends
|
|
1210
|
+
| OpaqueJsonSerializable<infer TData, any, unknown>
|
|
1211
|
+
| OpaqueJsonDeserialized<infer TData, any, unknown>
|
|
1212
|
+
? OpaqueJsonDeserialized<TData, Controls["AllowExactly"], Controls["AllowExtensionOf"]>
|
|
1213
|
+
: "internal error: failed to determine Opaque Json type";
|
|
1214
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
1215
|
+
|
|
1112
1216
|
/**
|
|
1113
1217
|
* Core implementation of {@link JsonDeserialized}.
|
|
1114
1218
|
*
|
|
@@ -1157,36 +1261,38 @@ export namespace InternalUtilityTypes {
|
|
|
1157
1261
|
? /* `object` => */ Controls["DegenerateNonNullObjectSubstitute"]
|
|
1158
1262
|
: /* test for enum like types */ IfEnumLike<T> extends never
|
|
1159
1263
|
? /* enum or similar simple type (return as-is) => */ T
|
|
1160
|
-
: /*
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
/* properties with
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1264
|
+
: /* test for matching Opaque Json types */ T extends AnyOpaqueJsonType
|
|
1265
|
+
? /* Opaque Json type => */ JsonDeserializedOpaqueConversion<T, Controls>
|
|
1266
|
+
: /* property bag => */ FlattenIntersection<
|
|
1267
|
+
/* properties with symbol keys or wholly unsupported values are removed */
|
|
1268
|
+
{
|
|
1269
|
+
/* properties with defined values are recursed */
|
|
1270
|
+
[K in keyof T as NonSymbolWithDeserializablePropertyOf<
|
|
1271
|
+
T,
|
|
1272
|
+
Controls["AllowExactly"],
|
|
1273
|
+
Controls["AllowExtensionOf"],
|
|
1274
|
+
K
|
|
1275
|
+
>]: JsonDeserializedRecursion<
|
|
1276
|
+
T[K],
|
|
1277
|
+
Controls,
|
|
1278
|
+
RecurseLimit,
|
|
1279
|
+
TAncestorTypes
|
|
1280
|
+
>;
|
|
1281
|
+
} & {
|
|
1282
|
+
/* properties that may have undefined values are optional */
|
|
1283
|
+
[K in keyof T as NonSymbolWithPossiblyDeserializablePropertyOf<
|
|
1284
|
+
T,
|
|
1285
|
+
Controls["AllowExactly"],
|
|
1286
|
+
Controls["AllowExtensionOf"],
|
|
1287
|
+
K
|
|
1288
|
+
>]?: JsonDeserializedRecursion<
|
|
1289
|
+
T[K],
|
|
1290
|
+
Controls,
|
|
1291
|
+
RecurseLimit,
|
|
1292
|
+
TAncestorTypes
|
|
1293
|
+
>;
|
|
1294
|
+
}
|
|
1295
|
+
>
|
|
1190
1296
|
: /* not an object => */ never;
|
|
1191
1297
|
|
|
1192
1298
|
// #endregion
|
|
@@ -21,6 +21,7 @@ export type {
|
|
|
21
21
|
NonNullJsonObjectWith,
|
|
22
22
|
ReadonlyJsonTypeWith,
|
|
23
23
|
} from "./jsonType.js";
|
|
24
|
+
export type { OpaqueJsonDeserialized, OpaqueJsonSerializable } from "./opaqueJson.js";
|
|
24
25
|
export type { ShallowReadonly } from "./shallowReadonly.js";
|
|
25
26
|
|
|
26
27
|
export type {
|
package/src/internal.ts
CHANGED
|
@@ -10,6 +10,8 @@ export * from "./index.js";
|
|
|
10
10
|
// index.js is listed as the runtime file. This is done so that all imports are
|
|
11
11
|
// using the same outer runtime file. (Could be changed if needed.)
|
|
12
12
|
|
|
13
|
+
export type { JsonTypeToOpaqueJson, OpaqueJsonToJsonType } from "./jsonUtils.js";
|
|
14
|
+
|
|
13
15
|
// Export set of utility types re-tagged as internal for FF client convenience.
|
|
14
16
|
// These types are not intended for direct use by customers and api-extractor will
|
|
15
17
|
// flag misuse. If an externally visible version of these types is needed, import
|
|
@@ -28,6 +30,10 @@ import type {
|
|
|
28
30
|
JsonTypeWith as ExposedJsonTypeWith,
|
|
29
31
|
ReadonlyNonNullJsonObjectWith as ExposedReadonlyNonNullJsonObjectWith,
|
|
30
32
|
} from "./jsonType.js";
|
|
33
|
+
import type {
|
|
34
|
+
OpaqueJsonDeserialized as ExposedOpaqueJsonDeserialized,
|
|
35
|
+
OpaqueJsonSerializable as ExposedOpaqueJsonSerializable,
|
|
36
|
+
} from "./opaqueJson.js";
|
|
31
37
|
|
|
32
38
|
// Note: There are no docs for these re-exports. `@inheritdoc` cannot be used as:
|
|
33
39
|
// 1. api-extractor does not support renames.
|
|
@@ -71,6 +77,24 @@ export type JsonTypeWith<T> = ExposedJsonTypeWith<T>;
|
|
|
71
77
|
*/
|
|
72
78
|
export type ReadonlyNonNullJsonObjectWith<T> = ExposedReadonlyNonNullJsonObjectWith<T>;
|
|
73
79
|
|
|
80
|
+
/**
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
export type OpaqueJsonDeserialized<
|
|
84
|
+
T,
|
|
85
|
+
Option_AllowExactly extends unknown[] = [],
|
|
86
|
+
Option_AllowExtensionOf = never,
|
|
87
|
+
> = ExposedOpaqueJsonDeserialized<T, Option_AllowExactly, Option_AllowExtensionOf>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
export type OpaqueJsonSerializable<
|
|
93
|
+
T,
|
|
94
|
+
Option_AllowExactly extends unknown[] = [],
|
|
95
|
+
Option_AllowExtensionOf = never,
|
|
96
|
+
> = ExposedOpaqueJsonSerializable<T, Option_AllowExactly, Option_AllowExtensionOf>;
|
|
97
|
+
|
|
74
98
|
/**
|
|
75
99
|
* @internal
|
|
76
100
|
*/
|
package/src/jsonSerializable.ts
CHANGED
|
@@ -89,8 +89,8 @@ export interface JsonSerializableOptions {
|
|
|
89
89
|
* Also, `JsonSerializable<T>` does not prevent the construction of circular references.
|
|
90
90
|
*
|
|
91
91
|
* Specifying `JsonSerializable<unknown>` or `JsonSerializable<any>` yields a type
|
|
92
|
-
* alias for {@link JsonTypeWith}`<never>`
|
|
93
|
-
* safety is desired.
|
|
92
|
+
* alias for {@link JsonTypeWith}`<never>` | {@link OpaqueJsonSerializable}`<unknown>`
|
|
93
|
+
* and should not be used if precise type safety is desired.
|
|
94
94
|
*
|
|
95
95
|
* Class instances are indistinguishable from general objects by type checking
|
|
96
96
|
* unless they have non-public members.
|
package/src/jsonUtils.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { JsonDeserialized } from "./jsonDeserialized.js";
|
|
7
|
+
import type { JsonSerializable, JsonSerializableOptions } from "./jsonSerializable.js";
|
|
8
|
+
import type { OpaqueJsonDeserialized, OpaqueJsonSerializable } from "./opaqueJson.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Helper to return an Opaque Json type version of Json type
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* To use this helper, create a helper function that filters type `T` through at
|
|
15
|
+
* least {@link JsonSerializable} and optionally {@link JsonDeserialized}. Then
|
|
16
|
+
* cast value through `unknown as JsonTypeToOpaqueJson<T, Options>`, where
|
|
17
|
+
* `Options` reflects the serialization capabilities of that area.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* function castToOpaqueJson<T>(value: JsonSerializable<T>): JsonTypeToOpaqueJson<T> {
|
|
22
|
+
* return value as unknown as JsonTypeToOpaqueJson<T>;
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
export type JsonTypeToOpaqueJson<
|
|
29
|
+
T,
|
|
30
|
+
Options extends JsonSerializableOptions = {
|
|
31
|
+
AllowExactly: [];
|
|
32
|
+
AllowExtensionOf: never;
|
|
33
|
+
},
|
|
34
|
+
> = T extends JsonSerializable<T, Options> & JsonDeserialized<T, Options>
|
|
35
|
+
? OpaqueJsonSerializable<
|
|
36
|
+
T,
|
|
37
|
+
Options extends { AllowExactly: unknown[] } ? Options["AllowExactly"] : [],
|
|
38
|
+
Options extends { AllowExtensionOf: unknown } ? Options["AllowExtensionOf"] : never
|
|
39
|
+
> &
|
|
40
|
+
OpaqueJsonDeserialized<
|
|
41
|
+
T,
|
|
42
|
+
Options extends { AllowExactly: unknown[] } ? Options["AllowExactly"] : [],
|
|
43
|
+
Options extends { AllowExtensionOf: unknown } ? Options["AllowExtensionOf"] : never
|
|
44
|
+
>
|
|
45
|
+
: T extends JsonDeserialized<T, Options>
|
|
46
|
+
? OpaqueJsonDeserialized<
|
|
47
|
+
T,
|
|
48
|
+
Options extends { AllowExactly: unknown[] } ? Options["AllowExactly"] : [],
|
|
49
|
+
Options extends { AllowExtensionOf: unknown } ? Options["AllowExtensionOf"] : never
|
|
50
|
+
>
|
|
51
|
+
: T extends JsonSerializable<T, Options>
|
|
52
|
+
? OpaqueJsonSerializable<
|
|
53
|
+
T,
|
|
54
|
+
Options extends { AllowExactly: unknown[] } ? Options["AllowExactly"] : [],
|
|
55
|
+
Options extends { AllowExtensionOf: unknown } ? Options["AllowExtensionOf"] : never
|
|
56
|
+
>
|
|
57
|
+
: never;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Helper to extract Json type from an Opaque Json type
|
|
61
|
+
*
|
|
62
|
+
* @remarks
|
|
63
|
+
* This type only works with basic serialization capabilities (options).
|
|
64
|
+
* Attempts to make `Options` generic resulted in infinite recursion
|
|
65
|
+
* in TypeScript compiler that was not understood, so this type only
|
|
66
|
+
* supports TJson (value type) variance.
|
|
67
|
+
*
|
|
68
|
+
* To use this helper, create a helper function that accepts
|
|
69
|
+
* `OpaqueJsonSerializable<unknown> | OpaqueJsonDeserialized<unknown>`.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* function exposeFromOpaqueJson<TOpaque extends OpaqueJsonSerializable<unknown> | OpaqueJsonDeserialized<unknown>>(
|
|
74
|
+
* opaque: TOpaque,
|
|
75
|
+
* ): OpaqueJsonToJsonType<TOpaque> {
|
|
76
|
+
* return opaque as unknown as OpaqueJsonToJsonType<TOpaque>;
|
|
77
|
+
* }
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
export type OpaqueJsonToJsonType<
|
|
83
|
+
TOpaque extends OpaqueJsonSerializable<unknown> | OpaqueJsonDeserialized<unknown>,
|
|
84
|
+
> = TOpaque extends OpaqueJsonSerializable<infer TJson> & OpaqueJsonDeserialized<infer TJson>
|
|
85
|
+
? JsonSerializable<TJson> & JsonDeserialized<TJson>
|
|
86
|
+
: TOpaque extends OpaqueJsonDeserialized<infer TJson>
|
|
87
|
+
? JsonDeserialized<TJson>
|
|
88
|
+
: TOpaque extends OpaqueJsonSerializable<infer TJson>
|
|
89
|
+
? JsonSerializable<TJson>
|
|
90
|
+
: never;
|