@reventlessdev/reventless-spec 3.0.0-alpha.100
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 +931 -0
- package/LICENSE +202 -0
- package/README.md +109 -0
- package/package.json +49 -0
- package/rescript.json +32 -0
- package/run-generator.mjs +2 -0
- package/run-platform-generator.mjs +2 -0
- package/scripts/generate-currency.mjs +215 -0
- package/scripts/iso-4217-list-one.xml +1956 -0
- package/src/AnsiStyle.res +40 -0
- package/src/AnsiStyle.res.mjs +54 -0
- package/src/LogPrefix.res +192 -0
- package/src/LogPrefix.res.mjs +159 -0
- package/src/PackageVersion.res +67 -0
- package/src/PackageVersion.res.mjs +81 -0
- package/src/components/Aggregate.res +64 -0
- package/src/components/Aggregate.res.mjs +2 -0
- package/src/components/AutomationSlice.res +279 -0
- package/src/components/AutomationSlice.res.mjs +30 -0
- package/src/components/CapabilityManifest.res +74 -0
- package/src/components/CapabilityManifest.res.mjs +61 -0
- package/src/components/ComponentKind.res +99 -0
- package/src/components/ComponentKind.res.mjs +125 -0
- package/src/components/Counter.res +24 -0
- package/src/components/Counter.res.mjs +2 -0
- package/src/components/DcbDecode.res +118 -0
- package/src/components/DcbDecode.res.mjs +100 -0
- package/src/components/DcbScopeInference.res +244 -0
- package/src/components/DcbScopeInference.res.mjs +177 -0
- package/src/components/DcbTag.res +1335 -0
- package/src/components/DcbTag.res.mjs +898 -0
- package/src/components/DcbValidation.res +427 -0
- package/src/components/DcbValidation.res.mjs +423 -0
- package/src/components/DisplayName.res +40 -0
- package/src/components/DisplayName.res.mjs +26 -0
- package/src/components/ExtensionPoint.res +27 -0
- package/src/components/ExtensionPoint.res.mjs +2 -0
- package/src/components/InboundTranslationSlice.res +85 -0
- package/src/components/InboundTranslationSlice.res.mjs +2 -0
- package/src/components/OutboundTranslationSlice.res +153 -0
- package/src/components/OutboundTranslationSlice.res.mjs +2 -0
- package/src/components/Plugin.res +538 -0
- package/src/components/Plugin.res.mjs +264 -0
- package/src/components/PluginName.res +39 -0
- package/src/components/PluginName.res.mjs +45 -0
- package/src/components/ReadModel.res +199 -0
- package/src/components/ReadModel.res.mjs +18 -0
- package/src/components/Reference.res +55 -0
- package/src/components/Reference.res.mjs +50 -0
- package/src/components/Snapshot.res +26 -0
- package/src/components/Snapshot.res.mjs +2 -0
- package/src/components/StateAnnotations.res +97 -0
- package/src/components/StateAnnotations.res.mjs +15 -0
- package/src/components/StateChangeSlice.res +131 -0
- package/src/components/StateChangeSlice.res.mjs +2 -0
- package/src/components/StateViewSlice.res +123 -0
- package/src/components/StateViewSlice.res.mjs +2 -0
- package/src/components/Task.res +62 -0
- package/src/components/Task.res.mjs +2 -0
- package/src/generator/Codegen.res +842 -0
- package/src/generator/Codegen.res.mjs +565 -0
- package/src/generator/Config.res +106 -0
- package/src/generator/Config.res.mjs +69 -0
- package/src/generator/Discovery.res +230 -0
- package/src/generator/Discovery.res.mjs +198 -0
- package/src/generator/Generator_Node.res +14 -0
- package/src/generator/Generator_Node.res.mjs +18 -0
- package/src/generator/Pairing.res +460 -0
- package/src/generator/Pairing.res.mjs +415 -0
- package/src/generator/PlatformCodegen.res +207 -0
- package/src/generator/PlatformCodegen.res.mjs +154 -0
- package/src/generator/PlatformGenerator.res +126 -0
- package/src/generator/PlatformGenerator.res.mjs +114 -0
- package/src/generator/PlatformManifests.res +203 -0
- package/src/generator/PlatformManifests.res.mjs +212 -0
- package/src/generator/PluginGenerator.res +57 -0
- package/src/generator/PluginGenerator.res.mjs +73 -0
- package/src/semantic/Bytes.res +54 -0
- package/src/semantic/Bytes.res.mjs +38 -0
- package/src/semantic/Capabilities.res +43 -0
- package/src/semantic/Capabilities.res.mjs +17 -0
- package/src/semantic/Color.res +51 -0
- package/src/semantic/Color.res.mjs +29 -0
- package/src/semantic/Currency.res +598 -0
- package/src/semantic/Currency.res.mjs +743 -0
- package/src/semantic/DateRange.res +148 -0
- package/src/semantic/DateRange.res.mjs +74 -0
- package/src/semantic/Duration.res +53 -0
- package/src/semantic/Duration.res.mjs +26 -0
- package/src/semantic/Email.res +51 -0
- package/src/semantic/Email.res.mjs +31 -0
- package/src/semantic/GeoPoint.res +226 -0
- package/src/semantic/GeoPoint.res.mjs +190 -0
- package/src/semantic/Geocoding.res +127 -0
- package/src/semantic/Geocoding.res.mjs +36 -0
- package/src/semantic/Money.res +196 -0
- package/src/semantic/Money.res.mjs +138 -0
- package/src/semantic/Offload.res +294 -0
- package/src/semantic/Offload.res.mjs +191 -0
- package/src/semantic/Percent.res +53 -0
- package/src/semantic/Percent.res.mjs +33 -0
- package/src/semantic/Phone.res +55 -0
- package/src/semantic/Phone.res.mjs +29 -0
- package/src/semantic/Semantic.res +162 -0
- package/src/semantic/Semantic.res.mjs +95 -0
- package/src/semantic/StorageRef.res +164 -0
- package/src/semantic/StorageRef.res.mjs +111 -0
- package/src/semantic/Url.res +66 -0
- package/src/semantic/Url.res.mjs +48 -0
- package/src/types/Authorization.res +23 -0
- package/src/types/Authorization.res.mjs +33 -0
- package/src/types/Behavior.res +86 -0
- package/src/types/Behavior.res.mjs +2 -0
- package/src/types/DateTime.res +29 -0
- package/src/types/DateTime.res.mjs +16 -0
- package/src/types/EventMapping.res +100 -0
- package/src/types/EventMapping.res.mjs +15 -0
- package/src/types/Handler.res +30 -0
- package/src/types/Handler.res.mjs +2 -0
- package/src/types/Id.res +75 -0
- package/src/types/Id.res.mjs +37 -0
- package/src/types/Identity.res +46 -0
- package/src/types/Identity.res.mjs +51 -0
- package/src/types/Message.res +326 -0
- package/src/types/Message.res.mjs +186 -0
- package/src/types/Projection.res +220 -0
- package/src/types/Projection.res.mjs +44 -0
- package/src/types/QueryEngine.res +123 -0
- package/src/types/QueryEngine.res.mjs +12 -0
- package/src/types/ReadConsistency.res +38 -0
- package/src/types/ReadConsistency.res.mjs +29 -0
- package/src/types/Schedule.res +65 -0
- package/src/types/Schedule.res.mjs +68 -0
- package/src/types/SideEffect.res +45 -0
- package/src/types/SideEffect.res.mjs +2 -0
- package/src/types/StoredEvent.res +46 -0
- package/src/types/StoredEvent.res.mjs +32 -0
- package/src/types/Visibility.res +24 -0
- package/src/types/Visibility.res.mjs +25 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** ANSI terminal style primitives + sink detection for log output.
|
|
2
|
+
Kept in reventless-spec so both reventless-core (Logger / LogFormat) and
|
|
3
|
+
reventless-infra (compLog in ExtensionMapping/ExtensionPointMapping)
|
|
4
|
+
can share the same styling helpers AND the same sink decision.
|
|
5
|
+
|
|
6
|
+
This is the lowest layer in the logging stack — LogPrefix and Logger
|
|
7
|
+
depend on it, so the sink decision lives here as the single source of
|
|
8
|
+
truth. `useAnsi()` ⇒ TTY text mode (colour/bold); `isJsonSink()` ⇒
|
|
9
|
+
structured JSON for any non-TTY collector (CloudWatch, Datadog, …). */
|
|
10
|
+
|
|
11
|
+
@val external _isTty: option<bool> = "process.stdout.isTTY"
|
|
12
|
+
@val external _logFormat: option<string> = "process.env.REVENTLESS_LOG_FORMAT"
|
|
13
|
+
|
|
14
|
+
// "json" | "text". Explicit REVENTLESS_LOG_FORMAT override always wins; otherwise
|
|
15
|
+
// a TTY stdout ⇒ human-readable text, everything else (Lambda, Fargate, ECS,
|
|
16
|
+
// Azure, GCP, Docker, CI runners, piped stdout) ⇒ structured JSON.
|
|
17
|
+
let _resolveFormat = (): string =>
|
|
18
|
+
switch (_logFormat, _isTty) {
|
|
19
|
+
| (Some("json"), _) => "json"
|
|
20
|
+
| (Some("text"), _) => "text"
|
|
21
|
+
| (_, Some(true)) => "text"
|
|
22
|
+
| _ => "json"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Resolved once at module init; recomputable via `reload()` (test-only — after a
|
|
26
|
+
// test mutates process.env / process.stdout.isTTY). Not a hot path, but caching
|
|
27
|
+
// keeps every log call off `process.env`.
|
|
28
|
+
let _format = ref(_resolveFormat())
|
|
29
|
+
|
|
30
|
+
/** Test-only: re-evaluate REVENTLESS_LOG_FORMAT / process.stdout.isTTY. */
|
|
31
|
+
let reload = () => _format := _resolveFormat()
|
|
32
|
+
|
|
33
|
+
/** True when output should be structured JSON (non-TTY sink). */
|
|
34
|
+
let isJsonSink = () => _format.contents == "json"
|
|
35
|
+
|
|
36
|
+
/** True when output should carry ANSI colour/bold (TTY text mode). */
|
|
37
|
+
let useAnsi = () => _format.contents == "text"
|
|
38
|
+
|
|
39
|
+
/** Wrap a string in ANSI bold escape codes — no-op in a JSON sink. */
|
|
40
|
+
let bold = s => useAnsi() ? `\x1b[1m${s}\x1b[0m` : s
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
function _resolveFormat() {
|
|
5
|
+
let match = process.env.REVENTLESS_LOG_FORMAT;
|
|
6
|
+
let match$1 = process.stdout.isTTY;
|
|
7
|
+
if (match !== undefined) {
|
|
8
|
+
switch (match) {
|
|
9
|
+
case "json" :
|
|
10
|
+
return "json";
|
|
11
|
+
case "text" :
|
|
12
|
+
return "text";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
if (match$1 !== undefined && match$1) {
|
|
16
|
+
return "text";
|
|
17
|
+
} else {
|
|
18
|
+
return "json";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let _format = {
|
|
23
|
+
contents: _resolveFormat()
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function reload() {
|
|
27
|
+
_format.contents = _resolveFormat();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isJsonSink() {
|
|
31
|
+
return _format.contents === "json";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function useAnsi() {
|
|
35
|
+
return _format.contents === "text";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function bold(s) {
|
|
39
|
+
if (_format.contents === "text") {
|
|
40
|
+
return `\x1b[1m` + s + `\x1b[0m`;
|
|
41
|
+
} else {
|
|
42
|
+
return s;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
_resolveFormat,
|
|
48
|
+
_format,
|
|
49
|
+
reload,
|
|
50
|
+
isJsonSink,
|
|
51
|
+
useAnsi,
|
|
52
|
+
bold,
|
|
53
|
+
}
|
|
54
|
+
/* _format Not a pure module */
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/** Plugin-name resolution for log prefixes.
|
|
2
|
+
|
|
3
|
+
Shared between `ReventlessCore.Logger` (terminal/CloudWatch emit) and
|
|
4
|
+
`ReventlessInfra.{ExtensionPoint,Extension}Mapping.compLog` so logs from
|
|
5
|
+
either layer carry the same `[PluginName][Comp]` prefix.
|
|
6
|
+
|
|
7
|
+
Resolution priority for a comp string like `"Kind(Name)"`:
|
|
8
|
+
1. The inner name (e.g. `"AddProduct"`) looked up in `componentPluginRegistry`.
|
|
9
|
+
2. The ambient `currentPluginName` ref (set by `Plugin_Builder.construct`).
|
|
10
|
+
3. Transformations of the inner name, each tried against the registry:
|
|
11
|
+
- strip `@version` suffix (handles `Plugin(Foo@1.2.3)`)
|
|
12
|
+
- strip trailing `Plugin` (handles `CommandTopic(FooPlugin)`)
|
|
13
|
+
- last dot segment (handles `Extension(Catalog.Products.Ordering)`)
|
|
14
|
+
- first dot segment (handles `ExtensionPoint(Catalog.Products)`)
|
|
15
|
+
4. Longest registered component name that prefixes the inner name (handles
|
|
16
|
+
kind-suffixed resource names like `EventCollector(CustomersReadModel)`).
|
|
17
|
+
|
|
18
|
+
`Plugin_Builder` registers every component (and the plugin's self-name) when
|
|
19
|
+
constructing a plugin, so all transformation candidates resolve to a
|
|
20
|
+
real plugin name. */
|
|
21
|
+
|
|
22
|
+
// Ambient plugin name. Set inside `Plugin_Builder.Make.construct` so
|
|
23
|
+
// synchronous logs during construction carry a `[Name]` prefix.
|
|
24
|
+
let currentPluginName: ref<option<string>> = ref(None)
|
|
25
|
+
|
|
26
|
+
// Registry: component name → owning plugin name. Populated at construct time.
|
|
27
|
+
let componentPluginRegistry: ref<dict<string>> = ref(Dict.make())
|
|
28
|
+
|
|
29
|
+
let registerComponentPlugin = (~componentName: string, ~pluginName: string) =>
|
|
30
|
+
componentPluginRegistry.contents->Dict.set(componentName, pluginName)
|
|
31
|
+
|
|
32
|
+
// Stable hash for picking a color from the palette.
|
|
33
|
+
let hashStr = (s: string): int => {
|
|
34
|
+
let h = ref(0)
|
|
35
|
+
for i in 0 to s->String.length - 1 {
|
|
36
|
+
let code = s->String.charCodeAt(i)->Option.getOr(0)
|
|
37
|
+
h := h.contents + code * (i + 1)
|
|
38
|
+
}
|
|
39
|
+
h.contents
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Foreground colors that don't collide with level indicators (cyan / yellow / red).
|
|
43
|
+
let pluginColors = [
|
|
44
|
+
"\x1b[32m", // green
|
|
45
|
+
"\x1b[34m", // blue
|
|
46
|
+
"\x1b[35m", // magenta
|
|
47
|
+
"\x1b[92m", // bright green
|
|
48
|
+
"\x1b[94m", // bright blue
|
|
49
|
+
"\x1b[95m", // bright magenta
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
let pluginColor = (name: string): string =>
|
|
53
|
+
pluginColors->Array.getUnsafe(mod(hashStr(name), pluginColors->Array.length))
|
|
54
|
+
|
|
55
|
+
// Extract the inner argument from a comp like `"Kind(Name)"`.
|
|
56
|
+
let extractInnerName = (comp: string): option<string> => {
|
|
57
|
+
let openIdx = comp->String.indexOf("(")
|
|
58
|
+
let closeIdx = comp->String.lastIndexOf(")")
|
|
59
|
+
if openIdx > 0 && closeIdx > openIdx + 1 {
|
|
60
|
+
Some(comp->String.slice(~start=openIdx + 1, ~end=closeIdx))
|
|
61
|
+
} else {
|
|
62
|
+
None
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let stripAtVersion = (s: string): option<string> => {
|
|
67
|
+
let idx = s->String.indexOf("@")
|
|
68
|
+
if idx > 0 {
|
|
69
|
+
Some(s->String.slice(~start=0, ~end=idx))
|
|
70
|
+
} else {
|
|
71
|
+
None
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let stripPluginSuffix = (s: string): option<string> => {
|
|
76
|
+
let suffix = "Plugin"
|
|
77
|
+
if s->String.endsWith(suffix) && s->String.length > suffix->String.length {
|
|
78
|
+
Some(s->String.slice(~start=0, ~end=s->String.length - suffix->String.length))
|
|
79
|
+
} else {
|
|
80
|
+
None
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let firstDotSegment = (s: string): option<string> => {
|
|
85
|
+
let idx = s->String.indexOf(".")
|
|
86
|
+
if idx > 0 {
|
|
87
|
+
Some(s->String.slice(~start=0, ~end=idx))
|
|
88
|
+
} else {
|
|
89
|
+
None
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
let lastDotSegment = (s: string): option<string> => {
|
|
94
|
+
let idx = s->String.lastIndexOf(".")
|
|
95
|
+
if idx > 0 && idx + 1 < s->String.length {
|
|
96
|
+
Some(s->String.slice(~start=idx + 1, ~end=s->String.length))
|
|
97
|
+
} else {
|
|
98
|
+
None
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let lookup = (name: string): option<string> =>
|
|
103
|
+
componentPluginRegistry.contents->Dict.get(name)
|
|
104
|
+
|
|
105
|
+
// Last-resort candidate: the inner name is a registered component name carrying a
|
|
106
|
+
// component-kind suffix (`Customers` + `ReadModel` → `CustomersReadModel`), which is
|
|
107
|
+
// how event-collector resources are named. Longest prefix wins so `OrdersReadModel`
|
|
108
|
+
// resolves via `Orders` rather than a shorter `Order` registered by another plugin.
|
|
109
|
+
// LogPrefix sits below `ComponentType`, so this stays suffix-table-free.
|
|
110
|
+
let longestRegisteredPrefix = (name: string): option<string> =>
|
|
111
|
+
componentPluginRegistry.contents
|
|
112
|
+
->Dict.keysToArray
|
|
113
|
+
->Array.reduce(None, (acc, key) =>
|
|
114
|
+
if key->String.length < name->String.length && name->String.startsWith(key) {
|
|
115
|
+
switch acc {
|
|
116
|
+
| Some(best) if best->String.length >= key->String.length => acc
|
|
117
|
+
| _ => Some(key)
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
acc
|
|
121
|
+
}
|
|
122
|
+
)
|
|
123
|
+
->Option.flatMap(lookup)
|
|
124
|
+
|
|
125
|
+
let resolvePlugin = (~comp=?, ()) =>
|
|
126
|
+
switch comp {
|
|
127
|
+
| Some(c) =>
|
|
128
|
+
switch extractInnerName(c) {
|
|
129
|
+
| Some(inner) =>
|
|
130
|
+
switch lookup(inner) {
|
|
131
|
+
| Some(p) => Some(p)
|
|
132
|
+
| None =>
|
|
133
|
+
switch currentPluginName.contents {
|
|
134
|
+
| Some(p) => Some(p)
|
|
135
|
+
| None =>
|
|
136
|
+
// Try transformations in declaration order; first hit wins.
|
|
137
|
+
let candidates = [
|
|
138
|
+
stripAtVersion(inner),
|
|
139
|
+
stripPluginSuffix(inner),
|
|
140
|
+
lastDotSegment(inner),
|
|
141
|
+
firstDotSegment(inner),
|
|
142
|
+
]
|
|
143
|
+
candidates
|
|
144
|
+
->Array.reduce(None, (acc, candidate) =>
|
|
145
|
+
switch acc {
|
|
146
|
+
| Some(_) => acc
|
|
147
|
+
| None => candidate->Option.flatMap(lookup)
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
->Option.orElse(longestRegisteredPrefix(inner))
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
| None => currentPluginName.contents
|
|
154
|
+
}
|
|
155
|
+
| None => currentPluginName.contents
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Plain (no ANSI) prefix used for Lambda/CloudWatch output.
|
|
159
|
+
let fmtPlainPrefix = (~comp=?, ()) => {
|
|
160
|
+
let plugin = switch resolvePlugin(~comp?, ()) {
|
|
161
|
+
| Some(p) => `[${p}]`
|
|
162
|
+
| None => ""
|
|
163
|
+
}
|
|
164
|
+
let c = switch comp {
|
|
165
|
+
| Some(c) => `[${c}] `
|
|
166
|
+
| None => ""
|
|
167
|
+
}
|
|
168
|
+
plugin ++ c
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Bold-bracketed prefix used for terminal output.
|
|
172
|
+
// Plugin bracket is colored (foreground) by a stable hash of the plugin name;
|
|
173
|
+
// no trailing space between `[Plugin]` and `[Comp]`.
|
|
174
|
+
//
|
|
175
|
+
// Sink-aware: in a non-TTY/JSON sink it falls back to `fmtPlainPrefix` so no
|
|
176
|
+
// ANSI colour or bold leaks into structured logs. This makes every caller that
|
|
177
|
+
// pre-formats a prefix before reaching `Logger.emit` (EffectLogger.withComp,
|
|
178
|
+
// the infra-layer `compLog`s) correct without per-call-site changes.
|
|
179
|
+
let fmtComp = (~comp=?, ()) =>
|
|
180
|
+
if !AnsiStyle.useAnsi() {
|
|
181
|
+
fmtPlainPrefix(~comp?, ())
|
|
182
|
+
} else {
|
|
183
|
+
let plugin = switch resolvePlugin(~comp?, ()) {
|
|
184
|
+
| Some(p) => `${pluginColor(p)}${AnsiStyle.bold(`[${p}]`)}`
|
|
185
|
+
| None => ""
|
|
186
|
+
}
|
|
187
|
+
let c = switch comp {
|
|
188
|
+
| Some(c) => `${AnsiStyle.bold(`[${c}]`)} `
|
|
189
|
+
| None => ""
|
|
190
|
+
}
|
|
191
|
+
plugin ++ c
|
|
192
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
4
|
+
import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
|
|
5
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
+
import * as Stdlib_String from "@rescript/runtime/lib/es6/Stdlib_String.js";
|
|
7
|
+
import * as AnsiStyle$Reventless from "./AnsiStyle.res.mjs";
|
|
8
|
+
|
|
9
|
+
let currentPluginName = {
|
|
10
|
+
contents: undefined
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
let componentPluginRegistry = {
|
|
14
|
+
contents: {}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function registerComponentPlugin(componentName, pluginName) {
|
|
18
|
+
componentPluginRegistry.contents[componentName] = pluginName;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function hashStr(s) {
|
|
22
|
+
let h = 0;
|
|
23
|
+
for (let i = 0, i_finish = s.length; i < i_finish; ++i) {
|
|
24
|
+
let code = Stdlib_Option.getOr(Stdlib_String.charCodeAt(s, i), 0);
|
|
25
|
+
h = h + (code * (i + 1 | 0) | 0) | 0;
|
|
26
|
+
}
|
|
27
|
+
return h;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let pluginColors = [
|
|
31
|
+
"\x1b[32m",
|
|
32
|
+
"\x1b[34m",
|
|
33
|
+
"\x1b[35m",
|
|
34
|
+
"\x1b[92m",
|
|
35
|
+
"\x1b[94m",
|
|
36
|
+
"\x1b[95m"
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
function pluginColor(name) {
|
|
40
|
+
return pluginColors[Primitive_int.mod_(hashStr(name), pluginColors.length)];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function extractInnerName(comp) {
|
|
44
|
+
let openIdx = comp.indexOf("(");
|
|
45
|
+
let closeIdx = comp.lastIndexOf(")");
|
|
46
|
+
if (openIdx > 0 && closeIdx > (openIdx + 1 | 0)) {
|
|
47
|
+
return comp.slice(openIdx + 1 | 0, closeIdx);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function stripAtVersion(s) {
|
|
52
|
+
let idx = s.indexOf("@");
|
|
53
|
+
if (idx > 0) {
|
|
54
|
+
return s.slice(0, idx);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function stripPluginSuffix(s) {
|
|
59
|
+
let suffix = "Plugin";
|
|
60
|
+
if (s.endsWith(suffix) && s.length > suffix.length) {
|
|
61
|
+
return s.slice(0, s.length - suffix.length | 0);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function firstDotSegment(s) {
|
|
66
|
+
let idx = s.indexOf(".");
|
|
67
|
+
if (idx > 0) {
|
|
68
|
+
return s.slice(0, idx);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function lastDotSegment(s) {
|
|
73
|
+
let idx = s.lastIndexOf(".");
|
|
74
|
+
if (idx > 0 && (idx + 1 | 0) < s.length) {
|
|
75
|
+
return s.slice(idx + 1 | 0, s.length);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function lookup(name) {
|
|
80
|
+
return componentPluginRegistry.contents[name];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function longestRegisteredPrefix(name) {
|
|
84
|
+
return Stdlib_Option.flatMap(Stdlib_Array.reduce(Object.keys(componentPluginRegistry.contents), undefined, (acc, key) => {
|
|
85
|
+
if (key.length < name.length && name.startsWith(key) && !(acc !== undefined && acc.length >= key.length)) {
|
|
86
|
+
return key;
|
|
87
|
+
} else {
|
|
88
|
+
return acc;
|
|
89
|
+
}
|
|
90
|
+
}), lookup);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function resolvePlugin(comp, param) {
|
|
94
|
+
if (comp === undefined) {
|
|
95
|
+
return currentPluginName.contents;
|
|
96
|
+
}
|
|
97
|
+
let inner = extractInnerName(comp);
|
|
98
|
+
if (inner === undefined) {
|
|
99
|
+
return currentPluginName.contents;
|
|
100
|
+
}
|
|
101
|
+
let p = componentPluginRegistry.contents[inner];
|
|
102
|
+
if (p !== undefined) {
|
|
103
|
+
return p;
|
|
104
|
+
}
|
|
105
|
+
let p$1 = currentPluginName.contents;
|
|
106
|
+
if (p$1 !== undefined) {
|
|
107
|
+
return p$1;
|
|
108
|
+
}
|
|
109
|
+
let candidates = [
|
|
110
|
+
stripAtVersion(inner),
|
|
111
|
+
stripPluginSuffix(inner),
|
|
112
|
+
lastDotSegment(inner),
|
|
113
|
+
firstDotSegment(inner)
|
|
114
|
+
];
|
|
115
|
+
return Stdlib_Option.orElse(Stdlib_Array.reduce(candidates, undefined, (acc, candidate) => {
|
|
116
|
+
if (acc !== undefined) {
|
|
117
|
+
return acc;
|
|
118
|
+
} else {
|
|
119
|
+
return Stdlib_Option.flatMap(candidate, lookup);
|
|
120
|
+
}
|
|
121
|
+
}), longestRegisteredPrefix(inner));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function fmtPlainPrefix(comp, param) {
|
|
125
|
+
let p = resolvePlugin(comp, undefined);
|
|
126
|
+
let plugin = p !== undefined ? `[` + p + `]` : "";
|
|
127
|
+
let c = comp !== undefined ? `[` + comp + `] ` : "";
|
|
128
|
+
return plugin + c;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function fmtComp(comp, param) {
|
|
132
|
+
if (!AnsiStyle$Reventless.useAnsi()) {
|
|
133
|
+
return fmtPlainPrefix(comp, undefined);
|
|
134
|
+
}
|
|
135
|
+
let p = resolvePlugin(comp, undefined);
|
|
136
|
+
let plugin = p !== undefined ? pluginColor(p) + AnsiStyle$Reventless.bold(`[` + p + `]`) : "";
|
|
137
|
+
let c = comp !== undefined ? AnsiStyle$Reventless.bold(`[` + comp + `]`) + ` ` : "";
|
|
138
|
+
return plugin + c;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
currentPluginName,
|
|
143
|
+
componentPluginRegistry,
|
|
144
|
+
registerComponentPlugin,
|
|
145
|
+
hashStr,
|
|
146
|
+
pluginColors,
|
|
147
|
+
pluginColor,
|
|
148
|
+
extractInnerName,
|
|
149
|
+
stripAtVersion,
|
|
150
|
+
stripPluginSuffix,
|
|
151
|
+
firstDotSegment,
|
|
152
|
+
lastDotSegment,
|
|
153
|
+
lookup,
|
|
154
|
+
longestRegisteredPrefix,
|
|
155
|
+
resolvePlugin,
|
|
156
|
+
fmtPlainPrefix,
|
|
157
|
+
fmtComp,
|
|
158
|
+
}
|
|
159
|
+
/* AnsiStyle-Reventless Not a pure module */
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
let readVersion = (path: string) =>
|
|
2
|
+
NodeFs.readFileSync(path)
|
|
3
|
+
->JSON.parseOrThrow
|
|
4
|
+
->JSON.Decode.object
|
|
5
|
+
->Option.flatMap(o => o->Dict.get("version"))
|
|
6
|
+
->Option.flatMap(JSON.Decode.string)
|
|
7
|
+
->Option.getOr("0.0.0")
|
|
8
|
+
|
|
9
|
+
let fromCwd = () => readVersion("./package.json")
|
|
10
|
+
|
|
11
|
+
let findVersion = dir => {
|
|
12
|
+
let rec find = dir => {
|
|
13
|
+
let candidate = NodePath.join([dir, "package.json"])
|
|
14
|
+
if NodeFs.existsSync(candidate) {
|
|
15
|
+
readVersion(candidate)
|
|
16
|
+
} else {
|
|
17
|
+
let parent = NodePath.dirname(dir)
|
|
18
|
+
if parent == dir {
|
|
19
|
+
"0.0.0"
|
|
20
|
+
} else {
|
|
21
|
+
find(parent)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
find(dir)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let fromModuleUrl = (url: string) => findVersion(url->NodeUrl.fileURLToPath->NodePath.dirname)
|
|
29
|
+
|
|
30
|
+
/** Detect the caller's file via V8 Structured Stack Trace API and read the
|
|
31
|
+
version from the nearest package.json. Skips frames from framework packages
|
|
32
|
+
(reventless-spec, reventless-core, reventless-infra, reventless-local,
|
|
33
|
+
reventless-aws, reventless-interop). Falls back to CWD's package.json. */
|
|
34
|
+
let callerFile: unit => option<string> = %raw(`
|
|
35
|
+
function() {
|
|
36
|
+
var frameworkMarkers = [
|
|
37
|
+
'/reventless/',
|
|
38
|
+
'/@reventlessdev/reventless-',
|
|
39
|
+
];
|
|
40
|
+
var oldPrepare = Error.prepareStackTrace;
|
|
41
|
+
Error.prepareStackTrace = function(_, stack) { return stack; };
|
|
42
|
+
var err = new Error();
|
|
43
|
+
var stack = err.stack;
|
|
44
|
+
Error.prepareStackTrace = oldPrepare;
|
|
45
|
+
for (var i = 0; i < stack.length; i++) {
|
|
46
|
+
var file = stack[i].getFileName();
|
|
47
|
+
if (!file) continue;
|
|
48
|
+
var isFramework = false;
|
|
49
|
+
for (var j = 0; j < frameworkMarkers.length; j++) {
|
|
50
|
+
if (file.indexOf(frameworkMarkers[j]) !== -1) { isFramework = true; break; }
|
|
51
|
+
}
|
|
52
|
+
if (!isFramework) return file;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
`)
|
|
57
|
+
|
|
58
|
+
let fromCaller = () =>
|
|
59
|
+
switch callerFile() {
|
|
60
|
+
| Some(file) =>
|
|
61
|
+
if file->String.startsWith("file://") {
|
|
62
|
+
findVersion(file->NodeUrl.fileURLToPath->NodePath.dirname)
|
|
63
|
+
} else {
|
|
64
|
+
findVersion(file->NodePath.dirname)
|
|
65
|
+
}
|
|
66
|
+
| None => fromCwd()
|
|
67
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Nodefs from "node:fs";
|
|
4
|
+
import * as Nodeurl from "node:url";
|
|
5
|
+
import * as Nodepath from "node:path";
|
|
6
|
+
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
7
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
8
|
+
|
|
9
|
+
function readVersion(path) {
|
|
10
|
+
return Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(JSON.parse(Nodefs.readFileSync(path, "utf8"))), o => o["version"]), Stdlib_JSON.Decode.string), "0.0.0");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function fromCwd() {
|
|
14
|
+
return readVersion("./package.json");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function findVersion(dir) {
|
|
18
|
+
let _dir = dir;
|
|
19
|
+
while (true) {
|
|
20
|
+
let dir$1 = _dir;
|
|
21
|
+
let candidate = Nodepath.join(dir$1, "package.json");
|
|
22
|
+
if (Nodefs.existsSync(candidate)) {
|
|
23
|
+
return readVersion(candidate);
|
|
24
|
+
}
|
|
25
|
+
let parent = Nodepath.dirname(dir$1);
|
|
26
|
+
if (parent === dir$1) {
|
|
27
|
+
return "0.0.0";
|
|
28
|
+
}
|
|
29
|
+
_dir = parent;
|
|
30
|
+
continue;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function fromModuleUrl(url) {
|
|
35
|
+
return findVersion(Nodepath.dirname(Nodeurl.fileURLToPath(url)));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let callerFile = (function() {
|
|
39
|
+
var frameworkMarkers = [
|
|
40
|
+
'/reventless/',
|
|
41
|
+
'/@reventlessdev/reventless-',
|
|
42
|
+
];
|
|
43
|
+
var oldPrepare = Error.prepareStackTrace;
|
|
44
|
+
Error.prepareStackTrace = function(_, stack) { return stack; };
|
|
45
|
+
var err = new Error();
|
|
46
|
+
var stack = err.stack;
|
|
47
|
+
Error.prepareStackTrace = oldPrepare;
|
|
48
|
+
for (var i = 0; i < stack.length; i++) {
|
|
49
|
+
var file = stack[i].getFileName();
|
|
50
|
+
if (!file) continue;
|
|
51
|
+
var isFramework = false;
|
|
52
|
+
for (var j = 0; j < frameworkMarkers.length; j++) {
|
|
53
|
+
if (file.indexOf(frameworkMarkers[j]) !== -1) { isFramework = true; break; }
|
|
54
|
+
}
|
|
55
|
+
if (!isFramework) return file;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
function fromCaller() {
|
|
61
|
+
let file = callerFile();
|
|
62
|
+
if (file !== undefined) {
|
|
63
|
+
if (file.startsWith("file://")) {
|
|
64
|
+
return findVersion(Nodepath.dirname(Nodeurl.fileURLToPath(file)));
|
|
65
|
+
} else {
|
|
66
|
+
return findVersion(Nodepath.dirname(file));
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
return readVersion("./package.json");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
readVersion,
|
|
75
|
+
fromCwd,
|
|
76
|
+
findVersion,
|
|
77
|
+
fromModuleUrl,
|
|
78
|
+
callerFile,
|
|
79
|
+
fromCaller,
|
|
80
|
+
}
|
|
81
|
+
/* node:fs Not a pure module */
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Module type for an aggregate's identity and schema specification.
|
|
3
|
+
|
|
4
|
+
Every aggregate defines a `Spec` module satisfying this type. The `Spec` is
|
|
5
|
+
used by `Platform.Aggregate.Make` and by `Behavior.T` to fix the aggregate's
|
|
6
|
+
command, event, and error types.
|
|
7
|
+
|
|
8
|
+
@example
|
|
9
|
+
```rescript
|
|
10
|
+
// Category.res
|
|
11
|
+
module Id = Id.String
|
|
12
|
+
let name = "Category"
|
|
13
|
+
|
|
14
|
+
@schema
|
|
15
|
+
type command =
|
|
16
|
+
| AddCategory({categoryId: string, name: string})
|
|
17
|
+
| RenameCategory({categoryId: string, name: string})
|
|
18
|
+
| ArchiveCategory({categoryId: string})
|
|
19
|
+
|
|
20
|
+
@schema
|
|
21
|
+
type event =
|
|
22
|
+
| CategoryAdded({categoryId: string, name: string})
|
|
23
|
+
| CategoryRenamed({categoryId: string, name: string})
|
|
24
|
+
| CategoryArchived({categoryId: string})
|
|
25
|
+
|
|
26
|
+
@schema
|
|
27
|
+
type error =
|
|
28
|
+
| CategoryAlreadyExists
|
|
29
|
+
| CategoryNotFound
|
|
30
|
+
| CategoryAlreadyArchived
|
|
31
|
+
```
|
|
32
|
+
*/
|
|
33
|
+
module type Spec = {
|
|
34
|
+
module Id: Id.T
|
|
35
|
+
|
|
36
|
+
/** Logical aggregate name used as a prefix for infrastructure resource names. */
|
|
37
|
+
let name: string
|
|
38
|
+
|
|
39
|
+
/** Commands this aggregate accepts. Must carry `@schema`. */
|
|
40
|
+
@schema
|
|
41
|
+
type command
|
|
42
|
+
|
|
43
|
+
/** Events this aggregate emits. Must carry `@schema`. */
|
|
44
|
+
@schema
|
|
45
|
+
type event
|
|
46
|
+
|
|
47
|
+
/** Business rule violation errors. Must carry `@schema`. */
|
|
48
|
+
@schema
|
|
49
|
+
type error
|
|
50
|
+
|
|
51
|
+
/** Sury schema for the command type — generated automatically by `@schema`. */
|
|
52
|
+
let commandSchema: S.t<command>
|
|
53
|
+
|
|
54
|
+
/** File URL of this module (`import.meta.url`). Used by AWS builders to derive
|
|
55
|
+
the npm specifier for runtime dynamic imports. */
|
|
56
|
+
let moduleUrl: string
|
|
57
|
+
|
|
58
|
+
/** Authorization rule evaluated at the GraphQL resolver entry before any
|
|
59
|
+
command is dispatched. Auto-injected by `@@reventless.spec` and on
|
|
60
|
+
structurally-detected inline spec modules — defaults to
|
|
61
|
+
`AllowAuthenticated`; override at the file/module level with
|
|
62
|
+
`@@reventless.authorize(<rule>)`. */
|
|
63
|
+
let commandAuthorization: command => Authorization.permission
|
|
64
|
+
}
|