@dxos/echo 0.9.1-main.c7dcc2e112 → 0.9.1-staging.ee54ba693a
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/dist/lib/neutral/Annotation.mjs +22 -8
- package/dist/lib/neutral/Database.mjs +3 -3
- package/dist/lib/neutral/Entity.mjs +11 -11
- package/dist/lib/neutral/Err.mjs +7 -3
- package/dist/lib/neutral/Feed.mjs +15 -19
- package/dist/lib/neutral/Filter.mjs +13 -11
- package/dist/lib/neutral/Format.mjs +3 -7
- package/dist/lib/neutral/JsonSchema.mjs +7 -7
- package/dist/lib/neutral/Migration.mjs +11 -11
- package/dist/lib/neutral/Obj.mjs +15 -13
- package/dist/lib/neutral/Order.mjs +1 -1
- package/dist/lib/neutral/Query.mjs +17 -17
- package/dist/lib/neutral/QueryResult.mjs +1 -1
- package/dist/lib/neutral/Ref.mjs +6 -6
- package/dist/lib/neutral/Registry.mjs +1 -1
- package/dist/lib/neutral/Relation.mjs +12 -12
- package/dist/lib/neutral/Tag.mjs +15 -15
- package/dist/lib/neutral/Text.mjs +25 -0
- package/dist/lib/neutral/Text.mjs.map +7 -0
- package/dist/lib/neutral/Type.mjs +10 -10
- package/dist/lib/neutral/chunk-2HKGAQM4.mjs +1394 -0
- package/dist/lib/neutral/chunk-2HKGAQM4.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-O6BH7EPN.mjs → chunk-2ZHECXUR.mjs} +5 -4
- package/dist/lib/neutral/chunk-2ZHECXUR.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-AFANXSGV.mjs → chunk-3KTE2Y7Q.mjs} +20 -20
- package/dist/lib/neutral/chunk-3KTE2Y7Q.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-WZ32BF53.mjs → chunk-3TN2VMI4.mjs} +49 -37
- package/dist/lib/neutral/chunk-3TN2VMI4.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-E7IOTOZD.mjs → chunk-42L4HJ3Z.mjs} +11 -15
- package/dist/lib/neutral/chunk-42L4HJ3Z.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-K3S7D5PR.mjs → chunk-4A2NWKRJ.mjs} +5 -5
- package/dist/lib/neutral/chunk-ACFAOTKJ.mjs +1531 -0
- package/dist/lib/neutral/chunk-ACFAOTKJ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-Z3WMRRAZ.mjs → chunk-BEFR7LEA.mjs} +11 -9
- package/dist/lib/neutral/{chunk-Z3WMRRAZ.mjs.map → chunk-BEFR7LEA.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-6M2Z6WBH.mjs → chunk-BXIKXT7Q.mjs} +2 -6
- package/dist/lib/neutral/{chunk-6M2Z6WBH.mjs.map → chunk-BXIKXT7Q.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-3JXQUMUI.mjs → chunk-C57XMMBY.mjs} +21 -20
- package/dist/lib/neutral/chunk-C57XMMBY.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-JZ6LFQU5.mjs → chunk-C62JYFAD.mjs} +82 -8
- package/dist/lib/neutral/chunk-C62JYFAD.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-TF5BSLF6.mjs → chunk-FSGX2R62.mjs} +3 -3
- package/dist/lib/neutral/chunk-FSGX2R62.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-6CEISA3V.mjs → chunk-HBXT3GSB.mjs} +29 -15
- package/dist/lib/neutral/chunk-HBXT3GSB.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-WU3GIANS.mjs → chunk-IQR45HAD.mjs} +1 -1
- package/dist/lib/neutral/chunk-IQR45HAD.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-TFEWTY5A.mjs → chunk-KCBW4BR6.mjs} +4 -8
- package/dist/lib/neutral/chunk-KCBW4BR6.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-4TPQZPLY.mjs → chunk-L3E5IXAE.mjs} +198 -30
- package/dist/lib/neutral/chunk-L3E5IXAE.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-EVK6XBXO.mjs → chunk-PRC4FEKJ.mjs} +2 -2
- package/dist/lib/neutral/chunk-PRC4FEKJ.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-NOL7O3BL.mjs → chunk-SCT6FFCR.mjs} +9 -4
- package/dist/lib/neutral/chunk-SCT6FFCR.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-BBFJWWAV.mjs → chunk-TOCVVFK2.mjs} +26 -2
- package/dist/lib/neutral/chunk-TOCVVFK2.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-A53NTBHE.mjs → chunk-U53LSQQA.mjs} +3 -3
- package/dist/lib/neutral/{chunk-A53NTBHE.mjs.map → chunk-U53LSQQA.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-PLDMJJJC.mjs → chunk-UGFFV2FR.mjs} +2 -2
- package/dist/lib/neutral/{chunk-35INCYOE.mjs → chunk-UWLP4RFM.mjs} +1 -1
- package/dist/lib/neutral/chunk-UWLP4RFM.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-SZ5WB6HF.mjs → chunk-UZHCQ6NI.mjs} +13 -11
- package/dist/lib/neutral/{chunk-SZ5WB6HF.mjs.map → chunk-UZHCQ6NI.mjs.map} +3 -3
- package/dist/lib/neutral/{chunk-L3OBWBV2.mjs → chunk-WKIT2YY5.mjs} +2 -2
- package/dist/lib/neutral/{chunk-HGWQR5KH.mjs → chunk-XB6ISRAO.mjs} +27 -15
- package/dist/lib/neutral/chunk-XB6ISRAO.mjs.map +7 -0
- package/dist/lib/neutral/chunk-XXL42WCB.mjs +84 -0
- package/dist/lib/neutral/chunk-XXL42WCB.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-5GAIWRQB.mjs → chunk-XXWK4J53.mjs} +27 -42
- package/dist/lib/neutral/chunk-XXWK4J53.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +30 -26
- package/dist/lib/neutral/internal/index.mjs +91 -69
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/testing/index.mjs +79 -60
- package/dist/lib/neutral/testing/index.mjs.map +3 -3
- package/dist/types/src/Annotation.d.ts +35 -1
- package/dist/types/src/Annotation.d.ts.map +1 -1
- package/dist/types/src/Collection.d.ts +9 -8
- package/dist/types/src/Collection.d.ts.map +1 -1
- package/dist/types/src/Database.d.ts +16 -0
- package/dist/types/src/Database.d.ts.map +1 -1
- package/dist/types/src/Dataset.d.ts +1 -16
- package/dist/types/src/Dataset.d.ts.map +1 -1
- package/dist/types/src/Err.d.ts +67 -0
- package/dist/types/src/Err.d.ts.map +1 -1
- package/dist/types/src/Feed.d.ts +56 -80
- package/dist/types/src/Feed.d.ts.map +1 -1
- package/dist/types/src/Filter.d.ts +9 -1
- package/dist/types/src/Filter.d.ts.map +1 -1
- package/dist/types/src/Hypergraph.d.ts +2 -9
- package/dist/types/src/Hypergraph.d.ts.map +1 -1
- package/dist/types/src/Migration.d.ts +1 -1
- package/dist/types/src/Migration.d.ts.map +1 -1
- package/dist/types/src/Obj.d.ts +31 -6
- package/dist/types/src/Obj.d.ts.map +1 -1
- package/dist/types/src/Order.d.ts +1 -1
- package/dist/types/src/Order.d.ts.map +1 -1
- package/dist/types/src/Query.d.ts +1 -1
- package/dist/types/src/Query.d.ts.map +1 -1
- package/dist/types/src/QueryResult.d.ts +2 -2
- package/dist/types/src/QueryResult.d.ts.map +1 -1
- package/dist/types/src/Ref.d.ts +8 -4
- package/dist/types/src/Ref.d.ts.map +1 -1
- package/dist/types/src/Registry.d.ts +1 -1
- package/dist/types/src/Relation.d.ts.map +1 -1
- package/dist/types/src/Tag.d.ts +11 -13
- package/dist/types/src/Tag.d.ts.map +1 -1
- package/dist/types/src/Text.d.ts +41 -0
- package/dist/types/src/Text.d.ts.map +1 -0
- package/dist/types/src/Text.test.d.ts +2 -0
- package/dist/types/src/Text.test.d.ts.map +1 -0
- package/dist/types/src/Type.d.ts +33 -20
- package/dist/types/src/Type.d.ts.map +1 -1
- package/dist/types/src/View.d.ts +8 -9
- package/dist/types/src/View.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/annotations.d.ts +9 -0
- package/dist/types/src/internal/Annotation/annotations.d.ts.map +1 -1
- package/dist/types/src/internal/Annotation/atoms.d.ts +14 -0
- package/dist/types/src/internal/Annotation/atoms.d.ts.map +1 -0
- package/dist/types/src/internal/Annotation/entity-dictionary.d.ts +13 -0
- package/dist/types/src/internal/Annotation/entity-dictionary.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/api.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/guard.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/model.d.ts +1 -1
- package/dist/types/src/internal/Entity/model.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/object.d.ts +5 -1
- package/dist/types/src/internal/Entity/object.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/relation.d.ts +7 -0
- package/dist/types/src/internal/Entity/relation.d.ts.map +1 -1
- package/dist/types/src/internal/Entity/type-uri.d.ts.map +1 -1
- package/dist/types/src/internal/Filter/index.d.ts +2 -0
- package/dist/types/src/internal/Filter/index.d.ts.map +1 -0
- package/dist/types/src/internal/Filter/match.d.ts +22 -0
- package/dist/types/src/internal/Filter/match.d.ts.map +1 -0
- package/dist/types/src/internal/Format/format.d.ts +0 -2
- package/dist/types/src/internal/Format/format.d.ts.map +1 -1
- package/dist/types/src/internal/Format/index.d.ts +2 -2
- package/dist/types/src/internal/Format/index.d.ts.map +1 -1
- package/dist/types/src/internal/Format/string.d.ts +0 -8
- package/dist/types/src/internal/Format/string.d.ts.map +1 -1
- package/dist/types/src/internal/Format/types.d.ts +2 -1
- package/dist/types/src/internal/Format/types.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/atoms.d.ts +7 -3
- package/dist/types/src/internal/Obj/atoms.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/clone.d.ts +2 -1
- package/dist/types/src/internal/Obj/clone.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/create-object.d.ts +3 -4
- package/dist/types/src/internal/Obj/create-object.d.ts.map +1 -1
- package/dist/types/src/internal/Obj/json-serializer.d.ts.map +1 -1
- package/dist/types/src/internal/Query/index.d.ts +1 -0
- package/dist/types/src/internal/Query/index.d.ts.map +1 -1
- package/dist/types/src/internal/Query/query-result-effect.d.ts +9 -0
- package/dist/types/src/internal/Query/query-result-effect.d.ts.map +1 -0
- package/dist/types/src/internal/Ref/atoms.d.ts +1 -2
- package/dist/types/src/internal/Ref/atoms.d.ts.map +1 -1
- package/dist/types/src/internal/Ref/ref.d.ts +13 -6
- package/dist/types/src/internal/Ref/ref.d.ts.map +1 -1
- package/dist/types/src/internal/common/atom-snapshot.d.ts +8 -0
- package/dist/types/src/internal/common/atom-snapshot.d.ts.map +1 -0
- package/dist/types/src/internal/common/proxy/make-object.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/proxy-types.d.ts +12 -0
- package/dist/types/src/internal/common/proxy/proxy-types.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/proxy-utils.d.ts +25 -0
- package/dist/types/src/internal/common/proxy/proxy-utils.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/schema-validator.d.ts +5 -0
- package/dist/types/src/internal/common/proxy/schema-validator.d.ts.map +1 -1
- package/dist/types/src/internal/common/proxy/typed-handler.d.ts +17 -0
- package/dist/types/src/internal/common/proxy/typed-handler.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/entity.d.ts +4 -4
- package/dist/types/src/internal/common/types/entity.d.ts.map +1 -1
- package/dist/types/src/internal/common/types/meta.d.ts +2 -4
- package/dist/types/src/internal/common/types/meta.d.ts.map +1 -1
- package/dist/types/src/internal/index.d.ts +1 -0
- package/dist/types/src/internal/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-schema.d.ts +42 -171
- package/dist/types/src/testing/test-schema.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +20 -13
- package/src/Annotation.test.ts +257 -10
- package/src/Annotation.ts +55 -6
- package/src/Collection.ts +10 -12
- package/src/Database.ts +22 -20
- package/src/Err.ts +22 -0
- package/src/Feed.ts +114 -141
- package/src/Filter.test.ts +38 -0
- package/src/Filter.ts +17 -3
- package/src/Hypergraph.ts +2 -11
- package/src/Migration.ts +1 -1
- package/src/Obj.test.ts +92 -12
- package/src/Obj.ts +36 -5
- package/src/Order.ts +3 -3
- package/src/Query.test.ts +2 -2
- package/src/Query.ts +16 -16
- package/src/QueryResult.ts +2 -2
- package/src/Ref.ts +12 -4
- package/src/Registry.ts +1 -1
- package/src/Relation.ts +1 -1
- package/src/Tag.ts +12 -16
- package/src/Text.test.ts +186 -0
- package/src/Text.ts +116 -0
- package/src/Type.test.ts +52 -24
- package/src/Type.ts +69 -31
- package/src/View.ts +22 -30
- package/src/index.ts +1 -1
- package/src/internal/Annotation/annotations.ts +15 -2
- package/src/internal/Annotation/atoms.ts +107 -0
- package/src/internal/Annotation/entity-dictionary.ts +40 -37
- package/src/internal/Entity/api.ts +1 -1
- package/src/internal/Entity/guard.ts +2 -1
- package/src/internal/Entity/model.ts +2 -2
- package/src/internal/Entity/object.ts +14 -1
- package/src/internal/Entity/relation.ts +19 -0
- package/src/internal/Entity/type-uri.ts +3 -1
- package/src/internal/Filter/index.ts +5 -0
- package/src/internal/Filter/match.ts +284 -0
- package/src/internal/Format/format.ts +0 -2
- package/src/internal/Format/index.ts +2 -2
- package/src/internal/Format/string.ts +0 -12
- package/src/internal/Format/types.ts +4 -2
- package/src/internal/JsonSchema/json-schema.test.ts +82 -54
- package/src/internal/Obj/atoms.ts +31 -18
- package/src/internal/Obj/clone.ts +61 -20
- package/src/internal/Obj/create-object.test.ts +3 -3
- package/src/internal/Obj/create-object.ts +3 -4
- package/src/internal/Obj/inspect.ts +1 -1
- package/src/internal/Obj/json-serializer.test.ts +7 -5
- package/src/internal/Obj/json-serializer.ts +1 -1
- package/src/internal/Obj/schema-validator.test.ts +53 -0
- package/src/internal/Obj/set-value.test.ts +29 -19
- package/src/internal/Query/index.ts +1 -0
- package/src/internal/Query/query-result-effect.ts +35 -0
- package/src/internal/Ref/atoms.ts +23 -3
- package/src/internal/Ref/ref.test.ts +8 -8
- package/src/internal/Ref/ref.ts +26 -20
- package/src/internal/common/atom-snapshot.ts +19 -0
- package/src/internal/common/proxy/make-object.ts +1 -1
- package/src/internal/common/proxy/proxy-types.ts +20 -0
- package/src/internal/common/proxy/proxy-utils.ts +37 -1
- package/src/internal/common/proxy/reactive-array.ts +3 -3
- package/src/internal/common/proxy/reactive.test.ts +1 -1
- package/src/internal/common/proxy/schema-validator.ts +181 -8
- package/src/internal/common/proxy/typed-handler.ts +254 -76
- package/src/internal/common/types/entity.ts +15 -7
- package/src/internal/index.ts +1 -0
- package/src/testing/test-schema.ts +75 -90
- package/dist/lib/neutral/chunk-35INCYOE.mjs.map +0 -7
- package/dist/lib/neutral/chunk-3JXQUMUI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-4TPQZPLY.mjs.map +0 -7
- package/dist/lib/neutral/chunk-5GAIWRQB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-6CEISA3V.mjs.map +0 -7
- package/dist/lib/neutral/chunk-AFANXSGV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BBFJWWAV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-E7IOTOZD.mjs.map +0 -7
- package/dist/lib/neutral/chunk-EVK6XBXO.mjs.map +0 -7
- package/dist/lib/neutral/chunk-HGWQR5KH.mjs.map +0 -7
- package/dist/lib/neutral/chunk-JZ6LFQU5.mjs.map +0 -7
- package/dist/lib/neutral/chunk-NOL7O3BL.mjs.map +0 -7
- package/dist/lib/neutral/chunk-O6BH7EPN.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TF5BSLF6.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TFEWTY5A.mjs.map +0 -7
- package/dist/lib/neutral/chunk-VQYL2OQF.mjs +0 -2353
- package/dist/lib/neutral/chunk-VQYL2OQF.mjs.map +0 -7
- package/dist/lib/neutral/chunk-WU3GIANS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-WZ32BF53.mjs.map +0 -7
- package/dist/lib/neutral/chunk-X3NUUON4.mjs +0 -184
- package/dist/lib/neutral/chunk-X3NUUON4.mjs.map +0 -7
- package/dist/types/src/exemplars.test.d.ts +0 -2
- package/dist/types/src/exemplars.test.d.ts.map +0 -1
- package/dist/types/src/hierarchy.test.d.ts +0 -2
- package/dist/types/src/hierarchy.test.d.ts.map +0 -1
- package/src/exemplars.test.ts +0 -21
- package/src/hierarchy.test.ts +0 -33
- /package/dist/lib/neutral/{chunk-K3S7D5PR.mjs.map → chunk-4A2NWKRJ.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-PLDMJJJC.mjs.map → chunk-UGFFV2FR.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-L3OBWBV2.mjs.map → chunk-WKIT2YY5.mjs.map} +0 -0
|
@@ -32,18 +32,6 @@ export const Formula = Schema.String.pipe(FormatAnnotation.set(TypeFormat.Formul
|
|
|
32
32
|
// TODO(burdon): Implement.
|
|
33
33
|
export const Hostname = Schema.String.pipe(FormatAnnotation.set(TypeFormat.Hostname));
|
|
34
34
|
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
*/
|
|
38
|
-
// TODO(burdon): Implement.
|
|
39
|
-
export const JSON = Schema.String.pipe(FormatAnnotation.set(TypeFormat.JSON));
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
*/
|
|
44
|
-
// TODO(burdon): Implement.
|
|
45
|
-
export const Markdown = Schema.String.pipe(FormatAnnotation.set(TypeFormat.Markdown));
|
|
46
|
-
|
|
47
35
|
/**
|
|
48
36
|
* Regex
|
|
49
37
|
* https://json-schema.org/understanding-json-schema/reference/regular_expressions
|
|
@@ -7,7 +7,7 @@ import type * as JSONSchema from 'effect/JSONSchema';
|
|
|
7
7
|
import * as Option from 'effect/Option';
|
|
8
8
|
import * as SchemaAST from 'effect/SchemaAST';
|
|
9
9
|
|
|
10
|
-
import { createAnnotationHelper } from '../Annotation
|
|
10
|
+
import { createAnnotationHelper } from '../Annotation';
|
|
11
11
|
import { type JsonSchemaType } from '../JsonSchema';
|
|
12
12
|
|
|
13
13
|
// TODO(burdon): Rename PropertyType.
|
|
@@ -79,10 +79,11 @@ export enum TypeFormat {
|
|
|
79
79
|
DID = 'did', // Users, etc.
|
|
80
80
|
DXN = 'dxn',
|
|
81
81
|
Email = 'email',
|
|
82
|
-
Formula = 'formula', // Spreadsheet formula.
|
|
82
|
+
Formula = 'formula', // Spreadsheet (Excel, Google Sheets, etc.) formula.
|
|
83
83
|
Hostname = 'hostname',
|
|
84
84
|
JSON = 'json',
|
|
85
85
|
Markdown = 'markdown',
|
|
86
|
+
Password = 'password',
|
|
86
87
|
Regex = 'regex',
|
|
87
88
|
SingleSelect = 'single-select',
|
|
88
89
|
Text = 'text',
|
|
@@ -149,6 +150,7 @@ export const formatToType: Record<TypeFormat, TypeEnum> = {
|
|
|
149
150
|
[TypeFormat.Hostname]: TypeEnum.String,
|
|
150
151
|
[TypeFormat.JSON]: TypeEnum.String,
|
|
151
152
|
[TypeFormat.Markdown]: TypeEnum.String,
|
|
153
|
+
[TypeFormat.Password]: TypeEnum.String,
|
|
152
154
|
[TypeFormat.Regex]: TypeEnum.String,
|
|
153
155
|
[TypeFormat.URL]: TypeEnum.String,
|
|
154
156
|
[TypeFormat.UUID]: TypeEnum.String,
|
|
@@ -33,9 +33,7 @@ const EXAMPLE_NAMESPACE = '@example';
|
|
|
33
33
|
|
|
34
34
|
describe('effect-to-json', () => {
|
|
35
35
|
test('type annotation', () => {
|
|
36
|
-
const Test = Schema.Struct({ name: Schema.String })
|
|
37
|
-
Type.makeObject(DXN.make('com.example.type.test', '0.1.0')),
|
|
38
|
-
);
|
|
36
|
+
const Test = Type.makeObject(DXN.make('com.example.type.test', '0.1.0'))(Schema.Struct({ name: Schema.String }));
|
|
39
37
|
const jsonSchema = toJsonSchema(Test);
|
|
40
38
|
expect(jsonSchema.$id).toEqual('dxn:com.example.type.test:0.1.0');
|
|
41
39
|
expect(jsonSchema.version).toEqual('0.1.0');
|
|
@@ -43,20 +41,26 @@ describe('effect-to-json', () => {
|
|
|
43
41
|
|
|
44
42
|
test('property meta annotation', () => {
|
|
45
43
|
const meta = { maxLength: 0 };
|
|
46
|
-
const Test =
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
const Test = Type.makeObject(DXN.make('com.example.type.test', '0.1.0'))(
|
|
45
|
+
Schema.Struct({
|
|
46
|
+
name: Schema.String.pipe(PropertyMeta(EXAMPLE_NAMESPACE, meta)),
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
49
|
const jsonSchema = toJsonSchema(Test);
|
|
50
50
|
expect(getNormalizedEchoAnnotations(jsonSchema.properties!.name!)!.meta![EXAMPLE_NAMESPACE]).to.deep.eq(meta);
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
test('reference annotation', () => {
|
|
54
|
-
const Nested =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
const Nested = Type.makeObject(DXN.make('com.example.type.testNested', '0.1.0'))(
|
|
55
|
+
Schema.Struct({
|
|
56
|
+
name: Schema.String,
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
|
+
const Test = Type.makeObject(DXN.make('com.example.type.test', '0.1.0'))(
|
|
60
|
+
Schema.Struct({
|
|
61
|
+
name: Ref(Nested),
|
|
62
|
+
}),
|
|
63
|
+
);
|
|
60
64
|
const jsonSchema = toJsonSchema(Test);
|
|
61
65
|
// log.info('schema', { jsonSchema });
|
|
62
66
|
const nested = jsonSchema.properties!.name;
|
|
@@ -66,12 +70,16 @@ describe('effect-to-json', () => {
|
|
|
66
70
|
// TODO(ZaymonFC): @dmaretskyi we still need to fix this.
|
|
67
71
|
// TODO(dmaretskyi): Remove FieldLookupAnnotationId.
|
|
68
72
|
test.skip('reference annotation with lookup property', () => {
|
|
69
|
-
const Nested =
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
const Nested = Type.makeObject(DXN.make('com.example.type.testNested', '0.1.0'))(
|
|
74
|
+
Schema.Struct({
|
|
75
|
+
name: Schema.String,
|
|
76
|
+
}),
|
|
77
|
+
);
|
|
78
|
+
const Test = Type.makeObject(DXN.make('com.example.type.test', '0.1.0'))(
|
|
79
|
+
Schema.Struct({
|
|
80
|
+
name: Ref(Nested).annotations({ [FieldLookupAnnotationId]: 'name' }),
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
75
83
|
const jsonSchema = toJsonSchema(Test);
|
|
76
84
|
const effectSchema = toEffectSchema(jsonSchema);
|
|
77
85
|
|
|
@@ -80,24 +88,32 @@ describe('effect-to-json', () => {
|
|
|
80
88
|
});
|
|
81
89
|
|
|
82
90
|
test('array of references', () => {
|
|
83
|
-
const Nested =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
const Nested = Type.makeObject(DXN.make('com.example.type.testNested', '0.1.0'))(
|
|
92
|
+
Schema.Struct({
|
|
93
|
+
name: Schema.String,
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
const Test = Type.makeObject(DXN.make('com.example.type.test', '0.1.0'))(
|
|
97
|
+
Schema.Struct({
|
|
98
|
+
name: Schema.Array(Ref(Nested)),
|
|
99
|
+
}),
|
|
100
|
+
);
|
|
89
101
|
|
|
90
102
|
const jsonSchema = toJsonSchema(Test);
|
|
91
103
|
expectReferenceAnnotation((jsonSchema.properties!.name as any).items);
|
|
92
104
|
});
|
|
93
105
|
|
|
94
106
|
test('optional references', () => {
|
|
95
|
-
const Nested =
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
107
|
+
const Nested = Type.makeObject(DXN.make('com.example.type.testNested', '0.1.0'))(
|
|
108
|
+
Schema.Struct({
|
|
109
|
+
name: Schema.String,
|
|
110
|
+
}),
|
|
111
|
+
);
|
|
112
|
+
const Test = Type.makeObject(DXN.make('com.example.type.test', '0.1.0'))(
|
|
113
|
+
Schema.Struct({
|
|
114
|
+
name: Schema.optional(Ref(Nested)),
|
|
115
|
+
}),
|
|
116
|
+
);
|
|
101
117
|
const jsonSchema = toJsonSchema(Test);
|
|
102
118
|
expectReferenceAnnotation(jsonSchema.properties!.name);
|
|
103
119
|
});
|
|
@@ -110,12 +126,14 @@ describe('effect-to-json', () => {
|
|
|
110
126
|
});
|
|
111
127
|
|
|
112
128
|
test('annotations', () => {
|
|
113
|
-
const TempSchema =
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
129
|
+
const TempSchema = Type.makeObject(DXN.make('com.example.type.person', '0.1.0'))(
|
|
130
|
+
Schema.Struct({
|
|
131
|
+
name: Schema.String.annotations({ description: 'Person name', title: 'Name' }),
|
|
132
|
+
email: Schema.String.pipe(FormatAnnotation.set(TypeFormat.Email)).annotations({
|
|
133
|
+
description: 'Email address',
|
|
134
|
+
}),
|
|
117
135
|
}),
|
|
118
|
-
|
|
136
|
+
);
|
|
119
137
|
|
|
120
138
|
const jsonSchema = toJsonSchema(TempSchema);
|
|
121
139
|
expect(jsonSchema).to.deep.eq({
|
|
@@ -159,14 +177,18 @@ describe('effect-to-json', () => {
|
|
|
159
177
|
});
|
|
160
178
|
|
|
161
179
|
test('reference property by ref', () => {
|
|
162
|
-
const Organization =
|
|
163
|
-
|
|
164
|
-
|
|
180
|
+
const Organization = Type.makeObject(DXN.make('com.example.type.organization', '0.1.0'))(
|
|
181
|
+
Schema.Struct({
|
|
182
|
+
field: Schema.String,
|
|
183
|
+
}),
|
|
184
|
+
);
|
|
165
185
|
|
|
166
|
-
const Contact =
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
186
|
+
const Contact = Type.makeObject(DXN.make('com.example.type.person', '0.1.0'))(
|
|
187
|
+
Schema.Struct({
|
|
188
|
+
name: Schema.String,
|
|
189
|
+
organization: Ref(Organization).annotations({ description: 'Contact organization' }),
|
|
190
|
+
}),
|
|
191
|
+
);
|
|
170
192
|
|
|
171
193
|
// log.info('Contact', { ast: Contact.ast });
|
|
172
194
|
|
|
@@ -211,14 +233,18 @@ describe('effect-to-json', () => {
|
|
|
211
233
|
});
|
|
212
234
|
|
|
213
235
|
test('add reference property', () => {
|
|
214
|
-
const Organization =
|
|
215
|
-
|
|
216
|
-
|
|
236
|
+
const Organization = Type.makeObject(DXN.make('com.example.type.organization', '0.1.0'))(
|
|
237
|
+
Schema.Struct({
|
|
238
|
+
field: Schema.String,
|
|
239
|
+
}),
|
|
240
|
+
);
|
|
217
241
|
|
|
218
|
-
const Contact =
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
242
|
+
const Contact = Type.makeObject(DXN.make('com.example.type.person', '0.1.0'))(
|
|
243
|
+
Schema.Struct({
|
|
244
|
+
name: Schema.String,
|
|
245
|
+
organization: Ref(Organization).annotations({ description: 'Contact organization' }),
|
|
246
|
+
}),
|
|
247
|
+
);
|
|
222
248
|
|
|
223
249
|
const jsonSchema = toJsonSchema(Contact);
|
|
224
250
|
setSchemaProperty(
|
|
@@ -418,9 +444,11 @@ describe('json-to-effect', () => {
|
|
|
418
444
|
|
|
419
445
|
for (const partial of [false, true]) {
|
|
420
446
|
test(`deserialized equals original ${partial ? 'with partial' : ''}`, () => {
|
|
421
|
-
const Organization =
|
|
422
|
-
|
|
423
|
-
|
|
447
|
+
const Organization = Type.makeObject(DXN.make('com.example.type.organization', '0.1.0'))(
|
|
448
|
+
Schema.Struct({
|
|
449
|
+
field: Schema.String,
|
|
450
|
+
}),
|
|
451
|
+
);
|
|
424
452
|
|
|
425
453
|
const fields = {
|
|
426
454
|
string: Schema.String,
|
|
@@ -436,8 +464,8 @@ describe('json-to-effect', () => {
|
|
|
436
464
|
null: Schema.Null,
|
|
437
465
|
} as const;
|
|
438
466
|
|
|
439
|
-
const Test = (
|
|
440
|
-
|
|
467
|
+
const Test = Type.makeObject(DXN.make('com.example.type.test', '0.1.0'))(
|
|
468
|
+
partial ? Schema.partial(Schema.Struct(fields)) : Schema.Struct(fields),
|
|
441
469
|
);
|
|
442
470
|
|
|
443
471
|
const jsonSchema = toJsonSchema(Test);
|
|
@@ -15,10 +15,12 @@ import type * as Obj from '../../Obj';
|
|
|
15
15
|
import type * as Ref from '../../Ref';
|
|
16
16
|
import type * as Relation from '../../Relation';
|
|
17
17
|
import { getLabel } from '../Annotation';
|
|
18
|
+
import { snapshotForComparison } from '../common/atom-snapshot';
|
|
18
19
|
import { subscribe } from '../common/proxy/reactive';
|
|
19
|
-
import {
|
|
20
|
+
import { getDatabase, isEntity } from '../Entity';
|
|
20
21
|
import { RefTypeId } from '../Ref/ref';
|
|
21
22
|
import { loadRefTarget } from '../Ref/utils';
|
|
23
|
+
import { isDeleted } from './deleted';
|
|
22
24
|
import { getSnapshot } from './snapshot';
|
|
23
25
|
|
|
24
26
|
const isRef = (obj: unknown): obj is Ref.Ref<any> =>
|
|
@@ -63,8 +65,9 @@ const refFamily = Atom.family(<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Ato
|
|
|
63
65
|
const setupTargetSubscription = (target: T): Obj.Snapshot<T> => {
|
|
64
66
|
unsubscribeTarget?.();
|
|
65
67
|
unsubscribeTarget = subscribe(target, () => {
|
|
68
|
+
// Deleted objects resolve to undefined so callers don't need to inspect isDeleted.
|
|
66
69
|
// getSnapshot adds SnapshotKindId brand at runtime; cast bridges static types.
|
|
67
|
-
get.setSelf(getSnapshot(target) as unknown as Obj.Snapshot<T>);
|
|
70
|
+
get.setSelf(isDeleted(target) ? undefined : (getSnapshot(target) as unknown as Obj.Snapshot<T>));
|
|
68
71
|
});
|
|
69
72
|
return getSnapshot(target) as unknown as Obj.Snapshot<T>;
|
|
70
73
|
};
|
|
@@ -77,19 +80,6 @@ const refFamily = Atom.family(<T extends Obj.Unknown>(ref: Ref.Ref<T>): Atom.Ato
|
|
|
77
80
|
}).pipe(Atom.keepAlive);
|
|
78
81
|
});
|
|
79
82
|
|
|
80
|
-
/**
|
|
81
|
-
* Snapshot a value to create a new reference for comparison and React dependency tracking.
|
|
82
|
-
*/
|
|
83
|
-
const snapshotForComparison = <V>(value: V): V => {
|
|
84
|
-
if (Array.isArray(value)) {
|
|
85
|
-
return [...value] as V;
|
|
86
|
-
}
|
|
87
|
-
if (value !== null && typeof value === 'object') {
|
|
88
|
-
return { ...value } as V;
|
|
89
|
-
}
|
|
90
|
-
return value;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
83
|
/**
|
|
94
84
|
* Atom family for ECHO object properties.
|
|
95
85
|
* Uses nested families: outer keyed by object, inner keyed by property key.
|
|
@@ -150,6 +140,20 @@ const refWithReactiveFamily = Atom.family(<T extends Obj.Unknown>(ref: Ref.Ref<T
|
|
|
150
140
|
);
|
|
151
141
|
});
|
|
152
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Atom family for a property of a ref's target object.
|
|
145
|
+
* Resolves the ref (reactively) then projects the property atom, so it fires when the ref resolves or when
|
|
146
|
+
* that property changes. Yields `undefined` while the target is unresolved.
|
|
147
|
+
*/
|
|
148
|
+
const refPropertyFamily = Atom.family(<T extends Obj.Unknown>(ref: Ref.Ref<T>) =>
|
|
149
|
+
Atom.family(<K extends keyof T>(key: K): Atom.Atom<T[K] | undefined> => {
|
|
150
|
+
return Atom.make<T[K] | undefined>((get) => {
|
|
151
|
+
const target = get(refWithReactiveFamily(ref));
|
|
152
|
+
return target ? get(propertyFamily(target)(key)) : undefined;
|
|
153
|
+
}).pipe(Atom.keepAlive);
|
|
154
|
+
}),
|
|
155
|
+
);
|
|
156
|
+
|
|
153
157
|
/**
|
|
154
158
|
* Atom family for any ECHO entity (obj or relation) — returns a snapshot.
|
|
155
159
|
*/
|
|
@@ -201,10 +205,19 @@ export const makeAtom: {
|
|
|
201
205
|
};
|
|
202
206
|
|
|
203
207
|
/**
|
|
204
|
-
* Create a read-only atom for a specific property of a reactive object.
|
|
205
|
-
* Only fires updates when the property value actually changes.
|
|
208
|
+
* Create a read-only atom for a specific property of a reactive object, or of a ref's target.
|
|
209
|
+
* Only fires updates when the property value actually changes. Given a ref, the atom resolves the target
|
|
210
|
+
* first and yields `undefined` until it loads.
|
|
206
211
|
*/
|
|
207
|
-
export const makeProperty
|
|
212
|
+
export const makeProperty: {
|
|
213
|
+
<T extends Obj.Unknown, K extends keyof T>(obj: T, key: K): Atom.Atom<T[K]>;
|
|
214
|
+
<T extends Obj.Unknown, K extends keyof T>(ref: Ref.Ref<T>, key: K): Atom.Atom<T[K] | undefined>;
|
|
215
|
+
} = (objOrRef: Obj.Unknown | Ref.Ref<any>, key: any): Atom.Atom<any> => {
|
|
216
|
+
if (isRef(objOrRef)) {
|
|
217
|
+
return refPropertyFamily(objOrRef as Ref.Ref<any>)(key);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const obj = objOrRef as Obj.Unknown;
|
|
208
221
|
assertArgument(isEntity(obj), 'obj', 'Object must be a reactive object');
|
|
209
222
|
return propertyFamily(obj)(key);
|
|
210
223
|
};
|
|
@@ -3,20 +3,42 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { invariant } from '@dxos/invariant';
|
|
6
|
-
import { deepMapValues } from '@dxos/util';
|
|
6
|
+
import { assumeType, deepMapValues } from '@dxos/util';
|
|
7
7
|
|
|
8
8
|
import type * as Obj from '../../Obj';
|
|
9
9
|
import { makeObject } from '../common/proxy';
|
|
10
|
-
import { getSchema, getStaticTypeSchema, getType } from '../common/types';
|
|
10
|
+
import { ParentId, getSchema, getStaticTypeSchema, getType } from '../common/types';
|
|
11
11
|
import { getMeta } from '../common/types/meta';
|
|
12
|
+
import { type InternalObjectProps } from '../Entity/model';
|
|
12
13
|
import { Ref } from '../Ref';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Clones an object or relation.
|
|
16
|
-
*
|
|
17
|
+
* By default this does not clone referenced objects, only the properties in the object; pass `opts.deep`
|
|
18
|
+
* to recurse into refs (see {@link Obj.CloneOptions}).
|
|
17
19
|
* @returns A new object with the same schema and properties.
|
|
18
20
|
*/
|
|
19
|
-
export const clone = <T extends Obj.Any>(obj: T, opts?: Obj.CloneOptions): T =>
|
|
21
|
+
export const clone = <T extends Obj.Any>(obj: T, opts?: Obj.CloneOptions): T =>
|
|
22
|
+
cloneInner(obj, opts, obj, new Map(), new Set());
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Recursive clone worker threaded with two cycle-guard structures:
|
|
26
|
+
* - `cache`: id → already-finished clone; reused when the same object appears more than once in a DAG.
|
|
27
|
+
* - `inProgress`: ids of objects whose clone is currently being computed; a ref back into this set means
|
|
28
|
+
* a true cycle — the original ref is kept rather than recursing forever.
|
|
29
|
+
*/
|
|
30
|
+
const cloneInner = <T extends Obj.Any>(
|
|
31
|
+
obj: T,
|
|
32
|
+
opts: Obj.CloneOptions | undefined,
|
|
33
|
+
root: Obj.Any,
|
|
34
|
+
cache: Map<string, Obj.Any>,
|
|
35
|
+
inProgress: Set<string>,
|
|
36
|
+
): T => {
|
|
37
|
+
if (cache.has(obj.id)) {
|
|
38
|
+
return cache.get(obj.id) as T;
|
|
39
|
+
}
|
|
40
|
+
inProgress.add(obj.id);
|
|
41
|
+
|
|
20
42
|
const { id, ...data } = obj;
|
|
21
43
|
// Prefer cloning through the type entity so the cloned instance preserves
|
|
22
44
|
// `Obj.getType` identity. Falls back to the raw schema for older instances
|
|
@@ -24,30 +46,49 @@ export const clone = <T extends Obj.Any>(obj: T, opts?: Obj.CloneOptions): T =>
|
|
|
24
46
|
const typeEntity = getType(obj);
|
|
25
47
|
const schema = typeEntity != null ? getStaticTypeSchema(typeEntity) : getSchema(obj);
|
|
26
48
|
invariant(schema != null, 'Object should have a type or schema');
|
|
27
|
-
|
|
49
|
+
|
|
50
|
+
const mapRef = (value: unknown, recurse: (value: unknown) => unknown): unknown => {
|
|
28
51
|
if (Ref.isRef(value)) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
52
|
+
const target = value.target;
|
|
53
|
+
// A ref back to an in-progress object means a cycle — keep the original ref to break it.
|
|
54
|
+
if (
|
|
55
|
+
target != null &&
|
|
56
|
+
!inProgress.has(target.id) &&
|
|
57
|
+
(opts?.deep === 'all' || (opts?.deep === 'parent' && isChildOf(target, root)))
|
|
58
|
+
) {
|
|
59
|
+
return Ref.make(cloneInner(target, opts, root, cache, inProgress));
|
|
32
60
|
}
|
|
33
61
|
return value;
|
|
34
62
|
}
|
|
35
63
|
return recurse(value);
|
|
36
|
-
}
|
|
64
|
+
};
|
|
37
65
|
|
|
66
|
+
const props: any = deepMapValues(data, mapRef);
|
|
38
67
|
if (opts?.retainId) {
|
|
39
68
|
props.id = id;
|
|
40
69
|
}
|
|
41
|
-
const meta = deepMapValues(getMeta(obj),
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
return recurse(value);
|
|
50
|
-
});
|
|
70
|
+
const meta = deepMapValues(getMeta(obj), mapRef);
|
|
71
|
+
const result = makeObject(schema, props, meta, typeEntity as object | undefined);
|
|
72
|
+
|
|
73
|
+
inProgress.delete(obj.id);
|
|
74
|
+
cache.set(obj.id, result);
|
|
75
|
+
return result;
|
|
76
|
+
};
|
|
51
77
|
|
|
52
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Whether `entity`'s parent chain reaches `root` — i.e. it is an owned descendant that cascade-deletes with
|
|
80
|
+
* the root. Walks the `ParentId` back-links (a finite tree); guarded against cycles defensively.
|
|
81
|
+
*/
|
|
82
|
+
const isChildOf = (entity: unknown, root: Obj.Any): boolean => {
|
|
83
|
+
const seen = new Set<InternalObjectProps>();
|
|
84
|
+
assumeType<InternalObjectProps>(entity);
|
|
85
|
+
let parent = entity[ParentId];
|
|
86
|
+
while (parent != null && !seen.has(parent)) {
|
|
87
|
+
if (parent.id === root.id) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
seen.add(parent);
|
|
91
|
+
parent = parent[ParentId];
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
53
94
|
};
|
|
@@ -54,13 +54,13 @@ describe('create (static version)', () => {
|
|
|
54
54
|
|
|
55
55
|
const json = JSON.parse(JSON.stringify(contact));
|
|
56
56
|
expect(json).toEqual({
|
|
57
|
-
id: contact.id,
|
|
57
|
+
'id': contact.id,
|
|
58
58
|
'@type': DXN.make(Type.getTypename(TestSchema.Person), Type.getVersion(TestSchema.Person)),
|
|
59
59
|
'@meta': {
|
|
60
60
|
keys: [],
|
|
61
61
|
},
|
|
62
|
-
name: 'Bot',
|
|
63
|
-
email: 'bot@example.com',
|
|
62
|
+
'name': 'Bot',
|
|
63
|
+
'email': 'bot@example.com',
|
|
64
64
|
});
|
|
65
65
|
expect(objectToJSON(contact)).toStrictEqual(json);
|
|
66
66
|
});
|
|
@@ -55,10 +55,9 @@ export type CreateObjectProps<T> = (T extends { id: string }
|
|
|
55
55
|
*
|
|
56
56
|
* @example
|
|
57
57
|
* ```ts
|
|
58
|
-
*
|
|
59
|
-
* name: Schema.String,
|
|
60
|
-
*
|
|
61
|
-
* }).pipe(Type.makeObject(DXN.make('com.example.type.person', '0.1.0')))
|
|
58
|
+
* class Contact extends Type.makeObject<Contact>(DXN.make('com.example.type.person', '0.1.0'))(
|
|
59
|
+
* Schema.Struct({ name: Schema.String, email: Schema.String }),
|
|
60
|
+
* ) {}
|
|
62
61
|
*
|
|
63
62
|
* const contact = createObject(Contact, {
|
|
64
63
|
* name: "John",
|
|
@@ -7,7 +7,7 @@ import type { InspectOptionsStylized, inspect as inspectFn } from 'node:util';
|
|
|
7
7
|
import { type CustomInspectFunction, inspectCustom } from '@dxos/debug';
|
|
8
8
|
|
|
9
9
|
import { getTypeURI } from '../Annotation';
|
|
10
|
-
import {
|
|
10
|
+
import { type AnyEntity, ATTR_TYPE } from '../common/types';
|
|
11
11
|
import { ATTR_META } from '../common/types/meta';
|
|
12
12
|
import { MetaId } from '../common/types/model-symbols';
|
|
13
13
|
|
|
@@ -10,7 +10,7 @@ import { DXN, EID } from '@dxos/keys';
|
|
|
10
10
|
import * as Obj from '../../Obj';
|
|
11
11
|
import { TestSchema } from '../../testing';
|
|
12
12
|
import * as Type from '../../Type';
|
|
13
|
-
import {
|
|
13
|
+
import { getTypename, getTypeURI } from '../Annotation';
|
|
14
14
|
import { getMetaChecked } from '../common/api';
|
|
15
15
|
import { ATTR_TYPE, EntityKind, KindId, TypeId, getSchema } from '../common/types';
|
|
16
16
|
import { MetaId } from '../common/types/model-symbols';
|
|
@@ -160,10 +160,12 @@ describe('Object JSON serializer', () => {
|
|
|
160
160
|
});
|
|
161
161
|
|
|
162
162
|
describe('Uint8Array', () => {
|
|
163
|
-
const Blob =
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
const Blob = Type.makeObject(DXN.make('com.example.type.blob', '0.1.0'))(
|
|
164
|
+
Schema.Struct({
|
|
165
|
+
name: Schema.String,
|
|
166
|
+
bytes: Schema.Uint8ArrayFromSelf,
|
|
167
|
+
}),
|
|
168
|
+
);
|
|
167
169
|
type Blob = Type.InstanceType<typeof Blob>;
|
|
168
170
|
|
|
169
171
|
test('round-trips Uint8Array field through JSON with schema', async ({ expect }) => {
|
|
@@ -15,9 +15,9 @@ import type * as Obj from '../../Obj';
|
|
|
15
15
|
import { getTypeAnnotation, getTypeURI, setTypename } from '../Annotation';
|
|
16
16
|
import { attachTypedJsonSerializer, defineHiddenProperty, typedJsonSerializer } from '../common/proxy';
|
|
17
17
|
import {
|
|
18
|
+
type AnyEntity,
|
|
18
19
|
ATTR_PARENT,
|
|
19
20
|
ATTR_TYPE,
|
|
20
|
-
type AnyEntity,
|
|
21
21
|
EntityKind,
|
|
22
22
|
KindId,
|
|
23
23
|
ParentId,
|
|
@@ -129,6 +129,19 @@ describe('schema-validator', () => {
|
|
|
129
129
|
valueToAssign: { any: 'value' },
|
|
130
130
|
});
|
|
131
131
|
});
|
|
132
|
+
|
|
133
|
+
test('walking into an Unknown-typed value does not throw', ({ expect }) => {
|
|
134
|
+
// Mirrors the annotation Dictionary (Record<string, Unknown>): nested keys/indices under an
|
|
135
|
+
// Unknown slot are all valid, so the validator must not reject while walking them.
|
|
136
|
+
const schema = Schema.Struct({ dict: Schema.Record({ key: Schema.String, value: Schema.Unknown }) });
|
|
137
|
+
for (const path of [
|
|
138
|
+
['dict', 'someType'],
|
|
139
|
+
['dict', 'someType', 'nested'],
|
|
140
|
+
['dict', 'someType', '0'],
|
|
141
|
+
]) {
|
|
142
|
+
SchemaValidator.getPropertySchema(schema, path);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
132
145
|
test('index signatures', () => {
|
|
133
146
|
for (const value of [42, '42']) {
|
|
134
147
|
validateValueToAssign({
|
|
@@ -179,4 +192,44 @@ describe('schema-validator', () => {
|
|
|
179
192
|
}
|
|
180
193
|
});
|
|
181
194
|
});
|
|
195
|
+
|
|
196
|
+
describe('assertExactProperties', () => {
|
|
197
|
+
test('rejects extra properties on a closed struct', () => {
|
|
198
|
+
const Person = Schema.Struct({ name: Schema.String });
|
|
199
|
+
expect(() => SchemaValidator.assertExactProperties(Person, { name: 'Alice', extra: true })).to.throw(
|
|
200
|
+
/Unknown property: extra/,
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test('allows extra properties when the schema has an index signature', () => {
|
|
205
|
+
const Expando = Schema.Struct({}, { key: Schema.String, value: Schema.Any });
|
|
206
|
+
expect(() => SchemaValidator.assertExactProperties(Expando, { custom: 'value' })).not.to.throw();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test('rejects extra nested properties', () => {
|
|
210
|
+
const schema = Schema.Struct({
|
|
211
|
+
nested: Schema.Struct({ field: Schema.Number }),
|
|
212
|
+
});
|
|
213
|
+
expect(() => SchemaValidator.assertExactProperties(schema, { nested: { field: 1, extra: true } })).to.throw(
|
|
214
|
+
/Unknown property: nested.extra/,
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('resolves nested discriminated union using target property values', () => {
|
|
219
|
+
const spec = Schema.Union(
|
|
220
|
+
Schema.Struct({ kind: Schema.Literal('feed'), feed: Schema.optional(Schema.String) }),
|
|
221
|
+
Schema.Struct({ kind: Schema.Literal('timer'), cron: Schema.String }),
|
|
222
|
+
);
|
|
223
|
+
const schema = Schema.Struct({ spec });
|
|
224
|
+
const target = { spec: { kind: 'feed' as const, feed: 'echo:/feed', extra: true } };
|
|
225
|
+
expect(() => SchemaValidator.assertExactProperties(schema, target, (path) => getDeep(target, path))).to.throw(
|
|
226
|
+
/Unknown property: spec.extra/,
|
|
227
|
+
);
|
|
228
|
+
expect(() =>
|
|
229
|
+
SchemaValidator.assertExactProperties(schema, { spec: { kind: 'feed' as const } }, (path) =>
|
|
230
|
+
getDeep({ spec: { kind: 'feed' as const } }, path),
|
|
231
|
+
),
|
|
232
|
+
).not.to.throw();
|
|
233
|
+
});
|
|
234
|
+
});
|
|
182
235
|
});
|