@effect-app/vue 2.67.7 → 2.69.0

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.
@@ -74,22 +74,25 @@ export declare namespace Commander {
74
74
  new(): {}
75
75
 
76
76
  /** click handlers */
77
- handle: (...args: Args) => RuntimeFiber<Exit.Exit<A, E>, never>
78
-
79
- // TODO: if we keep them, it would probably be nicer as an option api, deciding the return value like in Atom?
80
- /** @experimental */
81
- compose: (...args: Args) => Effect.Effect<Exit.Exit<A, E>, R>
82
- /** @experimental */
83
- compose2: (...args: Args) => Effect.Effect<A, E, R>
84
- /**
85
- * @experimental
86
- * captures the current span and returns an Effect that when run will execute the command
87
- */
88
- handleEffect: (...args: Args) => Effect.Effect<RuntimeFiber<Exit.Exit<A, E>, never>>
89
- /**
90
- * @experimental
91
- */
92
- exec: (...args: Args) => Effect.Effect<Exit.Exit<A, E>, never, Exclude<R, CommandContext>>
77
+ handle: ((...args: Args) => RuntimeFiber<Exit.Exit<A, E>, never>) & {
78
+ effect: (...args: Args) => Effect.Effect<A, E, R>
79
+ promise: (...args: Args) => Promise<A>
80
+ }
81
+
82
+ // // TODO: if we keep them, it would probably be nicer as an option api, deciding the return value like in Atom?
83
+ // /** @experimental */
84
+ // compose: (...args: Args) => Effect.Effect<Exit.Exit<A, E>, R>
85
+ // /** @experimental */
86
+ // compose2: (...args: Args) => Effect.Effect<A, E, R>
87
+ // /**
88
+ // * @experimental
89
+ // * captures the current span and returns an Effect that when run will execute the command
90
+ // */
91
+ // handleEffect: (...args: Args) => Effect.Effect<RuntimeFiber<Exit.Exit<A, E>, never>>
92
+ // /**
93
+ // * @experimental
94
+ // */
95
+ // exec: (...args: Args) => Effect.Effect<Exit.Exit<A, E>, never, Exclude<R, CommandContext>>
93
96
  }
94
97
 
95
98
  type CommandOutHelper<Args extends Array<unknown>, Eff extends Effect.Effect<any, any, any>, Id extends string> =
@@ -751,13 +754,160 @@ export declare namespace Commander {
751
754
 
752
755
  type ErrorRenderer<E, Args extends readonly any[]> = (e: E, action: string, ...args: Args) => string | undefined
753
756
 
757
+ const renderErrorMaker = I18n.use(
758
+ ({ intl }) =>
759
+ <E, Args extends readonly any[]>(action: string, errorRenderer?: ErrorRenderer<E, Args>) =>
760
+ (e: E, ...args: Args): string => {
761
+ if (errorRenderer) {
762
+ const m = errorRenderer(e, action, ...args)
763
+ if (m) {
764
+ return m
765
+ }
766
+ }
767
+ if (!S.is(SupportedErrors)(e) && !S.ParseResult.isParseError(e)) {
768
+ if (typeof e === "object" && e !== null) {
769
+ if ("message" in e) {
770
+ return `${e.message}`
771
+ }
772
+ if ("_tag" in e) {
773
+ return `${e._tag}`
774
+ }
775
+ }
776
+ return ""
777
+ }
778
+ const e2: SupportedErrors | S.ParseResult.ParseError = e
779
+ return Match.value(e2).pipe(
780
+ Match.tags({
781
+ ParseError: (e) => {
782
+ console.warn(e.toString())
783
+ return intl.formatMessage({ id: "validation.failed" })
784
+ }
785
+ }),
786
+ Match.orElse((e) => `${e.message ?? e._tag ?? e}`)
787
+ )
788
+ }
789
+ )
790
+
791
+ const defaultFailureMessageHandler = <E, Args extends Array<unknown>, AME, AMR>(
792
+ actionMaker:
793
+ | string
794
+ | ((o: Option.Option<E>, ...args: Args) => string)
795
+ | ((o: Option.Option<E>, ...args: Args) => Effect.Effect<string, AME, AMR>),
796
+ errorRenderer?: ErrorRenderer<E, Args>
797
+ ) =>
798
+ Effect.fnUntraced(function*(o: Option.Option<E>, ...args: Args) {
799
+ const action = yield* wrapEffect(actionMaker)(o, ...args)
800
+ const { intl } = yield* I18n
801
+ const renderError = yield* renderErrorMaker
802
+
803
+ return Option.match(o, {
804
+ onNone: () =>
805
+ intl.formatMessage(
806
+ { id: "handle.unexpected_error2" },
807
+ {
808
+ action,
809
+ error: "" // TODO consider again Cause.pretty(cause), // will be reported to Sentry/Otel anyway.. and we shouldn't bother users with error dumps?
810
+ }
811
+ ),
812
+ onSome: (e) =>
813
+ S.is(OperationFailure)(e)
814
+ ? {
815
+ level: "warn" as const,
816
+ message: intl.formatMessage(
817
+ { id: "handle.with_warnings" },
818
+ { action }
819
+ ) + e.message
820
+ ? "\n" + e.message
821
+ : ""
822
+ }
823
+ : `${
824
+ intl.formatMessage(
825
+ { id: "handle.with_errors" },
826
+ { action }
827
+ )
828
+ }:\n` + renderError(action, errorRenderer)(e, ...args)
829
+ })
830
+ })
831
+
832
+ export const CommanderStatic = {
833
+ /** Version of @see confirmOrInterrupt that automatically includes the action name in the default messages */
834
+ confirmOrInterrupt: Effect.fnUntraced(function*(
835
+ message: string | undefined = undefined
836
+ ) {
837
+ const context = yield* CommandContext
838
+ const { intl } = yield* I18n
839
+
840
+ yield* Confirm.confirmOrInterrupt(
841
+ message
842
+ ?? intl.formatMessage(
843
+ { id: "handle.confirmation" },
844
+ { action: context.action }
845
+ )
846
+ )
847
+ }),
848
+ /** Version of @see confirm that automatically includes the action name in the default messages */
849
+ confirm: Effect.fnUntraced(function*(
850
+ message: string | undefined = undefined
851
+ ) {
852
+ const context = yield* CommandContext
853
+ const { intl } = yield* I18n
854
+ return yield* Confirm.confirm(
855
+ message
856
+ ?? intl.formatMessage(
857
+ { id: "handle.confirmation" },
858
+ { action: context.action }
859
+ )
860
+ )
861
+ }),
862
+ updateAction:
863
+ <Args extends Array<unknown>>(update: (currentActionId: string, ...args: Args) => string) =>
864
+ <A, E, R>(_: Effect.Effect<A, E, R>, ...input: Args) =>
865
+ Effect.updateService(
866
+ _,
867
+ CommandContext,
868
+ (c) => ({ ...c, action: update(c.action, ...input) })
869
+ ),
870
+ defaultFailureMessageHandler,
871
+ renderError: renderErrorMaker,
872
+ /** Version of withDefaultToast that automatically includes the action name in the default messages and uses intl */
873
+ withDefaultToast: <A, E, R, Args extends Array<unknown>>(
874
+ options?: {
875
+ errorRenderer?: ErrorRenderer<E, Args>
876
+ onWaiting?: null | undefined | string | ((action: string, ...args: Args) => string | null | undefined)
877
+ onSuccess?: null | undefined | string | ((a: A, action: string, ...args: Args) => string | null | undefined)
878
+ }
879
+ ) =>
880
+ (
881
+ self: Effect.Effect<A, E, R>,
882
+ ...args: Args
883
+ ) =>
884
+ Effect.gen(function*() {
885
+ const cc = yield* CommandContext
886
+ const { intl } = yield* I18n
887
+ const withToast = yield* WithToast
888
+ return yield* self.pipe(
889
+ (_) =>
890
+ withToast<A, E, Args, R, never, never, I18n>({
891
+ onWaiting: options?.onWaiting === null ? null : intl.formatMessage(
892
+ { id: "handle.waiting" },
893
+ { action: cc.action }
894
+ ),
895
+ onSuccess: options?.onSuccess === null
896
+ ? null
897
+ : (a, ..._args) =>
898
+ intl.formatMessage({ id: "handle.success" }, { action: cc.action })
899
+ + (S.is(OperationSuccess)(a) && a.message ? "\n" + a.message : ""),
900
+ onFailure: defaultFailureMessageHandler(cc.action, options?.errorRenderer)
901
+ })(_, ...args)
902
+ )
903
+ })
904
+ }
905
+
754
906
  // @effect-diagnostics-next-line missingEffectServiceDependency:off
755
907
  export class Commander extends Effect.Service<Commander>()("Commander", {
756
908
  dependencies: [WithToast.Default, Confirm.Default],
757
909
  effect: Effect.gen(function*() {
758
910
  const { intl } = yield* I18n
759
- const withToast = yield* WithToast
760
- const { confirm, confirmOrInterrupt } = yield* Confirm
761
911
 
762
912
  const makeContext = <Id extends string>(id: Id) => {
763
913
  if (!id) throw new Error("must specify an id")
@@ -1025,196 +1175,57 @@ export class Commander extends Effect.Service<Commander>()("Commander", {
1025
1175
  }
1026
1176
  }
1027
1177
 
1028
- const renderError =
1029
- <E, Args extends readonly any[]>(action: string, errorRenderer?: ErrorRenderer<E, Args>) =>
1030
- (e: E, ...args: Args): string => {
1031
- if (errorRenderer) {
1032
- const m = errorRenderer(e, action, ...args)
1033
- if (m) {
1034
- return m
1035
- }
1036
- }
1037
- if (!S.is(SupportedErrors)(e) && !S.ParseResult.isParseError(e)) {
1038
- if (typeof e === "object" && e !== null) {
1039
- if ("message" in e) {
1040
- return `${e.message}`
1041
- }
1042
- if ("_tag" in e) {
1043
- return `${e._tag}`
1044
- }
1045
- }
1046
- return ""
1047
- }
1048
- const e2: SupportedErrors | S.ParseResult.ParseError = e
1049
- return Match.value(e2).pipe(
1050
- Match.tags({
1051
- ParseError: (e) => {
1052
- console.warn(e.toString())
1053
- return intl.formatMessage({ id: "validation.failed" })
1054
- }
1055
- }),
1056
- Match.orElse((e) => `${e.message ?? e._tag ?? e}`)
1057
- )
1058
- }
1059
-
1060
- const defaultFailureMessageHandler = <E, Args extends Array<unknown>, AME, AMR>(
1061
- actionMaker:
1062
- | string
1063
- | ((o: Option.Option<E>, ...args: Args) => string)
1064
- | ((o: Option.Option<E>, ...args: Args) => Effect.Effect<string, AME, AMR>),
1065
- errorRenderer?: ErrorRenderer<E, Args>
1066
- ) =>
1067
- Effect.fnUntraced(function*(o: Option.Option<E>, ...args: Args) {
1068
- const action = yield* wrapEffect(actionMaker)(o, ...args)
1069
-
1070
- return Option.match(o, {
1071
- onNone: () =>
1072
- intl.formatMessage(
1073
- { id: "handle.unexpected_error2" },
1074
- {
1075
- action,
1076
- error: "" // TODO consider again Cause.pretty(cause), // will be reported to Sentry/Otel anyway.. and we shouldn't bother users with error dumps?
1077
- }
1078
- ),
1079
- onSome: (e) =>
1080
- S.is(OperationFailure)(e)
1081
- ? {
1082
- level: "warn" as const,
1083
- message: intl.formatMessage(
1084
- { id: "handle.with_warnings" },
1085
- { action }
1086
- ) + e.message
1087
- ? "\n" + e.message
1088
- : ""
1089
- }
1090
- : `${
1091
- intl.formatMessage(
1092
- { id: "handle.with_errors" },
1093
- { action }
1094
- )
1095
- }:\n` + renderError(action, errorRenderer)(e, ...args)
1096
- })
1097
- })
1098
-
1099
1178
  return {
1100
- /** @experimental */
1101
- takeOver:
1102
- <Args extends any[], A, E, R, const Id extends string>(command: Commander.CommandOut<Args, A, E, R, Id>) =>
1103
- (...args: Args) => {
1104
- // we capture the call site stack here
1105
- const limit = Error.stackTraceLimit
1106
- Error.stackTraceLimit = 2
1107
- const errorCall = new Error()
1108
- const localErrorDef = new Error()
1109
- Error.stackTraceLimit = limit
1110
-
1111
- // TODO
1112
- const errorDef = localErrorDef
1113
-
1114
- let cache: false | string = false
1115
- const captureStackTrace = () => {
1116
- // in case of an error, we want to append the definition stack to the call site stack,
1117
- // so we can see where the handler was defined too
1118
-
1119
- if (cache !== false) {
1120
- return cache
1121
- }
1122
- if (errorCall.stack) {
1123
- const stackDef = errorDef.stack!.trim().split("\n")
1124
- const stackCall = errorCall.stack.trim().split("\n")
1125
- let endStackDef = stackDef.slice(2).join("\n").trim()
1126
- if (!endStackDef.includes(`(`)) {
1127
- endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
1128
- }
1129
- let endStackCall = stackCall.slice(2).join("\n").trim()
1130
- if (!endStackCall.includes(`(`)) {
1131
- endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
1132
- }
1133
- cache = `${endStackDef}\n${endStackCall}`
1134
- return cache
1135
- }
1136
- }
1137
-
1138
- return Effect.gen(function*() {
1139
- const ctx = yield* CommandContext
1140
- ctx.action = command.action
1141
- return yield* command.exec(...args).pipe(
1142
- Effect.flatten,
1143
- Effect.withSpan(
1144
- command.action,
1145
- { captureStackTrace }
1146
- )
1147
- )
1148
- })
1149
- },
1150
-
1151
- /** Version of @see confirmOrInterrupt that automatically includes the action name in the default messages */
1152
- confirmOrInterrupt: Effect.fnUntraced(function*(
1153
- message: string | undefined = undefined
1154
- ) {
1155
- const context = yield* CommandContext
1156
- yield* confirmOrInterrupt(
1157
- message
1158
- ?? intl.formatMessage(
1159
- { id: "handle.confirmation" },
1160
- { action: context.action }
1161
- )
1162
- )
1163
- }),
1164
- /** Version of @see confirm that automatically includes the action name in the default messages */
1165
- confirm: Effect.fnUntraced(function*(
1166
- message: string | undefined = undefined
1167
- ) {
1168
- const context = yield* CommandContext
1169
- return yield* confirm(
1170
- message
1171
- ?? intl.formatMessage(
1172
- { id: "handle.confirmation" },
1173
- { action: context.action }
1174
- )
1175
- )
1176
- }),
1177
- updateAction:
1178
- <Args extends Array<unknown>>(update: (currentActionId: string, ...args: Args) => string) =>
1179
- <A, E, R>(_: Effect.Effect<A, E, R>, ...input: Args) =>
1180
- Effect.updateService(
1181
- _,
1182
- CommandContext,
1183
- (c) => ({ ...c, action: update(c.action, ...input) })
1184
- ),
1185
- defaultFailureMessageHandler,
1186
- renderError,
1187
- /** Version of withDefaultToast that automatically includes the action name in the default messages and uses intl */
1188
- withDefaultToast: <A, E, R, Args extends Array<unknown>>(
1189
- options?: {
1190
- errorRenderer?: ErrorRenderer<E, Args>
1191
- onWaiting?: null | undefined | string | ((action: string, ...args: Args) => string | null | undefined)
1192
- onSuccess?: null | undefined | string | ((a: A, action: string, ...args: Args) => string | null | undefined)
1193
- }
1194
- ) =>
1195
- (
1196
- self: Effect.Effect<A, E, R>,
1197
- ...args: Args
1198
- ) =>
1199
- Effect.gen(function*() {
1200
- const cc = yield* CommandContext
1201
-
1202
- return yield* self.pipe(
1203
- (_) =>
1204
- withToast<A, E, Args, R>({
1205
- onWaiting: options?.onWaiting === null ? null : intl.formatMessage(
1206
- { id: "handle.waiting" },
1207
- { action: cc.action }
1208
- ),
1209
- onSuccess: options?.onSuccess === null
1210
- ? null
1211
- : (a, ..._args) =>
1212
- intl.formatMessage({ id: "handle.success" }, { action: cc.action })
1213
- + (S.is(OperationSuccess)(a) && a.message ? "\n" + a.message : ""),
1214
- onFailure: defaultFailureMessageHandler(cc.action, options?.errorRenderer)
1215
- })(_, ...args)
1216
- )
1217
- }),
1179
+ // /** @experimental */
1180
+ // takeOver:
1181
+ // <Args extends any[], A, E, R, const Id extends string>(command: Commander.CommandOut<Args, A, E, R, Id>) =>
1182
+ // (...args: Args) => {
1183
+ // // we capture the call site stack here
1184
+ // const limit = Error.stackTraceLimit
1185
+ // Error.stackTraceLimit = 2
1186
+ // const errorCall = new Error()
1187
+ // const localErrorDef = new Error()
1188
+ // Error.stackTraceLimit = limit
1189
+
1190
+ // // TODO
1191
+ // const errorDef = localErrorDef
1192
+
1193
+ // let cache: false | string = false
1194
+ // const captureStackTrace = () => {
1195
+ // // in case of an error, we want to append the definition stack to the call site stack,
1196
+ // // so we can see where the handler was defined too
1197
+
1198
+ // if (cache !== false) {
1199
+ // return cache
1200
+ // }
1201
+ // if (errorCall.stack) {
1202
+ // const stackDef = errorDef.stack!.trim().split("\n")
1203
+ // const stackCall = errorCall.stack.trim().split("\n")
1204
+ // let endStackDef = stackDef.slice(2).join("\n").trim()
1205
+ // if (!endStackDef.includes(`(`)) {
1206
+ // endStackDef = endStackDef.replace(/at (.*)/, "at ($1)")
1207
+ // }
1208
+ // let endStackCall = stackCall.slice(2).join("\n").trim()
1209
+ // if (!endStackCall.includes(`(`)) {
1210
+ // endStackCall = endStackCall.replace(/at (.*)/, "at ($1)")
1211
+ // }
1212
+ // cache = `${endStackDef}\n${endStackCall}`
1213
+ // return cache
1214
+ // }
1215
+ // }
1216
+
1217
+ // return Effect.gen(function*() {
1218
+ // const ctx = yield* CommandContext
1219
+ // ctx.action = command.action
1220
+ // return yield* command.exec(...args).pipe(
1221
+ // Effect.flatten,
1222
+ // Effect.withSpan(
1223
+ // command.action,
1224
+ // { captureStackTrace }
1225
+ // )
1226
+ // )
1227
+ // })
1228
+ // },
1218
1229
  /**
1219
1230
  * Define a Command for handling user actions with built-in error reporting and state management.
1220
1231
  *
@@ -16,5 +16,6 @@ export class Confirm extends Effect.Service<Confirm>()("Confirm", {
16
16
  )
17
17
 
18
18
  return { confirm, confirmOrInterrupt }
19
- })
19
+ }),
20
+ accessors: true
20
21
  }) {}
@@ -1,5 +1,5 @@
1
1
  import { Effect } from "effect-app"
2
- import { Commander } from "./commander.js"
2
+ import { Commander, CommanderStatic } from "./commander.js"
3
3
 
4
4
  export const makeUseCommand = Effect.fnUntraced(function*<R = never>() {
5
5
  const cmndr = yield* Commander
@@ -10,6 +10,7 @@ export const makeUseCommand = Effect.fnUntraced(function*<R = never>() {
10
10
  alt: cmndr.alt(runtime),
11
11
  fn: cmndr.fn(runtime),
12
12
  wrap: cmndr.wrap(runtime),
13
- alt2: cmndr.alt2(runtime)
13
+ alt2: cmndr.alt2(runtime),
14
+ ...CommanderStatic
14
15
  }
15
16
  })