@reventlessdev/reventless-core 3.0.0-alpha.196 → 3.0.0-alpha.197

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.197 (2026-08-01)
7
+
8
+ ### Features
9
+
10
+ * **spec:** add DateRange semantic type ([d85b6cc](https://github.com/ReventlessDev/reventless-core/commit/d85b6cc18241644905241df2abd99949dd758059))
11
+
12
+
6
13
  # 3.0.0-alpha.196 (2026-07-31)
7
14
 
8
15
  * feat(rescript)!: one Node bindings package, not two ([1258d8c](https://github.com/ReventlessDev/reventless-core/commit/1258d8c2b2ff2636b36a849fc5bdf9005c6fb0eb))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-core",
3
- "version": "3.0.0-alpha.196",
3
+ "version": "3.0.0-alpha.197",
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-hash-object": "1.2.0-alpha.14",
32
31
  "@reventlessdev/rescript-effect": "0.1.0-alpha.32",
33
- "@reventlessdev/rescript-node": "2.0.0-alpha.0",
34
- "@reventlessdev/rescript-jest": "1.0.0-alpha.10",
35
32
  "@reventlessdev/rescript-fast-csv": "2.0.0-alpha.0",
36
- "@reventlessdev/rescript-ssh2": "2.0.0-alpha.0",
33
+ "@reventlessdev/rescript-hash-object": "1.2.0-alpha.14",
34
+ "@reventlessdev/rescript-jest": "1.0.0-alpha.10",
35
+ "@reventlessdev/rescript-node": "2.0.0-alpha.0",
37
36
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
38
- "@reventlessdev/reventless-infra": "3.0.0-alpha.114",
39
- "@reventlessdev/rescript-uuid": "2.0.0-alpha.0",
40
- "@reventlessdev/reventless-spec": "3.0.0-alpha.89",
41
- "@reventlessdev/reventless-interop": "3.0.0-alpha.30"
37
+ "@reventlessdev/rescript-ssh2": "2.0.0-alpha.0",
38
+ "@reventlessdev/reventless-interop": "3.0.0-alpha.30",
39
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.115",
40
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.90",
41
+ "@reventlessdev/rescript-uuid": "2.0.0-alpha.0"
42
42
  },
43
43
  "devDependencies": {
44
44
  "rescript": "12.3.0",
@@ -742,4 +742,56 @@ describe("SuryToJsonSchema:", () => {
742
742
  ))->toEqual((true, true, true, false))
743
743
  })
744
744
  })
745
+
746
+ // The second composite, and the one whose emission the reader's shape rung
747
+ // depends on. Like `Money` it turns the field into an object — same
748
+ // shape-changed evidence, same upcaster warning for a collapse. Unlike it, the
749
+ // two parts keep their own `dateTime` marker, so a walker that only understands
750
+ // date-times still sees into the composite. That last property is asserted, not
751
+ // described, because it is what lets the UI's primary rung key on the shape
752
+ // before the `dateRange` marker reaches it in a release.
753
+ describe("DateRange is an object whose parts stay date-times:", () => {
754
+ let json = SuryToJsonSchema.deriveObjectSchema(
755
+ S.schema(s =>
756
+ {
757
+ "deliveryWindow": s.matches(Reventless.DateRange.schema),
758
+ "orderedAt": s.matches(Reventless.DateTime.string),
759
+ }
760
+ )->S.castToUnknown,
761
+ )
762
+ let keyOf = (name, key) => getPropertyOf(json, name)->Option.flatMap(s => getProperty(s, key))
763
+
764
+ testSync("the field is an object, not a string", () =>
765
+ expect(keyOf("deliveryWindow", "type"))->toEqual(Some(JSON.Encode.string("object")))
766
+ )
767
+
768
+ testSync("it carries the dateRange id, sourced from the type", () =>
769
+ expect((
770
+ keyOf("deliveryWindow", "x-reventless-semantic"),
771
+ keyOf("deliveryWindow", "x-reventless-semantic-source"),
772
+ ))->toEqual((Some(JSON.Encode.string("dateRange")), Some(JSON.Encode.string("type"))))
773
+ )
774
+
775
+ // The property that is not incidental: each part keeps its own date-time
776
+ // marker under the composite. `dateTime` predates the generic marker and
777
+ // surfaces as `format: "date-time"` (not `x-reventless-semantic`), so that is
778
+ // what a walker reads to see the two instants without knowing about ranges.
779
+ testSync("both instants keep their own date-time marker", () => {
780
+ let inner = getPropertyOf(json, "deliveryWindow")->Option.getOr(JSON.Encode.null)
781
+ expect((
782
+ getPropertyOf(inner, "start")->Option.flatMap(s => getProperty(s, "format")),
783
+ getPropertyOf(inner, "end")->Option.flatMap(s => getProperty(s, "format")),
784
+ ))->toEqual((Some(JSON.Encode.string("date-time")), Some(JSON.Encode.string("date-time"))))
785
+ })
786
+
787
+ // The control, mirroring the `Money` block's plain-float case: a lone
788
+ // date-time field stays a string and never becomes an object, so the
789
+ // object-ness above is the composite's doing and not the walk's.
790
+ testSync("a lone date-time field stays a string", () =>
791
+ expect((keyOf("orderedAt", "type"), keyOf("orderedAt", "format")))->toEqual((
792
+ Some(JSON.Encode.string("string")),
793
+ Some(JSON.Encode.string("date-time")),
794
+ ))
795
+ )
796
+ })
745
797
  })
@@ -11,6 +11,7 @@ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/component
11
11
  import * as Percent$Reventless from "@reventlessdev/reventless-spec/src/semantic/Percent.res.mjs";
12
12
  import * as Currency$Reventless from "@reventlessdev/reventless-spec/src/semantic/Currency.res.mjs";
13
13
  import * as DateTime$Reventless from "@reventlessdev/reventless-spec/src/types/DateTime.res.mjs";
14
+ import * as DateRange$Reventless from "@reventlessdev/reventless-spec/src/semantic/DateRange.res.mjs";
14
15
  import * as Reference$Reventless from "@reventlessdev/reventless-spec/src/components/Reference.res.mjs";
15
16
  import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
16
17
  import * as StateAnnotations$Reventless from "@reventlessdev/reventless-spec/src/components/StateAnnotations.res.mjs";
@@ -1035,6 +1036,44 @@ globalThis.describe("SuryToJsonSchema:", () => {
1035
1036
  ]);
1036
1037
  });
1037
1038
  });
1039
+ globalThis.describe("DateRange is an object whose parts stay date-times:", () => {
1040
+ let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(S.schema(s => ({
1041
+ deliveryWindow: s.m(DateRange$Reventless.schema),
1042
+ orderedAt: s.m(DateTime$Reventless.string)
1043
+ })));
1044
+ let keyOf = (name, key) => Stdlib_Option.flatMap(getPropertyOf(json, name), s => getProperty(s, key));
1045
+ globalThis.test("the field is an object, not a string", () => {
1046
+ globalThis.expect(keyOf("deliveryWindow", "type")).toEqual("object");
1047
+ });
1048
+ globalThis.test("it carries the dateRange id, sourced from the type", () => {
1049
+ globalThis.expect([
1050
+ keyOf("deliveryWindow", "x-reventless-semantic"),
1051
+ keyOf("deliveryWindow", "x-reventless-semantic-source")
1052
+ ]).toEqual([
1053
+ "dateRange",
1054
+ "type"
1055
+ ]);
1056
+ });
1057
+ globalThis.test("both instants keep their own date-time marker", () => {
1058
+ let inner = Stdlib_Option.getOr(getPropertyOf(json, "deliveryWindow"), null);
1059
+ globalThis.expect([
1060
+ Stdlib_Option.flatMap(getPropertyOf(inner, "start"), s => getProperty(s, "format")),
1061
+ Stdlib_Option.flatMap(getPropertyOf(inner, "end"), s => getProperty(s, "format"))
1062
+ ]).toEqual([
1063
+ "date-time",
1064
+ "date-time"
1065
+ ]);
1066
+ });
1067
+ globalThis.test("a lone date-time field stays a string", () => {
1068
+ globalThis.expect([
1069
+ keyOf("orderedAt", "type"),
1070
+ keyOf("orderedAt", "format")
1071
+ ]).toEqual([
1072
+ "string",
1073
+ "date-time"
1074
+ ]);
1075
+ });
1076
+ });
1038
1077
  });
1039
1078
 
1040
1079
  export {