@fluidframework/core-interfaces 2.32.0 → 2.33.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/api-report/core-interfaces.legacy.alpha.api.md +9 -9
  3. package/dist/deepReadonly.d.ts +56 -0
  4. package/dist/deepReadonly.d.ts.map +1 -0
  5. package/dist/deepReadonly.js +7 -0
  6. package/dist/deepReadonly.js.map +1 -0
  7. package/dist/exposedInternalUtilityTypes.d.ts +168 -3
  8. package/dist/exposedInternalUtilityTypes.d.ts.map +1 -1
  9. package/dist/exposedInternalUtilityTypes.js.map +1 -1
  10. package/dist/exposedUtilityTypes.d.ts +4 -2
  11. package/dist/exposedUtilityTypes.d.ts.map +1 -1
  12. package/dist/exposedUtilityTypes.js.map +1 -1
  13. package/dist/handles.d.ts +12 -0
  14. package/dist/handles.d.ts.map +1 -1
  15. package/dist/handles.js.map +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/internal.d.ts +10 -1
  20. package/dist/internal.d.ts.map +1 -1
  21. package/dist/internal.js.map +1 -1
  22. package/dist/jsonType.d.ts +28 -0
  23. package/dist/jsonType.d.ts.map +1 -1
  24. package/dist/jsonType.js.map +1 -1
  25. package/dist/shallowReadonly.d.ts +48 -0
  26. package/dist/shallowReadonly.d.ts.map +1 -0
  27. package/dist/shallowReadonly.js +7 -0
  28. package/dist/shallowReadonly.js.map +1 -0
  29. package/lib/deepReadonly.d.ts +56 -0
  30. package/lib/deepReadonly.d.ts.map +1 -0
  31. package/lib/deepReadonly.js +6 -0
  32. package/lib/deepReadonly.js.map +1 -0
  33. package/lib/exposedInternalUtilityTypes.d.ts +168 -3
  34. package/lib/exposedInternalUtilityTypes.d.ts.map +1 -1
  35. package/lib/exposedInternalUtilityTypes.js.map +1 -1
  36. package/lib/exposedUtilityTypes.d.ts +4 -2
  37. package/lib/exposedUtilityTypes.d.ts.map +1 -1
  38. package/lib/exposedUtilityTypes.js.map +1 -1
  39. package/lib/handles.d.ts +12 -0
  40. package/lib/handles.d.ts.map +1 -1
  41. package/lib/handles.js.map +1 -1
  42. package/lib/index.d.ts +1 -1
  43. package/lib/index.d.ts.map +1 -1
  44. package/lib/index.js.map +1 -1
  45. package/lib/internal.d.ts +10 -1
  46. package/lib/internal.d.ts.map +1 -1
  47. package/lib/internal.js.map +1 -1
  48. package/lib/jsonType.d.ts +28 -0
  49. package/lib/jsonType.d.ts.map +1 -1
  50. package/lib/jsonType.js.map +1 -1
  51. package/lib/shallowReadonly.d.ts +48 -0
  52. package/lib/shallowReadonly.d.ts.map +1 -0
  53. package/lib/shallowReadonly.js +6 -0
  54. package/lib/shallowReadonly.js.map +1 -0
  55. package/lib/tsdoc-metadata.json +1 -1
  56. package/package.json +3 -3
  57. package/src/deepReadonly.ts +76 -0
  58. package/src/exposedInternalUtilityTypes.ts +452 -5
  59. package/src/exposedUtilityTypes.ts +11 -2
  60. package/src/handles.ts +16 -0
  61. package/src/index.ts +1 -0
  62. package/src/internal.ts +15 -1
  63. package/src/jsonType.ts +36 -0
  64. package/src/shallowReadonly.ts +60 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/core-interfaces",
3
- "version": "2.32.0",
3
+ "version": "2.33.0",
4
4
  "description": "Fluid object interfaces",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -76,9 +76,9 @@
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.31.0",
79
+ "@fluidframework/core-interfaces-previous": "npm:@fluidframework/core-interfaces@2.32.0",
80
80
  "@fluidframework/eslint-config-fluid": "^5.7.3",
81
- "@microsoft/api-extractor": "7.50.1",
81
+ "@microsoft/api-extractor": "7.52.5",
82
82
  "@types/mocha": "^10.0.10",
83
83
  "@types/node": "^18.19.0",
84
84
  "c8": "^8.0.1",
@@ -0,0 +1,76 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import type {
7
+ DeepReadonlyRecursionLimit,
8
+ InternalUtilityTypes,
9
+ ReadonlySupportedGenerics,
10
+ } from "./exposedInternalUtilityTypes.js";
11
+
12
+ /**
13
+ * Default set of generic that {@link DeepReadonly} will apply deep immutability
14
+ * to generic types.
15
+ *
16
+ * @privateRemarks
17
+ * WeakRef should be added when lib is updated to ES2021 or later.
18
+ *
19
+ * @system
20
+ */
21
+ export type DeepReadonlySupportedGenericsDefault =
22
+ | Map<unknown, unknown>
23
+ | Promise<unknown>
24
+ | Set<unknown>
25
+ | WeakMap<object, unknown>
26
+ | WeakSet<object>;
27
+
28
+ /**
29
+ * Options for {@link DeepReadonly}.
30
+ *
31
+ * @beta
32
+ */
33
+ export interface DeepReadonlyOptions {
34
+ /**
35
+ * Union of Built-in and IFluidHandle whose generics will also be made deeply immutable.
36
+ *
37
+ * The default value is `Map` | `Promise` | `Set` | `WeakMap` | `WeakSet`.
38
+ */
39
+ DeepenedGenerics?: ReadonlySupportedGenerics;
40
+
41
+ /**
42
+ * Limit on processing recursive types.
43
+ *
44
+ * The default value is `"NoLimit"`.
45
+ */
46
+ RecurseLimit?: DeepReadonlyRecursionLimit;
47
+ }
48
+
49
+ /**
50
+ * Transforms type to a fully and deeply immutable type, with limitations.
51
+ *
52
+ * @remarks
53
+ * This utility type is similar to a recursive `Readonly<T>`, but also
54
+ * applies immutability to common generic types like `Map` and `Set`.
55
+ *
56
+ * Optionally, immutability can be applied to supported generics types. See
57
+ * {@link DeepReadonlySupportedGenericsDefault} for generics that have
58
+ * immutability applied to generic type by default.
59
+ *
60
+ * @beta
61
+ */
62
+ export type DeepReadonly<
63
+ T,
64
+ Options extends DeepReadonlyOptions = {
65
+ DeepenedGenerics: DeepReadonlySupportedGenericsDefault;
66
+ RecurseLimit: "NoLimit";
67
+ },
68
+ > = InternalUtilityTypes.DeepReadonlyImpl<
69
+ T,
70
+ Options extends { DeepenedGenerics: unknown }
71
+ ? Options["DeepenedGenerics"]
72
+ : DeepReadonlySupportedGenericsDefault,
73
+ Options extends { RecurseLimit: DeepReadonlyRecursionLimit }
74
+ ? Options["RecurseLimit"]
75
+ : "NoLimit"
76
+ >;
@@ -5,17 +5,51 @@
5
5
 
6
6
  /* eslint-disable @rushstack/no-new-null */
7
7
 
8
+ import type { ErasedType } from "./erasedType.js";
9
+ import type { IFluidHandle } from "./handles.js";
8
10
  import type {
9
11
  SerializationErrorPerNonPublicProperties,
10
12
  SerializationErrorPerUndefinedArrayElement,
11
13
  } from "./jsonSerializationErrors.js";
12
- import type { JsonTypeWith, NonNullJsonObjectWith } from "./jsonType.js";
14
+ import type { JsonTypeWith, NonNullJsonObjectWith, ReadonlyJsonTypeWith } from "./jsonType.js";
13
15
 
14
16
  /**
15
17
  * Unique symbol for recursion meta-typing.
16
18
  */
17
19
  const RecursionMarkerSymbol: unique symbol = Symbol("recursion here");
18
20
 
21
+ /**
22
+ * Union of types that {@link DeepReadonly} and {@link ShallowReadonly}
23
+ * recognize to generate immutable form and optionally can alter their
24
+ * type parameters.
25
+ *
26
+ * @privateRemarks
27
+ * WeakRef should be added when lib is updated to ES2021 or later.
28
+ *
29
+ * @beta
30
+ */
31
+ export type ReadonlySupportedGenerics =
32
+ | IFluidHandle
33
+ | Map<unknown, unknown>
34
+ | Promise<unknown>
35
+ | Set<unknown>
36
+ | WeakMap<object, unknown>
37
+ | WeakSet<object>;
38
+
39
+ /**
40
+ * Limit on processing recursive types.
41
+ * Use of `"NoLimit"` may result in error:
42
+ * "ts(2589): Type instantiation is excessively deep and possibly infinite".
43
+ * In such cases, use string literal with some prefix series of `+`
44
+ * characters. The length of `+` character sequence indicates the recursion
45
+ * depth limit when a recursive type is found. Use of `0` will stop applying
46
+ * `DeepReadonly` at the first point recursion is detected.
47
+ *
48
+ * @beta
49
+ * @system
50
+ */
51
+ export type DeepReadonlyRecursionLimit = "NoLimit" | 0 | `+${string}`;
52
+
19
53
  /**
20
54
  * Collection of utility types that are not intended to be used/imported
21
55
  * directly outside of this package.
@@ -936,8 +970,6 @@ export namespace InternalUtilityTypes {
936
970
 
937
971
  // #endregion
938
972
 
939
- // #region JsonDeserialized implementation
940
-
941
973
  /**
942
974
  * Sentinel type for use when marking points of recursion (in a recursive type).
943
975
  * Type is expected to be unique, though no lengths are taken to ensure that.
@@ -955,12 +987,14 @@ export namespace InternalUtilityTypes {
955
987
  */
956
988
  export type RecursionLimit = `+${string}` | 0;
957
989
 
990
+ // #region JsonDeserialized implementation
991
+
958
992
  /**
959
993
  * Outer implementation of {@link JsonDeserialized} handling meta cases
960
994
  * like recursive types.
961
995
  *
962
996
  * @privateRemarks
963
- * This utility is reentrant and will process a type `T` up to RecurseLimit.
997
+ * This utility is reentrant and will process a type `T` up to `RecurseLimit`.
964
998
  *
965
999
  * @system
966
1000
  */
@@ -1046,7 +1080,7 @@ export namespace InternalUtilityTypes {
1046
1080
  : never /* unreachable else for infer */;
1047
1081
 
1048
1082
  /**
1049
- * Recurses T applying {@link InternalUtilityTypes.JsonDeserializedFilter} up to RecurseLimit times.
1083
+ * Recurses `T` applying {@link InternalUtilityTypes.JsonDeserializedFilter} up to `RecurseLimit` times.
1050
1084
  *
1051
1085
  * @system
1052
1086
  */
@@ -1149,4 +1183,417 @@ export namespace InternalUtilityTypes {
1149
1183
  : /* not an object => */ never;
1150
1184
 
1151
1185
  // #endregion
1186
+
1187
+ // #region *Readonly implementations
1188
+
1189
+ /**
1190
+ * If `T` is a `Map<K,V>` or `ReadonlyMap<K,V>`, returns `ReadonlyMap` and,
1191
+ * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to
1192
+ * `K` and `V` generics. `Else` is returned if not a generic map.
1193
+ *
1194
+ * @system
1195
+ */
1196
+ export type DeepenReadonlyInMapIfEnabled<
1197
+ T,
1198
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1199
+ NoDepthOrRecurseLimit extends "Shallow" | DeepReadonlyRecursionLimit,
1200
+ Else,
1201
+ > = T extends ReadonlyMap<infer K, infer V>
1202
+ ? Map<K, V> extends DeepenedGenerics
1203
+ ? ReadonlyMap<
1204
+ ReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,
1205
+ ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>
1206
+ >
1207
+ : ReadonlyMap<K, V>
1208
+ : Else;
1209
+
1210
+ /**
1211
+ * If `T` is a `Set<TSet>` or `ReadonlySet<TSet>`, returns `ReadonlySet` and,
1212
+ * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to
1213
+ * `TSet` generic. `Else` is returned if not a generic set.
1214
+ *
1215
+ * @system
1216
+ */
1217
+ export type DeepenReadonlyInSetIfEnabled<
1218
+ T,
1219
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1220
+ NoDepthOrRecurseLimit extends "Shallow" | DeepReadonlyRecursionLimit,
1221
+ Else,
1222
+ > = T extends ReadonlySet<infer V>
1223
+ ? Set<V> extends DeepenedGenerics
1224
+ ? ReadonlySet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>
1225
+ : ReadonlySet<V>
1226
+ : Else;
1227
+
1228
+ /**
1229
+ * If `T` is a `IFluidHandle<THandle>` and if `T` extends `DeepenedGenerics`,
1230
+ * {@link DeepReadonly} is applied to `THandle` generic.
1231
+ * `Else` is returned if not an `IFluidHandle`.
1232
+ *
1233
+ * @system
1234
+ */
1235
+ export type DeepenReadonlyInFluidHandleIfEnabled<
1236
+ T,
1237
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1238
+ NoDepthOrRecurseLimit extends "Shallow" | DeepReadonlyRecursionLimit,
1239
+ Else,
1240
+ > = T extends Readonly<IFluidHandle<infer V>>
1241
+ ? IFluidHandle<V> extends DeepenedGenerics
1242
+ ? Readonly<IFluidHandle<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>>
1243
+ : Readonly<T>
1244
+ : Else;
1245
+
1246
+ /**
1247
+ * If `T` is a `Promise<TPromise>` and if `T` extends `DeepenedGenerics`,
1248
+ * {@link DeepReadonly} is applied to `TPromise` generic.
1249
+ * `Else` is returned if not a `Promise`.
1250
+ *
1251
+ * @system
1252
+ */
1253
+ export type DeepenReadonlyInPromiseIfEnabled<
1254
+ T,
1255
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1256
+ NoDepthOrRecurseLimit extends "Shallow" | DeepReadonlyRecursionLimit,
1257
+ Else,
1258
+ > = T extends Promise<infer V>
1259
+ ? Promise<V> extends DeepenedGenerics
1260
+ ? Promise<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>
1261
+ : T
1262
+ : Else;
1263
+
1264
+ /**
1265
+ * If `T` is a `WeakMap<K,V>`, returns immutable `WeakMap` and,
1266
+ * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to
1267
+ * `K` and `V` generics. `Else` is returned if not a generic map.
1268
+ *
1269
+ * @system
1270
+ */
1271
+ export type DeepenReadonlyInWeakMapIfEnabled<
1272
+ T,
1273
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1274
+ NoDepthOrRecurseLimit extends "Shallow" | DeepReadonlyRecursionLimit,
1275
+ Else,
1276
+ > = T extends Omit<WeakMap<infer K, infer V>, "delete" | "set">
1277
+ ? WeakMap<K, V> extends DeepenedGenerics
1278
+ ? Omit<
1279
+ WeakMap<
1280
+ ReadonlyImpl<K, DeepenedGenerics, NoDepthOrRecurseLimit>,
1281
+ ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>
1282
+ >,
1283
+ "delete" | "set"
1284
+ >
1285
+ : Omit<WeakMap<K, V>, "delete" | "set">
1286
+ : Else;
1287
+
1288
+ /**
1289
+ * If `T` is a `WeakSet<TSet>`, returns immutable `WeakSet` and,
1290
+ * if `T` extends `DeepenedGenerics`, {@link DeepReadonly} is applied to
1291
+ * `TSet` generic. `Else` is returned if not a generic weak set.
1292
+ *
1293
+ * @system
1294
+ */
1295
+ export type DeepenReadonlyInWeakSetIfEnabled<
1296
+ T,
1297
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1298
+ NoDepthOrRecurseLimit extends "Shallow" | DeepReadonlyRecursionLimit,
1299
+ Else,
1300
+ > = T extends Omit<WeakSet<infer V>, "add" | "delete">
1301
+ ? WeakSet<V> extends DeepenedGenerics
1302
+ ? Omit<
1303
+ WeakSet<ReadonlyImpl<V, DeepenedGenerics, NoDepthOrRecurseLimit>>,
1304
+ "add" | "delete"
1305
+ >
1306
+ : Omit<WeakSet<V>, "add" | "delete">
1307
+ : Else;
1308
+
1309
+ /**
1310
+ * If `T` is a {@link ReadonlySupportedGenerics}, `T` is returned as
1311
+ * its immutable version, and if `T` extends `DeepenedGenerics`,
1312
+ * {@link DeepReadonly} is applied to `T`s generics.
1313
+ *
1314
+ * @system
1315
+ */
1316
+ export type DeepenReadonlyInGenerics<
1317
+ T,
1318
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1319
+ NoDepthOrRecurseLimit extends "Shallow" | DeepReadonlyRecursionLimit,
1320
+ Else,
1321
+ > = DeepenReadonlyInMapIfEnabled<
1322
+ T,
1323
+ DeepenedGenerics,
1324
+ NoDepthOrRecurseLimit,
1325
+ DeepenReadonlyInSetIfEnabled<
1326
+ T,
1327
+ DeepenedGenerics,
1328
+ NoDepthOrRecurseLimit,
1329
+ DeepenReadonlyInWeakMapIfEnabled<
1330
+ T,
1331
+ DeepenedGenerics,
1332
+ NoDepthOrRecurseLimit,
1333
+ DeepenReadonlyInWeakSetIfEnabled<
1334
+ T,
1335
+ DeepenedGenerics,
1336
+ NoDepthOrRecurseLimit,
1337
+ DeepenReadonlyInPromiseIfEnabled<
1338
+ T,
1339
+ DeepenedGenerics,
1340
+ NoDepthOrRecurseLimit,
1341
+ DeepenReadonlyInFluidHandleIfEnabled<
1342
+ T,
1343
+ DeepenedGenerics,
1344
+ NoDepthOrRecurseLimit,
1345
+ Else
1346
+ >
1347
+ >
1348
+ >
1349
+ >
1350
+ >
1351
+ >;
1352
+
1353
+ /**
1354
+ * Returns an `ErasedType` or "branded" primitive type as-is, or `Else` if not.
1355
+ * @typeParam T - Type to test.
1356
+ * @typeParam Else - Type to return if not `ErasedType` or "branded" primitive.
1357
+ *
1358
+ * @system
1359
+ */
1360
+ export type PreserveErasedTypeOrBrandedPrimitive<
1361
+ T extends object,
1362
+ Else,
1363
+ > = /* Test for erased type */ T extends ErasedType<infer _>
1364
+ ? /* erased type => keep as-is */ T
1365
+ : /* Test for branded primitive */ T extends infer Brand &
1366
+ (boolean | number | string | symbol | bigint)
1367
+ ? // Should just return T here, but TypeScript appears to produce `never` when doing so.
1368
+ // Workaround by inferring the Primitive type and returning intersection with B.
1369
+ T extends Brand & infer Primitive
1370
+ ? /* [potentially] branded type => "as-is" */ Primitive & Brand
1371
+ : /* Should never be reached */ T
1372
+ : Else;
1373
+
1374
+ /**
1375
+ * De-multiplexing implementation of {@link DeepReadonly} and {@link ShallowReadonly}
1376
+ * selecting behavior based on `NoDepthOrRecurseLimit`.
1377
+ *
1378
+ * @privateRemarks
1379
+ * This utility is reentrant. Its importance is that other utilities common to
1380
+ * readonly transformation may use `NoDepthOrRecurseLimit` to return the the
1381
+ * same processing algorithm.
1382
+ *
1383
+ * @system
1384
+ */
1385
+ export type ReadonlyImpl<
1386
+ T,
1387
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1388
+ NoDepthOrRecurseLimit extends "Shallow" | DeepReadonlyRecursionLimit,
1389
+ > = /* test for no depth */ NoDepthOrRecurseLimit extends "Shallow"
1390
+ ? /* no depth => */ ShallowReadonlyImpl<T, DeepenedGenerics>
1391
+ : /* test for no limit */ NoDepthOrRecurseLimit extends "NoLimit"
1392
+ ? /* no limit => */ DeepReadonlyRecursingInfinitely<T, DeepenedGenerics>
1393
+ : /* limited */ DeepReadonlyLimitingRecursion<
1394
+ T,
1395
+ DeepenedGenerics,
1396
+ Extract<NoDepthOrRecurseLimit, RecursionLimit>
1397
+ >;
1398
+
1399
+ // #region ShallowReadonly implementation
1400
+
1401
+ /**
1402
+ * Outer implementation of {@link ShallowReadonly}.
1403
+ *
1404
+ * @privateRemarks
1405
+ * This utility can be reentrant when generics are deepened.
1406
+ *
1407
+ * @system
1408
+ */
1409
+ export type ShallowReadonlyImpl<
1410
+ T,
1411
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1412
+ > = T extends object
1413
+ ? /* object => */ FilterPreservingFunction<
1414
+ T,
1415
+ DeepenReadonlyInGenerics<
1416
+ T,
1417
+ DeepenedGenerics,
1418
+ "Shallow",
1419
+ PreserveErasedTypeOrBrandedPrimitive<T, /* basic type => */ Readonly<T>>
1420
+ >
1421
+ >
1422
+ : /* not an object => */ T;
1423
+
1424
+ // #endregion
1425
+
1426
+ /**
1427
+ * Outer implementation of {@link DeepReadonly}.
1428
+ *
1429
+ * @privateRemarks
1430
+ * This utility is reentrant and will process a type `T` up to `RecurseLimit`.
1431
+ *
1432
+ * @system
1433
+ */
1434
+ export type DeepReadonlyImpl<
1435
+ T,
1436
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1437
+ RecurseLimit extends DeepReadonlyRecursionLimit,
1438
+ > = ReadonlyImpl<T, DeepenedGenerics, RecurseLimit>;
1439
+
1440
+ // #region DeepReadonly infinite recursion implementation
1441
+
1442
+ /**
1443
+ * Simple implementation of {@link DeepReadonly} that may handle limited recursive types.
1444
+ * In unhandled cases, TypeScript will produce:
1445
+ * ts(2589): Type instantiation is excessively deep and possibly infinite.
1446
+ *
1447
+ * @system
1448
+ */
1449
+ export type DeepReadonlyRecursingInfinitely<
1450
+ T,
1451
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1452
+ > = T extends object
1453
+ ? /* object => */ FilterPreservingFunction<
1454
+ T,
1455
+ // test for array of known recursive type: JsonTypeWith
1456
+ T extends readonly ReadonlyJsonTypeWith<infer Alternates>[]
1457
+ ? // Make sure this is exactly that case (many arrays will extend JsonTypeWith)
1458
+ // Note that `true extends IfExactTypeInTuple` is used over
1459
+ // if-else form as the else branch would be evaluated as input to
1460
+ // `IfExactTypeInTuple` and that could lead to infinite recursion.
1461
+ true extends IfExactTypeInTuple<
1462
+ T,
1463
+ [JsonTypeWith<Alternates>[], readonly ReadonlyJsonTypeWith<Alternates>[]]
1464
+ >
1465
+ ? readonly ReadonlyJsonTypeWith<
1466
+ DeepReadonlyRecursingInfinitely<Alternates, DeepenedGenerics>
1467
+ >[]
1468
+ : {
1469
+ readonly [K in keyof T]: DeepReadonlyRecursingInfinitely<
1470
+ T[K],
1471
+ DeepenedGenerics
1472
+ >;
1473
+ }
1474
+ : /* not JSON array => */ DeepenReadonlyInGenerics<
1475
+ T,
1476
+ DeepenedGenerics,
1477
+ "NoLimit",
1478
+ PreserveErasedTypeOrBrandedPrimitive<
1479
+ T,
1480
+ /* basic type => */ {
1481
+ readonly [K in keyof T]: DeepReadonlyRecursingInfinitely<
1482
+ T[K],
1483
+ DeepenedGenerics
1484
+ >;
1485
+ }
1486
+ >
1487
+ >
1488
+ >
1489
+ : /* not an object => */ T;
1490
+
1491
+ // #endregion
1492
+ // #region DeepReadonly limited recursion implementation
1493
+
1494
+ /**
1495
+ * Core implementation of {@link DeepReadonly} handling meta cases
1496
+ * like recursive types a limited number of times.
1497
+ *
1498
+ * @privateRemarks
1499
+ * This utility is reentrant and will process a type `T` up to `NoDepthOrRecurseLimit`.
1500
+ *
1501
+ * @system
1502
+ */
1503
+ export type DeepReadonlyLimitingRecursion<
1504
+ T,
1505
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1506
+ NoDepthOrRecurseLimit extends RecursionLimit,
1507
+ > = /* infer non-recursive version of T */ ReplaceRecursionWithMarkerAndPreserveAllowances<
1508
+ T,
1509
+ RecursionMarker,
1510
+ { AllowExactly: []; AllowExtensionOf: never }
1511
+ > extends infer TNoRecursionAndOnlyPublics
1512
+ ? /* test for no change from altered type (excluding non-publics) */ IsSameType<
1513
+ TNoRecursionAndOnlyPublics,
1514
+ DeepReadonlyWorker<TNoRecursionAndOnlyPublics, DeepenedGenerics, 0>
1515
+ > extends true
1516
+ ? /* same (no filtering needed) => test for non-public properties (class instance type) */
1517
+ IfNonPublicProperties<
1518
+ T,
1519
+ // Note: no extra allowance is made here for possible branded
1520
+ // primitives as DeepReadonlyWorker will allow them as
1521
+ // extensions of the primitives. Should there need a need to
1522
+ // explicit allow them here, see JsonSerializableImpl's use.
1523
+ { AllowExactly: []; AllowExtensionOf: never },
1524
+ "found non-publics",
1525
+ "only publics"
1526
+ > extends "found non-publics"
1527
+ ? /* hidden props => apply filtering => */
1528
+ DeepReadonlyWorker<
1529
+ T,
1530
+ DeepenedGenerics,
1531
+ Extract<NoDepthOrRecurseLimit, RecursionLimit>
1532
+ >
1533
+ : /* no hidden properties => readonly T is just T */
1534
+ T
1535
+ : /* filtering is needed => */ DeepReadonlyWorker<
1536
+ T,
1537
+ DeepenedGenerics,
1538
+ Extract<NoDepthOrRecurseLimit, RecursionLimit>
1539
+ >
1540
+ : /* unreachable else for infer */ never;
1541
+
1542
+ /**
1543
+ * Recurses `T` applying {@link InternalUtilityTypes.DeepReadonlyWorker} up to `RecurseLimit` times.
1544
+ *
1545
+ * @system
1546
+ */
1547
+ export type DeepReadonlyRecursion<
1548
+ T,
1549
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1550
+ RecurseLimit extends RecursionLimit,
1551
+ TAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,
1552
+ > = T extends TAncestorTypes
1553
+ ? RecurseLimit extends `+${infer RecursionRemainder}`
1554
+ ? /* Now that specific recursion is found, process that recursive type
1555
+ directly to avoid any collateral damage from ancestor type that
1556
+ required modification. */
1557
+ DeepReadonlyLimitingRecursion<
1558
+ T,
1559
+ DeepenedGenerics,
1560
+ RecursionRemainder extends RecursionLimit ? RecursionRemainder : 0
1561
+ >
1562
+ : T
1563
+ : DeepReadonlyWorker<T, DeepenedGenerics, RecurseLimit, TAncestorTypes | T>;
1564
+
1565
+ /**
1566
+ * Core implementation of {@link InternalUtilityTypes.DeepReadonlyLimitingRecursion}.
1567
+ *
1568
+ * @system
1569
+ */
1570
+ export type DeepReadonlyWorker<
1571
+ T,
1572
+ DeepenedGenerics extends ReadonlySupportedGenerics,
1573
+ RecurseLimit extends RecursionLimit,
1574
+ TAncestorTypes = T /* Always start with self as ancestor; otherwise recursion limit appears one greater */,
1575
+ > = /* test for object */ T extends object
1576
+ ? /* object => */ FilterPreservingFunction<
1577
+ T,
1578
+ DeepenReadonlyInGenerics<
1579
+ T,
1580
+ DeepenedGenerics,
1581
+ RecurseLimit,
1582
+ PreserveErasedTypeOrBrandedPrimitive<
1583
+ T,
1584
+ /* basic type => */ {
1585
+ readonly [K in keyof T]: DeepReadonlyRecursion<
1586
+ T[K],
1587
+ DeepenedGenerics,
1588
+ RecurseLimit,
1589
+ TAncestorTypes
1590
+ >;
1591
+ }
1592
+ >
1593
+ >
1594
+ >
1595
+ : /* not an object => */ T;
1596
+
1597
+ // #endregion
1598
+ // #endregion
1152
1599
  }
@@ -9,12 +9,21 @@
9
9
  // Should a customer need access to these types, export should be relocated to
10
10
  // index.ts and retagged export from internal.ts may be removed.
11
11
 
12
+ export type { DeepReadonly } from "./deepReadonly.js";
12
13
  export type { JsonDeserialized, JsonDeserializedOptions } from "./jsonDeserialized.js";
13
14
  export type { JsonSerializable, JsonSerializableOptions } from "./jsonSerializable.js";
14
15
  export type {
15
16
  SerializationErrorPerNonPublicProperties,
16
17
  SerializationErrorPerUndefinedArrayElement,
17
18
  } from "./jsonSerializationErrors.js";
18
- export type { JsonTypeWith, NonNullJsonObjectWith } from "./jsonType.js";
19
+ export type {
20
+ JsonTypeWith,
21
+ NonNullJsonObjectWith,
22
+ ReadonlyJsonTypeWith,
23
+ } from "./jsonType.js";
24
+ export type { ShallowReadonly } from "./shallowReadonly.js";
19
25
 
20
- export type { InternalUtilityTypes } from "./exposedInternalUtilityTypes.js";
26
+ export type {
27
+ InternalUtilityTypes,
28
+ ReadonlySupportedGenerics,
29
+ } from "./exposedInternalUtilityTypes.js";
package/src/handles.ts CHANGED
@@ -101,6 +101,22 @@ export interface IFluidHandleInternal<
101
101
  bind(handle: IFluidHandleInternal): void;
102
102
  }
103
103
 
104
+ /**
105
+ * @privateRemarks
106
+ * To be merged onto IFluidHandleInternal in accordance with breaking change policy
107
+ * @internal
108
+ */
109
+ export interface IFluidHandleInternalPayloadPending<
110
+ // REVIEW: Constrain `T` to something? How do we support dds and datastores safely?
111
+ out T = unknown, // FluidObject & IFluidLoadable,
112
+ > extends IFluidHandleInternal<T> {
113
+ /**
114
+ * Whether the handle has a pending payload, meaning that it may exist before its payload is retrievable.
115
+ * For instance, the BlobManager can generate handles before completing the blob upload/attach.
116
+ */
117
+ readonly payloadPending: boolean;
118
+ }
119
+
104
120
  /**
105
121
  * Symbol which must only be used on an {@link (IFluidHandle:interface)}, and is used to identify such objects.
106
122
  *
package/src/index.ts CHANGED
@@ -31,6 +31,7 @@ export type {
31
31
  IProvideFluidHandleContext,
32
32
  IProvideFluidHandle,
33
33
  IFluidHandleInternal,
34
+ IFluidHandleInternalPayloadPending,
34
35
  IFluidHandleErased,
35
36
  } from "./handles.js";
36
37
  export { IFluidHandleContext, IFluidHandle, fluidHandleSymbol } from "./handles.js";
package/src/internal.ts CHANGED
@@ -14,6 +14,7 @@ export * from "./index.js";
14
14
  // These types are not intended for direct use by customers and api-extractor will
15
15
  // flag misuse. If an externally visible version of these types is needed, import
16
16
  // from via /internal/exposedUtilityTypes rather than /internal.
17
+ import type { DeepReadonly as ExposedDeepReadonly } from "./deepReadonly.js";
17
18
  import type { InternalUtilityTypes as ExposedInternalUtilityTypes } from "./exposedInternalUtilityTypes.js";
18
19
  import type {
19
20
  JsonDeserialized as ExposedJsonDeserialized,
@@ -23,13 +24,21 @@ import type {
23
24
  JsonSerializable as ExposedJsonSerializable,
24
25
  JsonSerializableOptions,
25
26
  } from "./jsonSerializable.js";
26
- import type { JsonTypeWith as ExposedJsonTypeWith } from "./jsonType.js";
27
+ import type {
28
+ JsonTypeWith as ExposedJsonTypeWith,
29
+ ReadonlyNonNullJsonObjectWith as ExposedReadonlyNonNullJsonObjectWith,
30
+ } from "./jsonType.js";
27
31
 
28
32
  // Note: There are no docs for these re-exports. `@inheritdoc` cannot be used as:
29
33
  // 1. api-extractor does not support renames.
30
34
  // 2. api-extractor does not support package paths. ("Import paths are not supported")
31
35
  // Also not useful, at least in VS Code, as substitution is not made in place.
32
36
 
37
+ /**
38
+ * @internal
39
+ */
40
+ export type DeepReadonly<T> = ExposedDeepReadonly<T>;
41
+
33
42
  /**
34
43
  * @internal
35
44
  */
@@ -57,6 +66,11 @@ export type JsonSerializable<
57
66
  */
58
67
  export type JsonTypeWith<T> = ExposedJsonTypeWith<T>;
59
68
 
69
+ /**
70
+ * @internal
71
+ */
72
+ export type ReadonlyNonNullJsonObjectWith<T> = ExposedReadonlyNonNullJsonObjectWith<T>;
73
+
60
74
  /**
61
75
  * @internal
62
76
  */