@reventlessdev/reventless-core 3.0.0-alpha.192 → 3.0.0-alpha.193
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.193 (2026-07-30)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **spec:** semantic branded scalars — Email, Url, Phone, Percent, Color, Bytes, Duration ([2e64ff9](https://github.com/ReventlessDev/reventless-core/commit/2e64ff992e913c038a71659c731c25a104e3c5a9))
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
# 3.0.0-alpha.192 (2026-07-30)
|
|
7
14
|
|
|
8
15
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-core",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.193",
|
|
4
4
|
"description": "Core package for Reventless framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -28,17 +28,17 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"sury": "11.0.0-alpha.4",
|
|
30
30
|
"uuid": "^13.0.0",
|
|
31
|
-
"@reventlessdev/rescript-fast-csv": "1.2.0-alpha.14",
|
|
32
31
|
"@reventlessdev/rescript-hash-object": "1.2.0-alpha.13",
|
|
33
32
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.31",
|
|
34
|
-
"@reventlessdev/rescript-
|
|
33
|
+
"@reventlessdev/rescript-fast-csv": "1.2.0-alpha.14",
|
|
35
34
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.9",
|
|
35
|
+
"@reventlessdev/rescript-node-streams": "1.1.0-alpha.13",
|
|
36
36
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.17",
|
|
37
37
|
"@reventlessdev/rescript-ssh2": "1.1.0-alpha.14",
|
|
38
38
|
"@reventlessdev/rescript-uuid": "1.1.0-alpha.17",
|
|
39
|
-
"@reventlessdev/reventless-infra": "3.0.0-alpha.
|
|
40
|
-
"@reventlessdev/reventless-
|
|
41
|
-
"@reventlessdev/reventless-
|
|
39
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.111",
|
|
40
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.86",
|
|
41
|
+
"@reventlessdev/reventless-interop": "3.0.0-alpha.29"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"rescript": "12.3.0",
|
|
@@ -619,4 +619,46 @@ describe("SuryToJsonSchema:", () => {
|
|
|
619
619
|
expect(semanticOf(json, "imageUrl"))->toEqual(Some(JSON.Encode.string("storageRef")))
|
|
620
620
|
})
|
|
621
621
|
})
|
|
622
|
+
|
|
623
|
+
// The claim the branded scalars rest on: marking a field adds an annotation,
|
|
624
|
+
// not a shape. A string stays a string and a number stays a number on the
|
|
625
|
+
// wire, which is what makes them retrofittable onto a log that already has
|
|
626
|
+
// events in it. One of each is enough — the emission path is the same for all
|
|
627
|
+
// seven, and it is the *shape* half that is the load-bearing assertion here.
|
|
628
|
+
describe("branded scalars keep their underlying shape:", () => {
|
|
629
|
+
let fieldOf = (json, name) => getPropertyOf(json, name)
|
|
630
|
+
let keyOf = (json, name, key) => fieldOf(json, name)->Option.flatMap(s => getProperty(s, key))
|
|
631
|
+
|
|
632
|
+
let json = SuryToJsonSchema.deriveObjectSchema(
|
|
633
|
+
S.schema(s =>
|
|
634
|
+
{
|
|
635
|
+
"contactEmail": s.matches(Reventless.Email.schema),
|
|
636
|
+
"taxRate": s.matches(Reventless.Percent.schema),
|
|
637
|
+
}
|
|
638
|
+
)->S.castToUnknown,
|
|
639
|
+
)
|
|
640
|
+
|
|
641
|
+
testSync("a string scalar stays a string and carries its id", () =>
|
|
642
|
+
expect((
|
|
643
|
+
keyOf(json, "contactEmail", "type"),
|
|
644
|
+
keyOf(json, "contactEmail", "x-reventless-semantic"),
|
|
645
|
+
))->toEqual((Some(JSON.Encode.string("string")), Some(JSON.Encode.string("email"))))
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
testSync("a numeric scalar stays a number and carries its id", () =>
|
|
649
|
+
expect((
|
|
650
|
+
keyOf(json, "taxRate", "type"),
|
|
651
|
+
keyOf(json, "taxRate", "x-reventless-semantic"),
|
|
652
|
+
))->toEqual((Some(JSON.Encode.string("number")), Some(JSON.Encode.string("percent"))))
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
// The provenance half: a typed field outranks an annotated one, and this is
|
|
656
|
+
// the key a consumer reads to tell them apart.
|
|
657
|
+
testSync("both name the type as their source", () =>
|
|
658
|
+
expect((
|
|
659
|
+
keyOf(json, "contactEmail", "x-reventless-semantic-source"),
|
|
660
|
+
keyOf(json, "taxRate", "x-reventless-semantic-source"),
|
|
661
|
+
))->toEqual((Some(JSON.Encode.string("type")), Some(JSON.Encode.string("type"))))
|
|
662
|
+
)
|
|
663
|
+
})
|
|
622
664
|
})
|
|
@@ -4,8 +4,10 @@ import * as S from "sury/src/S.res.mjs";
|
|
|
4
4
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
5
5
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
6
6
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
|
+
import * as Email$Reventless from "@reventlessdev/reventless-spec/src/semantic/Email.res.mjs";
|
|
7
8
|
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
8
9
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
10
|
+
import * as Percent$Reventless from "@reventlessdev/reventless-spec/src/semantic/Percent.res.mjs";
|
|
9
11
|
import * as DateTime$Reventless from "@reventlessdev/reventless-spec/src/types/DateTime.res.mjs";
|
|
10
12
|
import * as Reference$Reventless from "@reventlessdev/reventless-spec/src/components/Reference.res.mjs";
|
|
11
13
|
import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
|
|
@@ -937,6 +939,40 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
937
939
|
globalThis.expect(semanticOf(json, "imageUrl")).toEqual("storageRef");
|
|
938
940
|
});
|
|
939
941
|
});
|
|
942
|
+
globalThis.describe("branded scalars keep their underlying shape:", () => {
|
|
943
|
+
let keyOf = (json, name, key) => Stdlib_Option.flatMap(getPropertyOf(json, name), s => getProperty(s, key));
|
|
944
|
+
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(S.schema(s => ({
|
|
945
|
+
contactEmail: s.m(Email$Reventless.schema),
|
|
946
|
+
taxRate: s.m(Percent$Reventless.schema)
|
|
947
|
+
})));
|
|
948
|
+
globalThis.test("a string scalar stays a string and carries its id", () => {
|
|
949
|
+
globalThis.expect([
|
|
950
|
+
keyOf(json, "contactEmail", "type"),
|
|
951
|
+
keyOf(json, "contactEmail", "x-reventless-semantic")
|
|
952
|
+
]).toEqual([
|
|
953
|
+
"string",
|
|
954
|
+
"email"
|
|
955
|
+
]);
|
|
956
|
+
});
|
|
957
|
+
globalThis.test("a numeric scalar stays a number and carries its id", () => {
|
|
958
|
+
globalThis.expect([
|
|
959
|
+
keyOf(json, "taxRate", "type"),
|
|
960
|
+
keyOf(json, "taxRate", "x-reventless-semantic")
|
|
961
|
+
]).toEqual([
|
|
962
|
+
"number",
|
|
963
|
+
"percent"
|
|
964
|
+
]);
|
|
965
|
+
});
|
|
966
|
+
globalThis.test("both name the type as their source", () => {
|
|
967
|
+
globalThis.expect([
|
|
968
|
+
keyOf(json, "contactEmail", "x-reventless-semantic-source"),
|
|
969
|
+
keyOf(json, "taxRate", "x-reventless-semantic-source")
|
|
970
|
+
]).toEqual([
|
|
971
|
+
"type",
|
|
972
|
+
"type"
|
|
973
|
+
]);
|
|
974
|
+
});
|
|
975
|
+
});
|
|
940
976
|
});
|
|
941
977
|
|
|
942
978
|
export {
|