@dxos/echo 0.9.0 → 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 +30 -8
- package/dist/lib/neutral/Database.mjs +7 -3
- package/dist/lib/neutral/Entity.mjs +15 -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 +19 -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-QQIYS74I.mjs → chunk-3KTE2Y7Q.mjs} +20 -20
- package/dist/lib/neutral/chunk-3KTE2Y7Q.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-R5W6DXR4.mjs → chunk-3TN2VMI4.mjs} +72 -36
- package/dist/lib/neutral/chunk-3TN2VMI4.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-5SMDBFVB.mjs → chunk-42L4HJ3Z.mjs} +11 -15
- package/dist/lib/neutral/chunk-42L4HJ3Z.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-7PI7C4EF.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-SBVFRTST.mjs → chunk-BEFR7LEA.mjs} +20 -10
- package/dist/lib/neutral/chunk-BEFR7LEA.mjs.map +7 -0
- 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-UUP46KUQ.mjs → chunk-C57XMMBY.mjs} +21 -20
- package/dist/lib/neutral/chunk-C57XMMBY.mjs.map +7 -0
- package/dist/lib/neutral/chunk-C62JYFAD.mjs +183 -0
- package/dist/lib/neutral/chunk-C62JYFAD.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-MZ7K3MLL.mjs → chunk-FSGX2R62.mjs} +3 -3
- package/dist/lib/neutral/chunk-FSGX2R62.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-TYGKCRMK.mjs → chunk-HBXT3GSB.mjs} +37 -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-WTQJHC75.mjs → chunk-L3E5IXAE.mjs} +225 -45
- 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-6YDI3J37.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-RIVWNMSF.mjs → chunk-U53LSQQA.mjs} +3 -3
- package/dist/lib/neutral/{chunk-RIVWNMSF.mjs.map → chunk-U53LSQQA.mjs.map} +1 -1
- package/dist/lib/neutral/{chunk-IGK6FN65.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-LWXVKPPW.mjs → chunk-UZHCQ6NI.mjs} +13 -11
- package/dist/lib/neutral/{chunk-LWXVKPPW.mjs.map → chunk-UZHCQ6NI.mjs.map} +3 -3
- package/dist/lib/neutral/{chunk-5SUJPHAE.mjs → chunk-WKIT2YY5.mjs} +2 -2
- package/dist/lib/neutral/{chunk-T6E37YIP.mjs → chunk-XB6ISRAO.mjs} +38 -18
- 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-ZGNNFYHS.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 +111 -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 +38 -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/Entity.d.ts +2 -0
- package/dist/types/src/Entity.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 +59 -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 +33 -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 +10 -6
- 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 +38 -21
- 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 +50 -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 +12 -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/index.d.ts +1 -0
- package/dist/types/src/internal/Ref/index.d.ts.map +1 -1
- package/dist/types/src/internal/Ref/ref.d.ts +79 -8
- package/dist/types/src/internal/Ref/ref.d.ts.map +1 -1
- package/dist/types/src/internal/Ref/strong-deps.d.ts +35 -0
- package/dist/types/src/internal/Ref/strong-deps.d.ts.map +1 -0
- 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 +58 -4
- package/src/Collection.ts +10 -12
- package/src/Database.ts +55 -21
- package/src/Entity.ts +3 -1
- package/src/Err.ts +22 -0
- package/src/Feed.ts +117 -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 +38 -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 +14 -6
- package/src/Registry.ts +1 -1
- package/src/Relation.ts +1 -1
- package/src/Tag.ts +13 -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 +85 -33
- package/src/View.ts +22 -30
- package/src/index.ts +1 -1
- package/src/internal/Annotation/annotations.ts +71 -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 +62 -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 +4 -4
- 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/index.ts +1 -0
- package/src/internal/Ref/ref.test.ts +8 -8
- package/src/internal/Ref/ref.ts +122 -39
- package/src/internal/Ref/strong-deps.ts +107 -0
- 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-3PBP4V4O.mjs +0 -101
- package/dist/lib/neutral/chunk-3PBP4V4O.mjs.map +0 -7
- package/dist/lib/neutral/chunk-4ZUHOTCG.mjs +0 -184
- package/dist/lib/neutral/chunk-4ZUHOTCG.mjs.map +0 -7
- package/dist/lib/neutral/chunk-5SMDBFVB.mjs.map +0 -7
- package/dist/lib/neutral/chunk-6YDI3J37.mjs.map +0 -7
- package/dist/lib/neutral/chunk-7FPIAJIV.mjs +0 -2279
- package/dist/lib/neutral/chunk-7FPIAJIV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-BBFJWWAV.mjs.map +0 -7
- package/dist/lib/neutral/chunk-EVK6XBXO.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MZ7K3MLL.mjs.map +0 -7
- package/dist/lib/neutral/chunk-O6BH7EPN.mjs.map +0 -7
- package/dist/lib/neutral/chunk-QQIYS74I.mjs.map +0 -7
- package/dist/lib/neutral/chunk-R5W6DXR4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-SBVFRTST.mjs.map +0 -7
- package/dist/lib/neutral/chunk-T6E37YIP.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TFEWTY5A.mjs.map +0 -7
- package/dist/lib/neutral/chunk-TYGKCRMK.mjs.map +0 -7
- package/dist/lib/neutral/chunk-UUP46KUQ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-WTQJHC75.mjs.map +0 -7
- package/dist/lib/neutral/chunk-WU3GIANS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ZGNNFYHS.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-7PI7C4EF.mjs.map → chunk-4A2NWKRJ.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-IGK6FN65.mjs.map → chunk-UGFFV2FR.mjs.map} +0 -0
- /package/dist/lib/neutral/{chunk-5SUJPHAE.mjs.map → chunk-WKIT2YY5.mjs.map} +0 -0
package/src/Obj.test.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2026 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { describe, expectTypeOf, test
|
|
5
|
+
import { describe, expect, expectTypeOf, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { EID } from '@dxos/keys';
|
|
8
8
|
|
|
@@ -12,6 +12,7 @@ import * as Obj from './Obj';
|
|
|
12
12
|
import * as Ref from './Ref';
|
|
13
13
|
import * as Relation from './Relation';
|
|
14
14
|
import { TestSchema } from './testing';
|
|
15
|
+
import type * as Type from './Type';
|
|
15
16
|
|
|
16
17
|
describe('Obj', () => {
|
|
17
18
|
describe('make', () => {
|
|
@@ -137,11 +138,11 @@ describe('Obj', () => {
|
|
|
137
138
|
|
|
138
139
|
test("prefer: 'named' returns dxn: URI when meta.key is set", ({ expect }) => {
|
|
139
140
|
const obj = Obj.make(TestSchema.Person, {
|
|
140
|
-
[Obj.Meta]: { key: 'org.dxos.
|
|
141
|
+
[Obj.Meta]: { key: 'org.dxos.skill.webSearch' },
|
|
141
142
|
name: 'Alice',
|
|
142
143
|
});
|
|
143
144
|
const uri = Obj.getURI(obj, { prefer: 'named' });
|
|
144
|
-
expect(uri).toBe('dxn:org.dxos.
|
|
145
|
+
expect(uri).toBe('dxn:org.dxos.skill.webSearch');
|
|
145
146
|
});
|
|
146
147
|
|
|
147
148
|
test("prefer: 'named' falls back to EID when meta.key is absent", ({ expect }) => {
|
|
@@ -152,12 +153,12 @@ describe('Obj', () => {
|
|
|
152
153
|
|
|
153
154
|
test("prefer: 'named' handles key with hyphens (falls back to raw key URI)", ({ expect }) => {
|
|
154
155
|
const obj = Obj.make(TestSchema.Person, {
|
|
155
|
-
[Obj.Meta]: { key: 'org.dxos.
|
|
156
|
+
[Obj.Meta]: { key: 'org.dxos.skill.web-search' },
|
|
156
157
|
name: 'Alice',
|
|
157
158
|
});
|
|
158
159
|
// Hyphens in the final DXN segment are invalid; falls back to the raw key as URI.
|
|
159
160
|
const uri = Obj.getURI(obj, { prefer: 'named' });
|
|
160
|
-
expect(uri).toBe('org.dxos.
|
|
161
|
+
expect(uri).toBe('org.dxos.skill.web-search');
|
|
161
162
|
});
|
|
162
163
|
|
|
163
164
|
test("prefer: 'absolute' falls back to current EID when object has no database", ({ expect }) => {
|
|
@@ -328,7 +329,7 @@ describe('Obj', () => {
|
|
|
328
329
|
employer: Ref.make(employer),
|
|
329
330
|
});
|
|
330
331
|
|
|
331
|
-
const cloned = Obj.clone(person, { deep:
|
|
332
|
+
const cloned = Obj.clone(person, { deep: 'all' });
|
|
332
333
|
|
|
333
334
|
expect(cloned.employer).not.toBe(person.employer);
|
|
334
335
|
expect(cloned.employer?.target).not.toBe(employer);
|
|
@@ -363,7 +364,7 @@ describe('Obj', () => {
|
|
|
363
364
|
tasks: [Ref.make(task1), Ref.make(task2)],
|
|
364
365
|
});
|
|
365
366
|
|
|
366
|
-
const cloned = Obj.clone(person, { deep:
|
|
367
|
+
const cloned = Obj.clone(person, { deep: 'all' });
|
|
367
368
|
|
|
368
369
|
expect(cloned.tasks).not.toBe(person.tasks);
|
|
369
370
|
expect(cloned.tasks?.length).toBe(2);
|
|
@@ -393,7 +394,7 @@ describe('Obj', () => {
|
|
|
393
394
|
employer: Ref.make(employer),
|
|
394
395
|
});
|
|
395
396
|
|
|
396
|
-
const cloned = Obj.clone(person, { deep:
|
|
397
|
+
const cloned = Obj.clone(person, { deep: 'all' });
|
|
397
398
|
|
|
398
399
|
expect(cloned.employer).toBeDefined();
|
|
399
400
|
expect(cloned.employer?.target).toBeDefined();
|
|
@@ -406,7 +407,7 @@ describe('Obj', () => {
|
|
|
406
407
|
username: 'bob',
|
|
407
408
|
});
|
|
408
409
|
|
|
409
|
-
const clonedWithoutEmployer = Obj.clone(personWithoutEmployer, { deep:
|
|
410
|
+
const clonedWithoutEmployer = Obj.clone(personWithoutEmployer, { deep: 'all' });
|
|
410
411
|
expect(clonedWithoutEmployer.employer).toBeUndefined();
|
|
411
412
|
});
|
|
412
413
|
|
|
@@ -426,7 +427,7 @@ describe('Obj', () => {
|
|
|
426
427
|
},
|
|
427
428
|
});
|
|
428
429
|
|
|
429
|
-
const cloned = Obj.clone(person, { deep:
|
|
430
|
+
const cloned = Obj.clone(person, { deep: 'all' });
|
|
430
431
|
|
|
431
432
|
expect(cloned.address?.city).toBe('San Francisco');
|
|
432
433
|
expect(cloned.address?.state).toBe('CA');
|
|
@@ -455,7 +456,7 @@ describe('Obj', () => {
|
|
|
455
456
|
tasks: [Ref.make(task1), Ref.make(task2), Ref.make(task3)],
|
|
456
457
|
});
|
|
457
458
|
|
|
458
|
-
const cloned = Obj.clone(person, { deep:
|
|
459
|
+
const cloned = Obj.clone(person, { deep: 'all' });
|
|
459
460
|
|
|
460
461
|
expect(cloned.tasks?.length).toBe(3);
|
|
461
462
|
expect(cloned.tasks?.[0]?.target?.title).toBe('Task 1');
|
|
@@ -488,7 +489,7 @@ describe('Obj', () => {
|
|
|
488
489
|
employer: Ref.make(employer),
|
|
489
490
|
});
|
|
490
491
|
|
|
491
|
-
const cloned = Obj.clone(person, { deep:
|
|
492
|
+
const cloned = Obj.clone(person, { deep: 'all', retainId: true });
|
|
492
493
|
|
|
493
494
|
expect(cloned.id).toBe(person.id);
|
|
494
495
|
expect(cloned.employer?.target).not.toBe(employer);
|
|
@@ -509,6 +510,48 @@ describe('Obj', () => {
|
|
|
509
510
|
expect(Obj.instanceOf(TestSchema.Person, cloned)).toBe(true);
|
|
510
511
|
expect(Obj.getType(cloned)).toBe(Obj.getType(person));
|
|
511
512
|
});
|
|
513
|
+
|
|
514
|
+
test("deep: 'parent' clones owned children but shares unowned refs", ({ expect }) => {
|
|
515
|
+
// An owned task (parented to the person) is cloned; a shared task (no parent link) is referenced as-is.
|
|
516
|
+
const ownedTask = Obj.make(TestSchema.Task, { title: 'Owned' });
|
|
517
|
+
const sharedTask = Obj.make(TestSchema.Task, { title: 'Shared' });
|
|
518
|
+
const person = Obj.make(TestSchema.Person, {
|
|
519
|
+
name: 'Alice',
|
|
520
|
+
email: 'alice@example.com',
|
|
521
|
+
username: 'alice',
|
|
522
|
+
tasks: [Ref.make(ownedTask), Ref.make(sharedTask)],
|
|
523
|
+
});
|
|
524
|
+
Obj.setParent(ownedTask, person);
|
|
525
|
+
|
|
526
|
+
const cloned = Obj.clone(person, { deep: 'parent' });
|
|
527
|
+
|
|
528
|
+
// Owned child is a fresh copy.
|
|
529
|
+
expect(cloned.tasks?.[0]?.target).not.toBe(ownedTask);
|
|
530
|
+
expect(cloned.tasks?.[0]?.target?.id).not.toBe(ownedTask.id);
|
|
531
|
+
expect(cloned.tasks?.[0]?.target?.title).toBe('Owned');
|
|
532
|
+
// Unowned (shared) ref points at the original object.
|
|
533
|
+
expect(cloned.tasks?.[1]?.target).toBe(sharedTask);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
test("deep: 'parent' follows transitive ownership", ({ expect }) => {
|
|
537
|
+
// grandchild ← child ← root: both are cloned because their parent chain reaches the clone root.
|
|
538
|
+
const grandchild = Obj.make(TestSchema.Task, { title: 'Grandchild' });
|
|
539
|
+
const child = Obj.make(TestSchema.Task, { title: 'Child', previous: Ref.make(grandchild) });
|
|
540
|
+
const person = Obj.make(TestSchema.Person, {
|
|
541
|
+
name: 'Alice',
|
|
542
|
+
email: 'alice@example.com',
|
|
543
|
+
username: 'alice',
|
|
544
|
+
tasks: [Ref.make(child)],
|
|
545
|
+
});
|
|
546
|
+
Obj.setParent(child, person);
|
|
547
|
+
Obj.setParent(grandchild, child);
|
|
548
|
+
|
|
549
|
+
const cloned = Obj.clone(person, { deep: 'parent' });
|
|
550
|
+
|
|
551
|
+
expect(cloned.tasks?.[0]?.target).not.toBe(child);
|
|
552
|
+
expect(cloned.tasks?.[0]?.target?.previous?.target).not.toBe(grandchild);
|
|
553
|
+
expect(cloned.tasks?.[0]?.target?.previous?.target?.title).toBe('Grandchild');
|
|
554
|
+
});
|
|
512
555
|
});
|
|
513
556
|
|
|
514
557
|
describe('type-level tests', () => {
|
|
@@ -638,4 +681,41 @@ describe('Obj', () => {
|
|
|
638
681
|
expect(target.properties).toEqual({ x: '2' });
|
|
639
682
|
});
|
|
640
683
|
});
|
|
684
|
+
|
|
685
|
+
describe('exemplars', () => {
|
|
686
|
+
test('factory', ({ expect }) => {
|
|
687
|
+
const factory = <S extends Type.AnyObj>(schema: S) => {
|
|
688
|
+
return (props: Obj.MakeProps<S>) => Obj.make(schema, props);
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
const makePerson = factory(TestSchema.Person);
|
|
692
|
+
const person = makePerson({ name: 'John Doe' });
|
|
693
|
+
expect(person.name).toBe('John Doe');
|
|
694
|
+
});
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
describe('Hierarchy', () => {
|
|
698
|
+
test('setParent and getParent', async () => {
|
|
699
|
+
const parent = Obj.make(TestSchema.Organization, { name: 'parent' });
|
|
700
|
+
const child = Obj.make(TestSchema.Person, { name: 'child' });
|
|
701
|
+
expect(Obj.getParent(child)).toBeUndefined();
|
|
702
|
+
|
|
703
|
+
Obj.setParent(child, parent);
|
|
704
|
+
expect(Obj.getParent(child)).toBe(parent);
|
|
705
|
+
|
|
706
|
+
Obj.setParent(child, undefined);
|
|
707
|
+
expect(Obj.getParent(child)).toBeUndefined();
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
test('create object with Obj.Parent in props', () => {
|
|
711
|
+
const parent = Obj.make(TestSchema.Organization, { name: 'DXOS' });
|
|
712
|
+
const child = Obj.make(TestSchema.Person, {
|
|
713
|
+
[Obj.Parent]: parent,
|
|
714
|
+
name: 'John',
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
expect(child.name).toBe('John');
|
|
718
|
+
expect(Obj.getParent(child)).toBe(parent);
|
|
719
|
+
});
|
|
720
|
+
});
|
|
641
721
|
});
|
package/src/Obj.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import * as Effect from 'effect/Effect';
|
|
8
8
|
import * as Equal from 'effect/Equal';
|
|
9
|
+
import * as Exit from 'effect/Exit';
|
|
9
10
|
import * as Function from 'effect/Function';
|
|
10
11
|
import * as Option from 'effect/Option';
|
|
11
12
|
import * as Schema from 'effect/Schema';
|
|
@@ -63,9 +64,9 @@ export interface Unknown extends BaseObj {}
|
|
|
63
64
|
* if (Obj.isObject(unknownValue)) { ... }
|
|
64
65
|
*
|
|
65
66
|
* // Reference to any object type
|
|
66
|
-
*
|
|
67
|
-
* objects: Schema.Array(Ref.Ref(Obj.Unknown)),
|
|
68
|
-
*
|
|
67
|
+
* class Collection extends Type.makeObject<Collection>(DXN.make('com.example.type.collection', '0.1.0'))(
|
|
68
|
+
* Schema.Struct({ objects: Schema.Array(Ref.Ref(Obj.Unknown)) }),
|
|
69
|
+
* ) {}
|
|
69
70
|
* ```
|
|
70
71
|
*/
|
|
71
72
|
// TODO(wittjosiah): Investigate if Schema.filter can validate KindId on ECHO instances.
|
|
@@ -299,6 +300,22 @@ export const getReactiveOption = <T extends Unknown>(snapshot: Snapshot<T>): Eff
|
|
|
299
300
|
export const getReactiveOrThrow = <T extends Unknown>(snapshot: Snapshot<T>): T =>
|
|
300
301
|
Effect.runSync(getReactive(snapshot));
|
|
301
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Synchronous version of `Obj.getReactive` that returns `undefined` instead of throwing.
|
|
305
|
+
* Accepts `undefined` input so callers can pass the result of `useObject` directly.
|
|
306
|
+
*
|
|
307
|
+
* @param snapshot - A snapshot of the object (from `Obj.getSnapshot` or `useObject`), or `undefined`.
|
|
308
|
+
* @returns The reactive object, or `undefined` if the snapshot is `undefined` or unresolvable.
|
|
309
|
+
*/
|
|
310
|
+
export const getReactiveOrUndefined = <T extends Unknown>(snapshot: Snapshot<T> | undefined): T | undefined => {
|
|
311
|
+
if (snapshot === undefined) {
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
return Effect.runSyncExit(getReactive(snapshot)).pipe(
|
|
315
|
+
Exit.match({ onSuccess: (value) => value, onFailure: () => undefined }),
|
|
316
|
+
);
|
|
317
|
+
};
|
|
318
|
+
|
|
302
319
|
export type CloneOptions = {
|
|
303
320
|
/**
|
|
304
321
|
* Retain the original object's ID.
|
|
@@ -308,9 +325,12 @@ export type CloneOptions = {
|
|
|
308
325
|
|
|
309
326
|
/**
|
|
310
327
|
* Recursively clone referenced objects.
|
|
311
|
-
*
|
|
328
|
+
* - `'parent'`: clone only refs whose target is transitively parented under the clone root (children
|
|
329
|
+
* that cascade-delete with it); shared refs (registry operations, context objects, …) are copied as-is.
|
|
330
|
+
* - `'all'`: clone every referenced object recursively.
|
|
331
|
+
* Omit for a shallow clone (refs copied as-is).
|
|
312
332
|
*/
|
|
313
|
-
deep?:
|
|
333
|
+
deep?: 'parent' | 'all';
|
|
314
334
|
};
|
|
315
335
|
|
|
316
336
|
/**
|
|
@@ -923,6 +943,19 @@ export const version = (entity: Unknown | Snapshot): Version => internal.version
|
|
|
923
943
|
// Atoms
|
|
924
944
|
//
|
|
925
945
|
|
|
946
|
+
/**
|
|
947
|
+
* Create a reactive snapshot atom for an ECHO object or ref.
|
|
948
|
+
* Use inside atom computations (e.g. `Atom.make((get) => get(Obj.atom(ref)))`) to subscribe
|
|
949
|
+
* to a ref's target — the atom re-fires when the target loads or changes.
|
|
950
|
+
*
|
|
951
|
+
* @idiom org.dxos.echo.objAtomReactive
|
|
952
|
+
* applies: Subscribing to a ref's target inside an atom computation or a non-React reactive context
|
|
953
|
+
* instead-of: `ref.target` — synchronous and not reactive; returns `undefined` when the target isn't loaded yet and never notifies when it becomes available
|
|
954
|
+
* uses: {@link atom}
|
|
955
|
+
* related: org.dxos.echo-react.useObjectReactive
|
|
956
|
+
*/
|
|
926
957
|
export const atom = objInternal.makeAtom;
|
|
927
958
|
export const atomReactive = objInternal.makeWithReactive;
|
|
928
959
|
export const atomProperty = objInternal.makeProperty;
|
|
960
|
+
export const labelAtom = objInternal.makeLabelAtom;
|
|
961
|
+
export const labelProperty = internal.getLabelProperty;
|
package/src/Order.ts
CHANGED
|
@@ -10,7 +10,7 @@ export interface Order<T> {
|
|
|
10
10
|
// TODO(dmaretskyi): See new effect-schema approach to variance.
|
|
11
11
|
'~Order': { value: T };
|
|
12
12
|
|
|
13
|
-
ast: QueryAST.Order;
|
|
13
|
+
'ast': QueryAST.Order;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export type Any = Order<any>;
|
|
@@ -18,11 +18,11 @@ export type Any = Order<any>;
|
|
|
18
18
|
class OrderClass implements Order<any> {
|
|
19
19
|
private static 'variance': Order<any>['~Order'] = {} as Order<any>['~Order'];
|
|
20
20
|
|
|
21
|
-
static is(value: unknown): value is Order<any> {
|
|
21
|
+
static 'is'(value: unknown): value is Order<any> {
|
|
22
22
|
return typeof value === 'object' && value !== null && '~Order' in value;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
constructor(public readonly ast: QueryAST.Order) {}
|
|
25
|
+
'constructor'(public readonly ast: QueryAST.Order) {}
|
|
26
26
|
|
|
27
27
|
'~Order' = OrderClass.variance;
|
|
28
28
|
}
|
package/src/Query.test.ts
CHANGED
|
@@ -582,8 +582,8 @@ describe('query api', () => {
|
|
|
582
582
|
const feed = (await Obj.fromJSON(
|
|
583
583
|
{
|
|
584
584
|
'@type': 'dxn:org.dxos.type.feed:0.1.0',
|
|
585
|
-
id: feedId,
|
|
586
|
-
name: 'test-feed',
|
|
585
|
+
'id': feedId,
|
|
586
|
+
'name': 'test-feed',
|
|
587
587
|
},
|
|
588
588
|
{ uri: feedDxn },
|
|
589
589
|
)) as Feed.Feed;
|
package/src/Query.ts
CHANGED
|
@@ -50,7 +50,7 @@ export interface Query<T> {
|
|
|
50
50
|
// TODO(dmaretskyi): See new effect-schema approach to variance.
|
|
51
51
|
'~Query': { value: T };
|
|
52
52
|
|
|
53
|
-
ast: QueryAST.Query;
|
|
53
|
+
'ast': QueryAST.Query;
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Filter the current selection based on a filter.
|
|
@@ -238,11 +238,11 @@ export type Type<Q extends Any> = Q extends Query<infer T> ? T : never;
|
|
|
238
238
|
class QueryClass implements Any {
|
|
239
239
|
private static 'variance': Any['~Query'] = {} as Any['~Query'];
|
|
240
240
|
|
|
241
|
-
constructor(public readonly ast: QueryAST.Query) {}
|
|
241
|
+
'constructor'(public readonly ast: QueryAST.Query) {}
|
|
242
242
|
|
|
243
243
|
'~Query' = QueryClass.variance;
|
|
244
244
|
|
|
245
|
-
select(filter: Filter.Any | Filter.Props<any>): Any {
|
|
245
|
+
'select'(filter: Filter.Any | Filter.Props<any>): Any {
|
|
246
246
|
if (Filter.is(filter)) {
|
|
247
247
|
return new QueryClass({
|
|
248
248
|
type: 'filter',
|
|
@@ -258,7 +258,7 @@ class QueryClass implements Any {
|
|
|
258
258
|
}
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
reference(key: string): Any {
|
|
261
|
+
'reference'(key: string): Any {
|
|
262
262
|
return new QueryClass({
|
|
263
263
|
type: 'reference-traversal',
|
|
264
264
|
anchor: this.ast,
|
|
@@ -266,7 +266,7 @@ class QueryClass implements Any {
|
|
|
266
266
|
});
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
-
referencedBy(target?: Type$.AnyEntity | URI.URI, key?: string): Any {
|
|
269
|
+
'referencedBy'(target?: Type$.AnyEntity | URI.URI, key?: string): Any {
|
|
270
270
|
const uri = target !== undefined ? internal.getTypeURIFromSpecifier(target) : null;
|
|
271
271
|
return new QueryClass({
|
|
272
272
|
type: 'incoming-references',
|
|
@@ -276,7 +276,7 @@ class QueryClass implements Any {
|
|
|
276
276
|
});
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
-
sourceOf(relation?: Type$.AnyRelation | URI.URI, predicates?: Filter.Props<unknown> | undefined): Any {
|
|
279
|
+
'sourceOf'(relation?: Type$.AnyRelation | URI.URI, predicates?: Filter.Props<unknown> | undefined): Any {
|
|
280
280
|
return new QueryClass({
|
|
281
281
|
type: 'relation',
|
|
282
282
|
anchor: this.ast,
|
|
@@ -285,7 +285,7 @@ class QueryClass implements Any {
|
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
-
targetOf(relation?: Type$.AnyRelation | URI.URI, predicates?: Filter.Props<unknown> | undefined): Any {
|
|
288
|
+
'targetOf'(relation?: Type$.AnyRelation | URI.URI, predicates?: Filter.Props<unknown> | undefined): Any {
|
|
289
289
|
return new QueryClass({
|
|
290
290
|
type: 'relation',
|
|
291
291
|
anchor: this.ast,
|
|
@@ -294,7 +294,7 @@ class QueryClass implements Any {
|
|
|
294
294
|
});
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
source(): Any {
|
|
297
|
+
'source'(): Any {
|
|
298
298
|
return new QueryClass({
|
|
299
299
|
type: 'relation-traversal',
|
|
300
300
|
anchor: this.ast,
|
|
@@ -302,7 +302,7 @@ class QueryClass implements Any {
|
|
|
302
302
|
});
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
target(): Any {
|
|
305
|
+
'target'(): Any {
|
|
306
306
|
return new QueryClass({
|
|
307
307
|
type: 'relation-traversal',
|
|
308
308
|
anchor: this.ast,
|
|
@@ -310,7 +310,7 @@ class QueryClass implements Any {
|
|
|
310
310
|
});
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
parent(): Any {
|
|
313
|
+
'parent'(): Any {
|
|
314
314
|
return new QueryClass({
|
|
315
315
|
type: 'hierarchy-traversal',
|
|
316
316
|
anchor: this.ast,
|
|
@@ -318,7 +318,7 @@ class QueryClass implements Any {
|
|
|
318
318
|
});
|
|
319
319
|
}
|
|
320
320
|
|
|
321
|
-
children(): Any {
|
|
321
|
+
'children'(): Any {
|
|
322
322
|
return new QueryClass({
|
|
323
323
|
type: 'hierarchy-traversal',
|
|
324
324
|
anchor: this.ast,
|
|
@@ -326,7 +326,7 @@ class QueryClass implements Any {
|
|
|
326
326
|
});
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
orderBy(...order: Order.Order<any>[]): Any {
|
|
329
|
+
'orderBy'(...order: Order.Order<any>[]): Any {
|
|
330
330
|
return new QueryClass({
|
|
331
331
|
type: 'order',
|
|
332
332
|
query: this.ast,
|
|
@@ -334,7 +334,7 @@ class QueryClass implements Any {
|
|
|
334
334
|
});
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
-
limit(limit: number): Any {
|
|
337
|
+
'limit'(limit: number): Any {
|
|
338
338
|
return new QueryClass({
|
|
339
339
|
type: 'limit',
|
|
340
340
|
query: this.ast,
|
|
@@ -342,7 +342,7 @@ class QueryClass implements Any {
|
|
|
342
342
|
});
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
-
from(
|
|
345
|
+
'from'(
|
|
346
346
|
...args:
|
|
347
347
|
| [
|
|
348
348
|
(
|
|
@@ -478,7 +478,7 @@ class QueryClass implements Any {
|
|
|
478
478
|
});
|
|
479
479
|
}
|
|
480
480
|
|
|
481
|
-
options(options: QueryAST.QueryOptions): Any {
|
|
481
|
+
'options'(options: QueryAST.QueryOptions): Any {
|
|
482
482
|
return new QueryClass({
|
|
483
483
|
type: 'options',
|
|
484
484
|
query: this.ast,
|
|
@@ -486,7 +486,7 @@ class QueryClass implements Any {
|
|
|
486
486
|
});
|
|
487
487
|
}
|
|
488
488
|
|
|
489
|
-
debugLabel(label: string): Any {
|
|
489
|
+
'debugLabel'(label: string): Any {
|
|
490
490
|
if (this.ast.type === 'options') {
|
|
491
491
|
return new QueryClass({
|
|
492
492
|
type: 'options',
|
package/src/QueryResult.ts
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import type * as Atom from '@effect-atom/atom/Atom';
|
|
6
|
-
import * as Effect from 'effect/Effect';
|
|
7
|
-
import * as Option from 'effect/Option';
|
|
6
|
+
import type * as Effect from 'effect/Effect';
|
|
7
|
+
import type * as Option from 'effect/Option';
|
|
8
8
|
|
|
9
9
|
import { type CleanupFn } from '@dxos/async';
|
|
10
10
|
|
package/src/Ref.ts
CHANGED
|
@@ -15,8 +15,9 @@ import type * as internal from './internal';
|
|
|
15
15
|
import * as refInternal from './internal/Ref';
|
|
16
16
|
import type * as JsonSchema from './JsonSchema';
|
|
17
17
|
import type * as Obj from './Obj';
|
|
18
|
+
import type * as Relation from './Relation';
|
|
18
19
|
// eslint-disable-next-line @dxos/rules/import-as-namespace
|
|
19
|
-
import type * as
|
|
20
|
+
import type * as Type$ from './Type';
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Instance type for a reference.
|
|
@@ -45,17 +46,24 @@ export type Unknown = refInternal.Ref<Obj.Unknown>;
|
|
|
45
46
|
*
|
|
46
47
|
* @example
|
|
47
48
|
* ```ts
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
49
|
+
* class Task extends Type.makeObject<Task>(DXN.make('com.example.type.task', '0.1.0'))(
|
|
50
|
+
* Schema.Struct({
|
|
51
|
+
* assignee: Ref.Ref(Person), // Creates a Ref schema
|
|
52
|
+
* }),
|
|
53
|
+
* ) {}
|
|
51
54
|
* ```
|
|
52
55
|
*/
|
|
53
56
|
export const Ref: {
|
|
54
|
-
<S extends
|
|
57
|
+
<S extends Type$.AnyObj>(type: S): RefSchema<Type$.InstanceType<S> & Obj.Unknown>;
|
|
58
|
+
|
|
59
|
+
// Relations are entities too and can be referenced. The instance type already
|
|
60
|
+
// carries the relation kind brand, so intersect with `Relation.Unknown` (not
|
|
61
|
+
// `Obj.Unknown`, whose object kind brand conflicts and collapses to `never`).
|
|
62
|
+
<S extends Type$.AnyRelation>(type: S): RefSchema<Type$.InstanceType<S> & Relation.Unknown>;
|
|
55
63
|
|
|
56
64
|
// `Type.Type` entities (the meta-schema kind) can be referenced too — e.g. a
|
|
57
65
|
// trigger that points to a stored function/workflow definition.
|
|
58
|
-
<T extends
|
|
66
|
+
<T extends Type$.Type<any>>(type: T): RefSchema<Type$.InstanceType<T>>;
|
|
59
67
|
|
|
60
68
|
// Schema-side overload for the well-known "any object" / "any relation" schemas.
|
|
61
69
|
// Other raw `Schema.Schema` values are intentionally rejected — callers should
|
package/src/Registry.ts
CHANGED
|
@@ -25,7 +25,7 @@ export type TypeId = typeof TypeId;
|
|
|
25
25
|
* A registry may delegate to an optional upstream registry: results from the local
|
|
26
26
|
* registry take precedence and upstream results fill in anything not found locally.
|
|
27
27
|
*
|
|
28
|
-
* Intended use cases include caches of schemas, operations,
|
|
28
|
+
* Intended use cases include caches of schemas, operations, skills, routines, plugins,
|
|
29
29
|
* etc., sourced from 3rd-party plugins, local code, or local space objects.
|
|
30
30
|
*
|
|
31
31
|
* Types (schema-definition entities produced by `Type.makeObject` / `Type.makeRelation`) are
|
package/src/Relation.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { raise } from '@dxos/debug';
|
|
|
10
10
|
import type { ForeignKey } from '@dxos/echo-protocol';
|
|
11
11
|
import { SchemaEx } from '@dxos/effect';
|
|
12
12
|
import { assertArgument, invariant } from '@dxos/invariant';
|
|
13
|
-
import { EID, type EntityId, type URI
|
|
13
|
+
import { DXN, EID, type EntityId, type URI } from '@dxos/keys';
|
|
14
14
|
import { assumeType } from '@dxos/util';
|
|
15
15
|
|
|
16
16
|
import type * as Database from './Database';
|
package/src/Tag.ts
CHANGED
|
@@ -14,30 +14,26 @@ import * as internal from './internal';
|
|
|
14
14
|
import * as Obj from './Obj';
|
|
15
15
|
import * as Type from './Type';
|
|
16
16
|
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
internal.LabelAnnotation.set(['label']),
|
|
22
|
-
|
|
23
|
-
// Shared DXN so `meta.tags` (the `Ref<Tag>` schema) and this type stay in sync.
|
|
24
|
-
Type.makeObject(internal.TagTypeDXN),
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
export type Tag = Type.InstanceType<typeof Tag>;
|
|
17
|
+
export class Tag extends Type.makeObject<Tag>(internal.TagTypeDXN)(
|
|
18
|
+
Schema.Struct({
|
|
19
|
+
label: Schema.String,
|
|
20
|
+
hue: Schema.optional(Schema.String), // TODO(burdon): Color name?
|
|
21
|
+
}).pipe(internal.LabelAnnotation.set(['label']), internal.HiddenAnnotation.set(true)),
|
|
22
|
+
) {}
|
|
28
23
|
|
|
29
24
|
export const make = (props: Obj.MakeProps<typeof Tag>) => Obj.make(Tag, props);
|
|
30
25
|
|
|
31
|
-
export type Map = Record<string, Tag
|
|
26
|
+
export type Map = Record<string, Type.InstanceType<typeof Tag>>;
|
|
32
27
|
|
|
33
|
-
export const sortTags = ({ label: a }: Tag
|
|
28
|
+
export const sortTags = ({ label: a }: Type.InstanceType<typeof Tag>, { label: b }: Type.InstanceType<typeof Tag>) =>
|
|
29
|
+
a.localeCompare(b);
|
|
34
30
|
|
|
35
|
-
export const createTagList = (tags: Map): Tag[] =>
|
|
31
|
+
export const createTagList = (tags: Map): Type.InstanceType<typeof Tag>[] =>
|
|
36
32
|
Object.entries(tags)
|
|
37
33
|
.map(([id, tag]) => ({ ...tag, id }))
|
|
38
34
|
.sort(sortTags);
|
|
39
35
|
|
|
40
|
-
export const findTagByLabel = (tags: Map | undefined, name: string): Tag | undefined => {
|
|
36
|
+
export const findTagByLabel = (tags: Map | undefined, name: string): Type.InstanceType<typeof Tag> | undefined => {
|
|
41
37
|
const entry = Object.entries(tags ?? {}).find(([_, tag]) => tag.label.toLowerCase() === name.toLowerCase());
|
|
42
38
|
return entry ? { ...entry[1], id: entry[0] } : undefined;
|
|
43
39
|
};
|
|
@@ -54,7 +50,7 @@ export const findTagByLabel = (tags: Map | undefined, name: string): Tag | undef
|
|
|
54
50
|
export const findOrCreate = async (
|
|
55
51
|
db: Pick<Database.Database, 'query' | 'add'>,
|
|
56
52
|
options: { label: string; hue?: string; key?: ForeignKey },
|
|
57
|
-
): Promise<Tag
|
|
53
|
+
): Promise<Type.InstanceType<typeof Tag>> => {
|
|
58
54
|
const { label, hue, key } = options;
|
|
59
55
|
const withHue = hue ? { hue } : {};
|
|
60
56
|
if (key) {
|
|
@@ -72,6 +68,7 @@ export const findOrCreate = async (
|
|
|
72
68
|
}
|
|
73
69
|
return existing;
|
|
74
70
|
}
|
|
71
|
+
|
|
75
72
|
return db.add(Obj.make(Tag, { [Obj.Meta]: { keys: [key] }, label, ...withHue }));
|
|
76
73
|
}
|
|
77
74
|
|