varlock 0.0.3 → 0.0.5

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.
Files changed (102) hide show
  1. package/README.md +48 -25
  2. package/dist/auto-load.js +5 -6
  3. package/dist/{chunk-7UQXFWKN.js → chunk-365YVT72.js} +93 -3
  4. package/dist/chunk-365YVT72.js.map +1 -0
  5. package/dist/{chunk-CPA2D42B.js → chunk-7SCZ3YWG.js} +10 -9
  6. package/dist/chunk-7SCZ3YWG.js.map +1 -0
  7. package/dist/{chunk-RF3YMFUX.js → chunk-C2ZQAQUU.js} +3 -4
  8. package/dist/chunk-C2ZQAQUU.js.map +1 -0
  9. package/dist/chunk-EVHLEWHL.js +59 -0
  10. package/dist/chunk-EVHLEWHL.js.map +1 -0
  11. package/dist/{chunk-3KZR56NU.js → chunk-GAQWSZCY.js} +3 -4
  12. package/dist/chunk-GAQWSZCY.js.map +1 -0
  13. package/dist/{chunk-7QXRUUDC.js → chunk-GCUCCUG5.js} +29 -7
  14. package/dist/chunk-GCUCCUG5.js.map +1 -0
  15. package/dist/{chunk-2CM6PMED.js → chunk-GVAD672U.js} +15 -27
  16. package/dist/chunk-GVAD672U.js.map +1 -0
  17. package/dist/{chunk-RPLDMNWT.js → chunk-HMRN5QZL.js} +3 -3
  18. package/dist/{chunk-RPLDMNWT.js.map → chunk-HMRN5QZL.js.map} +1 -1
  19. package/dist/{chunk-TYL3Q4QG.js → chunk-K2N2TG4M.js} +1227 -1259
  20. package/dist/chunk-K2N2TG4M.js.map +1 -0
  21. package/dist/chunk-LHTLO65N.js +99 -0
  22. package/dist/chunk-LHTLO65N.js.map +1 -0
  23. package/dist/{chunk-OXV76U3Y.js → chunk-LU2R63B4.js} +3 -4
  24. package/dist/chunk-LU2R63B4.js.map +1 -0
  25. package/dist/{chunk-B4UBSMSZ.js → chunk-PUGFIZE3.js} +4 -3
  26. package/dist/chunk-PUGFIZE3.js.map +1 -0
  27. package/dist/chunk-PZE4KJJW.js +14 -0
  28. package/dist/{chunk-3EBGAOLH.js.map → chunk-PZE4KJJW.js.map} +1 -1
  29. package/dist/{chunk-RCHPHIHX.js → chunk-RZT65DRA.js} +2 -2
  30. package/dist/chunk-RZT65DRA.js.map +1 -0
  31. package/dist/chunk-UFAGBKYG.js +54 -0
  32. package/dist/chunk-UFAGBKYG.js.map +1 -0
  33. package/dist/{chunk-5HDQH7UC.js → chunk-VVJO4FC3.js} +28 -169
  34. package/dist/chunk-VVJO4FC3.js.map +1 -0
  35. package/dist/chunk-VVKXMIKQ.js +180 -0
  36. package/dist/chunk-VVKXMIKQ.js.map +1 -0
  37. package/dist/{chunk-OSSLRXKM.js → chunk-WFN3ZXGS.js} +6 -6
  38. package/dist/chunk-WFN3ZXGS.js.map +1 -0
  39. package/dist/chunk-Y7WD33L3.js +17 -0
  40. package/dist/chunk-Y7WD33L3.js.map +1 -0
  41. package/dist/{chunk-NAZPFZOO.js → chunk-Z5KNSSLC.js} +10 -8
  42. package/dist/chunk-Z5KNSSLC.js.map +1 -0
  43. package/dist/cli/cli-executable.js +702 -158
  44. package/dist/cli/cli-executable.js.map +1 -1
  45. package/dist/doctor.command-NUG3BYDQ.js +7 -0
  46. package/dist/{doctor.command-L3P5LBOW.js.map → doctor.command-NUG3BYDQ.js.map} +1 -1
  47. package/dist/dotenv-compat.js +5 -6
  48. package/dist/encrypt.command-AGHQ4KTI.js +7 -0
  49. package/dist/{encrypt.command-VGJABHNK.js.map → encrypt.command-AGHQ4KTI.js.map} +1 -1
  50. package/dist/env-B8lQt2sl.d.ts +42 -0
  51. package/dist/help.command-B7VWA53B.js +5 -0
  52. package/dist/{help.command-YZDL2VEQ.js.map → help.command-B7VWA53B.js.map} +1 -1
  53. package/dist/index.d.ts +1 -2
  54. package/dist/index.js +11 -10
  55. package/dist/index.js.map +1 -1
  56. package/dist/init.command-DHE2Q6FX.js +13 -0
  57. package/dist/{init.command-Q4YBHAEG.js.map → init.command-DHE2Q6FX.js.map} +1 -1
  58. package/dist/load.command-GGE4OANH.js +12 -0
  59. package/dist/{load.command-K22PEH3D.js.map → load.command-GGE4OANH.js.map} +1 -1
  60. package/dist/login.command-25PKQUGR.js +10 -0
  61. package/dist/{login.command-22RUZJLR.js.map → login.command-25PKQUGR.js.map} +1 -1
  62. package/dist/run.command-BLL6AL52.js +12 -0
  63. package/dist/{run.command-DUAYGL6F.js.map → run.command-BLL6AL52.js.map} +1 -1
  64. package/dist/runtime/env.d.ts +1 -27
  65. package/dist/runtime/env.js +1 -1
  66. package/dist/runtime/patch-console.js +2 -3
  67. package/dist/runtime/patch-response.js +2 -3
  68. package/dist/runtime/patch-server-response.js +2 -3
  69. package/dist/telemetry.command-MVL3E366.js +10 -0
  70. package/dist/telemetry.command-MVL3E366.js.map +1 -0
  71. package/package.json +6 -2
  72. package/dist/chunk-2CM6PMED.js.map +0 -1
  73. package/dist/chunk-3EBGAOLH.js +0 -14
  74. package/dist/chunk-3KZR56NU.js.map +0 -1
  75. package/dist/chunk-5HDQH7UC.js.map +0 -1
  76. package/dist/chunk-7QXRUUDC.js.map +0 -1
  77. package/dist/chunk-7UQXFWKN.js.map +0 -1
  78. package/dist/chunk-B4UBSMSZ.js.map +0 -1
  79. package/dist/chunk-CPA2D42B.js.map +0 -1
  80. package/dist/chunk-LQZ6ICSS.js +0 -21
  81. package/dist/chunk-LQZ6ICSS.js.map +0 -1
  82. package/dist/chunk-NAZPFZOO.js.map +0 -1
  83. package/dist/chunk-OSSLRXKM.js.map +0 -1
  84. package/dist/chunk-OXV76U3Y.js.map +0 -1
  85. package/dist/chunk-Q5P7F3WA.js +0 -107
  86. package/dist/chunk-Q5P7F3WA.js.map +0 -1
  87. package/dist/chunk-QCC3P7BT.js +0 -39
  88. package/dist/chunk-QCC3P7BT.js.map +0 -1
  89. package/dist/chunk-RCHPHIHX.js.map +0 -1
  90. package/dist/chunk-RF3YMFUX.js.map +0 -1
  91. package/dist/chunk-TYL3Q4QG.js.map +0 -1
  92. package/dist/chunk-XHOJF7U7.js +0 -12
  93. package/dist/chunk-XHOJF7U7.js.map +0 -1
  94. package/dist/doctor.command-L3P5LBOW.js +0 -6
  95. package/dist/encrypt.command-VGJABHNK.js +0 -6
  96. package/dist/help.command-YZDL2VEQ.js +0 -5
  97. package/dist/init.command-Q4YBHAEG.js +0 -11
  98. package/dist/load.command-K22PEH3D.js +0 -10
  99. package/dist/login.command-22RUZJLR.js +0 -7
  100. package/dist/opt-out.command-Y4KUQ6PQ.js +0 -5
  101. package/dist/opt-out.command-Y4KUQ6PQ.js.map +0 -1
  102. package/dist/run.command-DUAYGL6F.js +0 -10
@@ -1,10 +1,10 @@
1
1
  import { __name } from './chunk-XN24GZXQ.js';
2
2
  import { exec } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
- import fs from 'node:fs/promises';
4
+ import fs2 from 'node:fs/promises';
5
5
  import path from 'node:path';
6
6
  import { ParsedEnvSpecStaticValue, ParsedEnvSpecFunctionCall, ParsedEnvSpecKeyValuePair, parseEnvSpecDotEnvFile } from '@env-spec/parser';
7
- import fs2 from 'node:fs';
7
+ import fs from 'node:fs';
8
8
 
9
9
  // ../../node_modules/.pnpm/@sindresorhus+is@7.0.1/node_modules/@sindresorhus/is/distribution/index.js
10
10
  var typedArrayTypeNames = [
@@ -701,7 +701,7 @@ function mapValues(obj, fn) {
701
701
  }
702
702
  __name(mapValues, "mapValues");
703
703
  function times(count, fn) {
704
- return Array.from({ length: count }, (_2, i) => fn(i));
704
+ return Array.from({ length: count }, (_3, i) => fn(i));
705
705
  }
706
706
  __name(times, "times");
707
707
  function map(array, fn) {
@@ -880,1133 +880,677 @@ var EmptyRequiredValueError = class extends ValidationError {
880
880
  }
881
881
  };
882
882
 
883
- // ../env-graph/src/lib/simple-queue.ts
884
- var SimpleQueue = class {
885
- static {
886
- __name(this, "SimpleQueue");
887
- }
888
- queue = [];
889
- processing = false;
890
- /** Add a task to the queue and return a promise that resolves when the task is complete */
891
- async enqueue(task) {
892
- return new Promise((resolve, reject) => {
893
- this.queue.push(async () => {
894
- try {
895
- const result = await task();
896
- resolve(result);
897
- } catch (err) {
898
- reject(err);
899
- }
900
- });
901
- this.processQueue();
902
- });
903
- }
904
- async processQueue() {
905
- if (this.processing || this.queue.length === 0) {
906
- return;
907
- }
908
- this.processing = true;
909
- const task = this.queue.shift();
910
- if (task) {
911
- try {
912
- await task();
913
- } finally {
914
- this.processing = false;
915
- this.processQueue();
916
- }
917
- }
918
- }
919
- };
920
-
921
- // ../env-graph/src/lib/resolver.ts
922
- var execAsync = promisify(exec);
923
- var Resolver = class {
924
- constructor(fnArgs) {
925
- this.fnArgs = fnArgs;
926
- }
927
- static {
928
- __name(this, "Resolver");
929
- }
930
- static fnName;
931
- inferredType;
932
- _schemaErrors = [];
933
- _depsObj = {};
934
- get childResolvers() {
935
- return this.fnArgs.flatMap((r) => my_dash_default.isPlainObject(r) ? my_dash_default.values(r) : r);
936
- }
937
- get schemaErrors() {
938
- return [
939
- ...this._schemaErrors,
940
- ...this.childResolvers.flatMap((r) => r.schemaErrors)
941
- ];
942
- }
943
- get depsObj() {
944
- const mergedDepsObj = { ...this._depsObj };
945
- this.childResolvers.forEach((r) => Object.assign(mergedDepsObj, r.depsObj));
946
- return mergedDepsObj;
947
- }
948
- get deps() {
949
- return Object.keys(this.depsObj);
950
- }
951
- configItem;
952
- async process(configItem) {
953
- this.configItem = configItem;
954
- try {
955
- await this._process(configItem);
956
- } catch (error) {
957
- if (error instanceof SchemaError) {
958
- this._schemaErrors.push(error);
959
- } else if (error instanceof Error) {
960
- this._schemaErrors.push(new SchemaError(error));
961
- } else {
962
- throw new Error(`Non-error thrown while processing resolver - ${error}`);
963
- }
964
- }
965
- this.childResolvers.forEach((r) => r.process(configItem));
966
- }
967
- // meant to be used by subclass _process methods
968
- addDep(key) {
969
- this._depsObj[key] = true;
970
- if (!this.configItem) throw new Error("expected configItem to be set");
971
- if (!this.configItem.envGraph.configSchema[key]) {
972
- this._schemaErrors.push(new SchemaError(`Unknown referenced key: ${key}`));
973
- }
974
- }
975
- async resolve() {
976
- const resolvedValue = await this._resolve();
977
- return resolvedValue;
978
- }
979
- // meant to be used by subclass _resolve methods
980
- getDepValue(key) {
981
- const depItem = this.configItem?.envGraph.configSchema[key];
982
- if (!depItem) throw new Error(`Expected to find item - ${key}`);
983
- return depItem.resolvedValue;
984
- }
985
- };
986
- var StaticValueResolver = class extends Resolver {
987
- constructor(staticValue) {
988
- super([]);
989
- this.staticValue = staticValue;
990
- if (staticValue !== void 0) {
991
- this.inferredType = typeof staticValue;
992
- }
883
+ // ../env-graph/src/lib/data-types.ts
884
+ var EnvGraphDataType = class {
885
+ constructor(def, factory) {
886
+ this.def = def;
887
+ this.factory = factory;
993
888
  }
994
889
  static {
995
- __name(this, "StaticValueResolver");
996
- }
997
- label = "static";
998
- icon = "bi:dash";
999
- async _resolve() {
1000
- return this.staticValue;
890
+ __name(this, "EnvGraphDataType");
1001
891
  }
1002
- async _process() {
892
+ get name() {
893
+ return this.def.name;
1003
894
  }
1004
- };
1005
- var ErrorResolver = class extends Resolver {
1006
- static {
1007
- __name(this, "ErrorResolver");
895
+ get icon() {
896
+ return this.def.icon;
1008
897
  }
1009
- constructor(err) {
1010
- super([]);
1011
- this._schemaErrors.push(err);
898
+ /** @internal */
899
+ get _rawDef() {
900
+ return this.def;
1012
901
  }
1013
- label = "error";
1014
- icon = "bi:dash";
1015
- async _resolve() {
1016
- return void 0;
902
+ coerce(val) {
903
+ return this.def.coerce ? this.def.coerce(val) : val;
1017
904
  }
1018
- async _process() {
905
+ validate(val) {
906
+ return this.def.validate ? this.def.validate(val) : true;
1019
907
  }
1020
908
  };
1021
- var ConcatResolver = class extends Resolver {
1022
- static {
1023
- __name(this, "ConcatResolver");
1024
- }
1025
- static fnName = "concat";
1026
- label = "concat";
1027
- icon = "material-symbols:join";
1028
- inferredType = "string";
1029
- async _process() {
1030
- if (this.fnArgs.some((arg) => my_dash_default.isPlainObject(arg))) {
1031
- throw new SchemaError("concat() does not support key-value arguments");
909
+ function createEnvGraphDataType(dataTypeDef) {
910
+ const typeFactoryFn = /* @__PURE__ */ __name((...usageOpts) => {
911
+ return new EnvGraphDataType(
912
+ my_dash_default.isFunction(dataTypeDef) ? dataTypeDef(...usageOpts) : dataTypeDef,
913
+ typeFactoryFn
914
+ );
915
+ }, "typeFactoryFn");
916
+ typeFactoryFn._isEnvGraphDataTypeFactory = true;
917
+ const exampleInstance = typeFactoryFn(...[]);
918
+ typeFactoryFn.dataTypeName = exampleInstance.name;
919
+ return typeFactoryFn;
920
+ }
921
+ __name(createEnvGraphDataType, "createEnvGraphDataType");
922
+ function coerceToString(rawVal) {
923
+ if (rawVal === void 0 || rawVal === null) return "";
924
+ return my_dash_default.isString(rawVal) ? rawVal : String(rawVal);
925
+ }
926
+ __name(coerceToString, "coerceToString");
927
+ function coerceToNumber(rawVal) {
928
+ let numVal;
929
+ if (my_dash_default.isString(rawVal)) {
930
+ const parsed = parseFloat(rawVal);
931
+ if (my_dash_default.isNan(parsed) || parsed === Infinity || parsed === -Infinity) {
932
+ throw new CoercionError("Unable to coerce string to number");
1032
933
  }
1033
- if (this.fnArgs.length < 2) {
1034
- throw new SchemaError("concat() expects at least two arguments");
934
+ numVal = parsed;
935
+ } else if (my_dash_default.isNumber(rawVal)) {
936
+ if (numVal === Infinity || numVal === -Infinity) {
937
+ throw new CoercionError("Inifinity is not a valid number");
1035
938
  }
939
+ numVal = rawVal;
940
+ } else {
941
+ throw new CoercionError(`Cannot convert ${rawVal} to number`);
1036
942
  }
1037
- async _resolve() {
1038
- const resolvedValues = [];
1039
- for (const arg of this.fnArgs) {
1040
- if (my_dash_default.isPlainObject(arg)) {
1041
- throw new Error("concat() does not support key-value arguments");
943
+ return numVal;
944
+ }
945
+ __name(coerceToNumber, "coerceToNumber");
946
+ var StringDataType = createEnvGraphDataType(
947
+ (settings) => ({
948
+ name: "string",
949
+ icon: "carbon:string-text",
950
+ coerce: /* @__PURE__ */ __name((rawVal) => {
951
+ let val = coerceToString(rawVal);
952
+ if (settings?.toUpperCase) val = val.toUpperCase();
953
+ if (settings?.toLowerCase) val = val.toLowerCase();
954
+ return val;
955
+ }, "coerce"),
956
+ validate: /* @__PURE__ */ __name((val) => {
957
+ const errors = [];
958
+ if (settings?.minLength !== void 0 && val.length < settings.minLength) {
959
+ errors.push(new ValidationError(`Length must be more than ${settings.minLength}`));
1042
960
  }
1043
- const resolvedChildValue = await arg.resolve();
1044
- resolvedValues.push(String(resolvedChildValue ?? ""));
1045
- }
1046
- return resolvedValues.join("");
1047
- }
1048
- };
1049
- var FallbackResolver = class extends Resolver {
1050
- static {
1051
- __name(this, "FallbackResolver");
1052
- }
1053
- static fnName = "fallback";
1054
- label = "fallback";
1055
- icon = "memory:table-top-stairs-up";
1056
- async _process() {
1057
- if (this.fnArgs.some((arg) => my_dash_default.isPlainObject(arg))) {
1058
- throw new SchemaError("fallback() does not support key-value arguments");
1059
- }
1060
- if (this.fnArgs.length < 2) {
1061
- throw new SchemaError("fallback() expects at least two arguments");
1062
- }
1063
- }
1064
- async _resolve() {
1065
- for (const arg of this.fnArgs) {
1066
- if (my_dash_default.isPlainObject(arg)) throw new Error("fallback() does not support key-value arguments");
1067
- const resolvedChildValue = await arg.resolve();
1068
- if (resolvedChildValue !== void 0 && resolvedChildValue !== "") {
1069
- return resolvedChildValue;
961
+ if (settings?.maxLength !== void 0 && val.length > settings.maxLength) {
962
+ errors.push(new ValidationError(`Length must be less than ${settings.maxLength}`));
1070
963
  }
1071
- }
1072
- }
1073
- };
1074
- var ExecResolver = class _ExecResolver extends Resolver {
1075
- static {
1076
- __name(this, "ExecResolver");
1077
- }
1078
- static fnName = "exec";
1079
- label = "exec";
1080
- icon = "iconoir:terminal";
1081
- async _process() {
1082
- if (this.fnArgs.length !== 1) {
1083
- throw new SchemaError("exec() expects a single child arg");
1084
- }
1085
- if (this.fnArgs.some((arg) => my_dash_default.isPlainObject(arg))) {
1086
- throw new SchemaError("exec() does not support key-value arguments");
1087
- }
1088
- }
1089
- static execQueue = new SimpleQueue();
1090
- async _resolve() {
1091
- if (my_dash_default.isPlainObject(this.fnArgs[0])) throw new Error("exec() does not support key-value arguments");
1092
- const commandStr = await this.fnArgs[0].resolve();
1093
- if (typeof commandStr !== "string") {
1094
- throw new ResolutionError("exec() expects a string child arg");
1095
- }
1096
- try {
1097
- const { stdout, stderr } = await _ExecResolver.execQueue.enqueue(() => execAsync(commandStr));
1098
- return stdout.replace(/\n$/, "");
1099
- } catch (err) {
1100
- console.log("exec() failed", err);
1101
- throw new ResolutionError(`exec() command failed: ${commandStr}`);
1102
- }
1103
- }
1104
- };
1105
- var RefResolver = class extends Resolver {
1106
- static {
1107
- __name(this, "RefResolver");
1108
- }
1109
- static fnName = "ref";
1110
- label = "ref";
1111
- icon = "mdi-light:content-duplicate";
1112
- refKey;
1113
- async _process() {
1114
- if (this.fnArgs.length !== 1) {
1115
- throw new SchemaError("ref() expects a single child arg");
1116
- }
1117
- if (!(this.fnArgs[0] instanceof StaticValueResolver)) {
1118
- throw new SchemaError("ref() expects a single static value passed in");
1119
- }
1120
- const keyName = this.fnArgs[0].staticValue;
1121
- if (typeof keyName !== "string") {
1122
- throw new SchemaError("ref() expects a string keyname passed in");
1123
- }
1124
- this.refKey = keyName;
1125
- this.addDep(keyName);
1126
- }
1127
- async _resolve() {
1128
- if (!this.refKey) throw new Error("expected refKey to be set");
1129
- return this.getDepValue(this.refKey);
1130
- }
1131
- };
1132
- var RegexResolver = class extends Resolver {
1133
- static {
1134
- __name(this, "RegexResolver");
1135
- }
1136
- static fnName = "regex";
1137
- label = "regex";
1138
- icon = "mdi:regex";
1139
- regex;
1140
- async _process() {
1141
- if (this.fnArgs.length !== 1) {
1142
- throw new SchemaError("regex() expects a single child arg");
1143
- }
1144
- if (!(this.fnArgs[0] instanceof StaticValueResolver)) {
1145
- throw new SchemaError("regex() expects a single static value passed in");
1146
- }
1147
- const regexStr = this.fnArgs[0].staticValue;
1148
- if (typeof regexStr !== "string") {
1149
- throw new SchemaError("regex() expects a string");
1150
- }
1151
- this.regex = new RegExp(regexStr);
1152
- }
1153
- async _resolve() {
1154
- if (!this.regex) throw new Error("expected regex to be set");
1155
- return this.regex;
1156
- }
1157
- };
1158
- var RemapResolver = class extends Resolver {
1159
- static {
1160
- __name(this, "RemapResolver");
1161
- }
1162
- static fnName = "remap";
1163
- label = "remap";
1164
- icon = "codicon:replace";
1165
- remappings;
1166
- async _process() {
1167
- if (my_dash_default.isPlainObject(this.fnArgs[0])) {
1168
- throw new SchemaError("remap() expects the first arg to be the value to remap");
1169
- }
1170
- if (!my_dash_default.isPlainObject(this.fnArgs[1])) {
1171
- throw new SchemaError("remap() expects the all args after the first to be key-value pairs of remappings");
1172
- }
1173
- if (this.fnArgs.length !== 2) {
1174
- throw new SchemaError("remap() should not have any additional non key-value args after remappings");
1175
- }
1176
- this.remappings = this.fnArgs[1];
1177
- }
1178
- async _resolve() {
1179
- if (my_dash_default.isPlainObject(this.fnArgs[0])) {
1180
- throw new SchemaError("remap() expects the first arg to be the value to remap");
1181
- }
1182
- if (!my_dash_default.isPlainObject(this.fnArgs[1])) {
1183
- throw new SchemaError("remap() expects the all args after the first to be key-value pairs of remappings");
1184
- }
1185
- const originalValue = await this.fnArgs[0].resolve();
1186
- if (!this.remappings) throw new Error("expected remappings to be set");
1187
- for (const [remappedVal, matchValResolver] of Object.entries(this.remappings)) {
1188
- const matchVal = await matchValResolver.resolve();
1189
- if (matchVal instanceof RegExp && originalValue !== void 0) {
1190
- if (matchVal.test(String(originalValue))) return remappedVal;
1191
- } else {
1192
- if (matchVal === originalValue) return remappedVal;
964
+ if (settings?.isLength !== void 0 && val.length !== settings.isLength) {
965
+ errors.push(new ValidationError(`Length must be exactly ${settings.isLength}`));
966
+ }
967
+ if (settings?.startsWith && !val.startsWith(settings.startsWith)) {
968
+ errors.push(new ValidationError(`Value must start with "${settings.startsWith}"`));
969
+ }
970
+ if (settings?.endsWith && !val.endsWith(settings.endsWith)) {
971
+ errors.push(new ValidationError(`Value must start with "${settings.endsWith}"`));
972
+ }
973
+ if (settings?.matches) {
974
+ const regex = my_dash_default.isString(settings.matches) ? new RegExp(settings.matches) : settings.matches;
975
+ const matches = val.match(regex);
976
+ if (!matches) {
977
+ errors.push(new ValidationError(`Value must match regex "${settings.matches}"`));
978
+ }
979
+ }
980
+ return errors.length ? errors : true;
981
+ }, "validate")
982
+ })
983
+ );
984
+ var NumberDataType = createEnvGraphDataType(
985
+ (settings) => ({
986
+ name: "number",
987
+ icon: "carbon:string-integer",
988
+ coerce(rawVal) {
989
+ let numVal = coerceToNumber(rawVal);
990
+ if (settings?.coerceToMinMaxRange) {
991
+ if (settings?.min !== void 0) numVal = Math.max(settings?.min, numVal);
992
+ if (settings?.max !== void 0) numVal = Math.min(settings?.max, numVal);
993
+ }
994
+ if (settings?.isInt === true || settings?.precision === 0) {
995
+ numVal = Math.round(numVal);
996
+ } else if (settings?.precision) {
997
+ const p = 10 ** settings.precision;
998
+ numVal = Math.round(numVal * p) / p;
999
+ }
1000
+ return numVal;
1001
+ },
1002
+ validate(val) {
1003
+ const errors = [];
1004
+ if (settings?.min !== void 0 && val < settings?.min) {
1005
+ errors.push(new ValidationError(`Min value is ${settings?.min}`));
1006
+ }
1007
+ if (settings?.max !== void 0 && val > settings?.max) {
1008
+ errors.push(new ValidationError(`Max value is ${settings?.max}`));
1193
1009
  }
1010
+ if (settings?.isDivisibleBy !== void 0 && val % settings.isDivisibleBy !== 0) {
1011
+ errors.push(new ValidationError(`Value must be divisible by ${settings?.isDivisibleBy}`));
1012
+ }
1013
+ return errors.length ? errors : true;
1014
+ }
1015
+ })
1016
+ );
1017
+ var BooleanDataType = createEnvGraphDataType({
1018
+ name: "boolean",
1019
+ icon: "carbon:boolean",
1020
+ // probably want allow some settings
1021
+ // - more strict about coercion or adding additional true/false values
1022
+ // - coercing to other values - like 0,1
1023
+ coerce(val) {
1024
+ if (my_dash_default.isBoolean(val)) {
1025
+ return val;
1026
+ } else if (my_dash_default.isString(val)) {
1027
+ const cleanVal = val.toLowerCase().trim();
1028
+ if (["t", "true", "yes", "on", "1"].includes(cleanVal)) return true;
1029
+ if (["f", "false", "no", "off", "0"].includes(cleanVal)) return false;
1030
+ throw new CoercionError("Unable to coerce string value to boolean");
1031
+ } else if (my_dash_default.isNumber(val)) {
1032
+ if (val === 0) return false;
1033
+ if (val === 1) return true;
1034
+ throw new CoercionError("Unable to coerce number value to boolean (only 0 or 1 is valid)");
1035
+ } else {
1036
+ throw new CoercionError("Unable to coerce value to boolean");
1194
1037
  }
1195
- return originalValue;
1196
- }
1197
- };
1198
- var BaseResolvers = [
1199
- ConcatResolver,
1200
- FallbackResolver,
1201
- RefResolver,
1202
- ExecResolver,
1203
- RemapResolver,
1204
- RegexResolver
1205
- ];
1206
-
1207
- // ../env-graph/src/lib/data-source.ts
1208
- var DATA_SOURCE_TYPES = Object.freeze({
1209
- schema: {
1210
- fileSuffixes: ["schema"],
1211
- precedence: 0
1212
- },
1213
- example: {
1214
- fileSuffixes: ["sample", "example"],
1215
- precedence: 1
1216
- },
1217
- defaults: {
1218
- fileSuffixes: ["default", "defaults"],
1219
- precedence: 2
1220
- },
1221
- values: {
1222
- fileSuffixes: [],
1223
- precedence: 3
1224
1038
  },
1225
- overrides: {
1226
- fileSuffixes: ["local", "override"],
1227
- precedence: 4
1039
+ // TODO: add settings to be more strict, or to allow other values to coerce to true/false
1040
+ validate(val) {
1041
+ if (my_dash_default.isBoolean(val)) return true;
1042
+ return new ValidationError("Value must be `true` or `false`");
1228
1043
  }
1229
1044
  });
1230
- var EnvGraphDataSource = class {
1231
- static {
1232
- __name(this, "EnvGraphDataSource");
1233
- }
1234
- static DATA_SOURCE_TYPES = DATA_SOURCE_TYPES;
1235
- // reference back to the graph
1236
- graph;
1237
- type = "values";
1238
- applyForEnv;
1239
- disabled = false;
1240
- ignoreNewDefs = false;
1241
- /** an error encountered while loading/parsing the data source */
1242
- loadingError;
1243
- get isValid() {
1244
- return !this.loadingError;
1245
- }
1246
- configItemDefs = {};
1247
- decorators = {};
1248
- getStaticValues() {
1249
- const obj = {};
1250
- for (const [key, def] of Object.entries(this.configItemDefs)) {
1251
- if (def.resolver instanceof StaticValueResolver) {
1252
- obj[key] = String(def.resolver.staticValue ?? "");
1045
+ var UrlDataType = createEnvGraphDataType(
1046
+ (settings) => ({
1047
+ name: "url",
1048
+ icon: "carbon:url",
1049
+ coerce(rawVal) {
1050
+ const val = coerceToString(rawVal);
1051
+ if (settings?.prependHttps && !val.startsWith("https://")) return `https://${val}`;
1052
+ return val;
1053
+ },
1054
+ validate(val) {
1055
+ const url = new URL(val);
1056
+ if (settings?.allowedDomains && !settings.allowedDomains.includes(url.host.toLowerCase())) {
1057
+ return new ValidationError(`Domain (${url.host}) is not in allowed list: ${settings.allowedDomains.join(",")}`);
1253
1058
  }
1059
+ return true;
1254
1060
  }
1255
- return obj;
1256
- }
1257
- };
1258
- var ProcessEnvDataSource = class _ProcessEnvDataSource extends EnvGraphDataSource {
1259
- static {
1260
- __name(this, "ProcessEnvDataSource");
1261
- }
1262
- type = "overrides";
1263
- typeLabel = "process";
1264
- label = "process.env";
1265
- ignoreNewDefs = true;
1266
- static processEnvValues;
1267
- // ? do we want to set decorator values from env vars here? -- ex: _ENV_FLAG_KEY
1268
- // depends if we want those to work only within process.env
1269
- constructor() {
1270
- super();
1271
- if (!_ProcessEnvDataSource.processEnvValues) {
1272
- _ProcessEnvDataSource.processEnvValues = {};
1273
- for (const itemKey of Object.keys(process.env)) {
1274
- _ProcessEnvDataSource.processEnvValues[itemKey] = process.env[itemKey];
1061
+ })
1062
+ );
1063
+ var SimpleObjectDataType = createEnvGraphDataType({
1064
+ name: "simple-object",
1065
+ icon: "tabler:code-dots",
1066
+ // curly brackets with nothing inside
1067
+ coerce(val) {
1068
+ if (my_dash_default.isPlainObject(val)) return val;
1069
+ if (my_dash_default.isString(val)) {
1070
+ try {
1071
+ const parsedObj = JSON.parse(val);
1072
+ if (my_dash_default.isPlainObject(parsedObj)) return parsedObj;
1073
+ return new CoercionError("Unable to coerce JSON parsed string to object");
1074
+ } catch (err) {
1075
+ return new CoercionError("Error parsing JSON string while coercing string to object");
1275
1076
  }
1276
1077
  }
1277
- for (const itemKey of Object.keys(_ProcessEnvDataSource.processEnvValues)) {
1278
- this.configItemDefs[itemKey] = {
1279
- resolver: new StaticValueResolver(_ProcessEnvDataSource.processEnvValues[itemKey])
1280
- };
1281
- }
1282
- }
1283
- };
1284
- var EnvSourceParseError = class extends Error {
1285
- constructor(message, location) {
1286
- super(message);
1287
- this.location = location;
1288
- }
1289
- static {
1290
- __name(this, "EnvSourceParseError");
1291
- }
1292
- };
1293
- var FileBasedDataSource = class extends EnvGraphDataSource {
1294
- static {
1295
- __name(this, "FileBasedDataSource");
1296
- }
1297
- isGitIgnored;
1298
- fullPath;
1299
- fileName;
1300
- rawContents;
1301
- get typeLabel() {
1302
- return this.constructor.format;
1303
- }
1304
- get label() {
1305
- return this.fileName;
1306
- }
1307
- static format = "unknown";
1308
- // no abstract static
1309
- static validFileExtensions = [];
1310
- get validFileExtensions() {
1311
- return this.constructor.validFileExtensions;
1312
- }
1313
- constructor(fullPath, opts) {
1314
- super();
1315
- this.fullPath = fullPath;
1316
- this.fileName = path.basename(fullPath);
1317
- if (opts?.overrideContents) {
1318
- this.rawContents = opts.overrideContents;
1319
- this.isGitIgnored = opts.overrideGitIgnored;
1320
- }
1321
- if (!this.fileName.startsWith(".env")) {
1322
- throw new Error('file name must start with ".env"');
1078
+ return new CoercionError("Cannot coerce value to object");
1079
+ },
1080
+ validate(val) {
1081
+ if (my_dash_default.isPlainObject(val)) return true;
1082
+ return new ValidationError("Value must be an object");
1083
+ }
1084
+ });
1085
+ var EnumDataType = createEnvGraphDataType(
1086
+ (...enumOptions) => ({
1087
+ name: "enum",
1088
+ icon: "material-symbols-light:category",
1089
+ // a few shapes... not sure about this one
1090
+ coerce(val) {
1091
+ if (my_dash_default.isString(val) || my_dash_default.isNumber(val) || my_dash_default.isBoolean(val)) return val;
1092
+ return new CoercionError("Value must be a string, number, or boolean");
1093
+ },
1094
+ validate(val) {
1095
+ const possibleValues = enumOptions || [];
1096
+ if (!possibleValues.includes(val)) {
1097
+ throw new ValidationError("Current value is not in list of possible values", {
1098
+ tip: `Possible values are: "${possibleValues.join('", "')}"`
1099
+ });
1100
+ }
1101
+ },
1102
+ _rawEnumOptions: enumOptions
1103
+ })
1104
+ );
1105
+ var EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
1106
+ var EmailDataType = createEnvGraphDataType(
1107
+ (settings) => ({
1108
+ name: "email",
1109
+ icon: "iconoir:at-sign",
1110
+ typeDescription: "standard email address",
1111
+ coerce(rawVal) {
1112
+ let val = coerceToString(rawVal);
1113
+ if (settings?.normalize) val = val.toLowerCase();
1114
+ return val;
1115
+ },
1116
+ validate(val) {
1117
+ const result = EMAIL_REGEX.test(val);
1118
+ if (result) return true;
1119
+ return new ValidationError("Value must be a valid email address");
1323
1120
  }
1324
- const fileNameParts = this.fileName.substring(1).split(".");
1325
- const maybeExtension = fileNameParts[fileNameParts.length - 1];
1326
- if (this.validFileExtensions.includes(maybeExtension)) {
1327
- fileNameParts.pop();
1121
+ })
1122
+ );
1123
+ var IP_V4_ADDRESS_REGEX = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/;
1124
+ var IP_V6_ADDRESS_REGEX = /^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$/;
1125
+ var ipAddressDataType = createEnvGraphDataType(
1126
+ (settings) => ({
1127
+ name: "ip",
1128
+ icon: "iconoir:ip-address-tag",
1129
+ typeDescription: "ip v4 or v6 address",
1130
+ coerce(rawVal) {
1131
+ let val = coerceToString(rawVal);
1132
+ if (settings?.normalize) val = val.toLowerCase();
1133
+ return val;
1134
+ },
1135
+ validate(val) {
1136
+ const regex = settings?.version === 6 ? IP_V6_ADDRESS_REGEX : IP_V4_ADDRESS_REGEX;
1137
+ const result = regex.test(val);
1138
+ if (result) return true;
1139
+ return new ValidationError("Value must be a valid IP address");
1328
1140
  }
1329
- const maybeFileType = fileNameParts[fileNameParts.length - 1];
1330
- for (const [possibleSourceType, possibleSourceSpec] of Object.entries(DATA_SOURCE_TYPES)) {
1331
- if (possibleSourceSpec.fileSuffixes.includes(maybeFileType)) {
1332
- this.type = possibleSourceType;
1333
- break;
1141
+ })
1142
+ );
1143
+ var PortDataType = createEnvGraphDataType(
1144
+ (settings) => ({
1145
+ name: "port",
1146
+ icon: "material-symbols:captive-portal",
1147
+ //! globe with arrow - not sure about this one
1148
+ typeDescription: "valid port number between 0 and 65535",
1149
+ coerce(rawVal) {
1150
+ if (my_dash_default.isString(rawVal)) {
1151
+ if (rawVal.includes(".")) throw new CoercionError("Port number must be an integer");
1152
+ if (rawVal.includes("e")) throw new CoercionError("Port number should be an integer, not in exponential notation");
1153
+ }
1154
+ return coerceToNumber(rawVal);
1155
+ },
1156
+ validate(val) {
1157
+ if (settings?.min !== void 0 && val < settings?.min) {
1158
+ return new ValidationError(`Min value is ${settings?.min}`);
1159
+ }
1160
+ if (settings?.max !== void 0 && val > settings?.max) {
1161
+ return new ValidationError(`Max value is ${settings?.max}`);
1162
+ }
1163
+ if (val < 0 || val > 65535) {
1164
+ return new ValidationError("Value must be a valid port number (0-65535)");
1334
1165
  }
1166
+ return true;
1335
1167
  }
1336
- if (this.type !== "values") fileNameParts.pop();
1337
- if (fileNameParts.length > 2) {
1338
- throw Error(`Unsure how to interpret filename - ${this.fileName}`);
1339
- } else if (fileNameParts.length === 2) {
1340
- this.applyForEnv = fileNameParts[1];
1341
- if (this.applyForEnv === "dev") this.applyForEnv = "development";
1342
- if (this.applyForEnv === "stage") this.applyForEnv = "staging";
1343
- if (this.applyForEnv === "prod") this.applyForEnv = "production";
1168
+ })
1169
+ );
1170
+ var SEMVER_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
1171
+ var SemverDataType = createEnvGraphDataType(
1172
+ (settings) => ({
1173
+ name: "semver",
1174
+ icon: "simple-icons:semver",
1175
+ typeDescription: "semantic version string",
1176
+ validate(val) {
1177
+ const result = SEMVER_REGEX.test(val);
1178
+ if (result) return true;
1179
+ return new ValidationError("Value must be a valid semantic version string");
1344
1180
  }
1181
+ })
1182
+ );
1183
+ var ISO_DATE_REGEX = /^(?:[+-]?\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24:?00)(?:[.,]\d+(?!:))?)?(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[zZ]|(?:[+-])(?:[01]\d|2[0-3]):?(?:[0-5]\d)?)?)?)?$/;
1184
+ var IsoDateDataType = createEnvGraphDataType({
1185
+ name: "isoDate",
1186
+ icon: "formkit:datetime",
1187
+ typeDescription: "ISO 8601 date string with optional time and milliseconds",
1188
+ validate(val) {
1189
+ const result = ISO_DATE_REGEX.test(val);
1190
+ if (result) return true;
1191
+ return new ValidationError("Value must be a valid ISO 8601 date string");
1345
1192
  }
1346
- // no async constructors... :(
1347
- async finishInit() {
1348
- if (!this.rawContents) {
1349
- this.isGitIgnored = await checkIsFileGitIgnored(this.fullPath);
1350
- this.rawContents = await fs.readFile(this.fullPath, "utf8");
1351
- }
1352
- await this._parseContents();
1193
+ });
1194
+ var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1195
+ var UuidDataType = createEnvGraphDataType({
1196
+ name: "uuid",
1197
+ icon: "mdi:identifier",
1198
+ typeDescription: "UUID string V1-V5 per RFC4122, including NIL",
1199
+ validate(val) {
1200
+ const result = UUID_REGEX.test(val);
1201
+ if (result) return true;
1202
+ return new ValidationError("Value must be a valid UUID string");
1203
+ }
1204
+ });
1205
+ var MD5_REGEX = /^[a-f0-9]{32}$/;
1206
+ var Md5DataType = createEnvGraphDataType({
1207
+ name: "md5",
1208
+ typeDescription: "MD5 hash string",
1209
+ validate(val) {
1210
+ const result = MD5_REGEX.test(val);
1211
+ if (result) return true;
1212
+ return new ValidationError("Value must be a valid MD5 hash string");
1353
1213
  }
1214
+ });
1215
+ var BaseDataTypes = {
1216
+ string: StringDataType,
1217
+ number: NumberDataType,
1218
+ boolean: BooleanDataType,
1219
+ simpleObject: SimpleObjectDataType,
1220
+ enum: EnumDataType,
1221
+ email: EmailDataType,
1222
+ url: UrlDataType,
1223
+ ipAddress: ipAddressDataType,
1224
+ port: PortDataType,
1225
+ semver: SemverDataType,
1226
+ isoDate: IsoDateDataType,
1227
+ uuid: UuidDataType,
1228
+ md5: Md5DataType
1354
1229
  };
1355
- var DotEnvFileDataSource = class extends FileBasedDataSource {
1230
+
1231
+ // ../env-graph/src/lib/simple-queue.ts
1232
+ var SimpleQueue = class {
1356
1233
  static {
1357
- __name(this, "DotEnvFileDataSource");
1234
+ __name(this, "SimpleQueue");
1358
1235
  }
1359
- static format = ".env";
1360
- static validFileExtensions = [];
1361
- // no extension for dotenv files!
1362
- parsedFile;
1363
- convertParserValueToResolvers(value) {
1364
- if (!this.graph) throw new Error("expected graph to be set");
1365
- if (value === void 0) {
1366
- return new StaticValueResolver(void 0);
1367
- } else if (value instanceof ParsedEnvSpecStaticValue) {
1368
- return new StaticValueResolver(value.unescapedValue);
1369
- } else if (value instanceof ParsedEnvSpecFunctionCall) {
1370
- const ResolverFnClass = this.graph.registeredResolverFunctions[value.name];
1371
- if (!ResolverFnClass) {
1372
- return new ErrorResolver(new SchemaError(`Unknown resolver function: ${value.name}()`));
1373
- }
1374
- const argsFromParser = value.data.args.values;
1375
- let keyValueArgs;
1376
- const argsAsResolversArray = [];
1377
- for (const arg of argsFromParser) {
1378
- if (arg instanceof ParsedEnvSpecKeyValuePair) {
1379
- keyValueArgs ??= {};
1380
- keyValueArgs[arg.key] = this.convertParserValueToResolvers(arg.value);
1381
- } else {
1382
- if (keyValueArgs) {
1383
- return new ErrorResolver(new SchemaError("After switching to key-value function args, cannot switch back"));
1384
- }
1385
- argsAsResolversArray.push(this.convertParserValueToResolvers(arg));
1236
+ queue = [];
1237
+ processing = false;
1238
+ /** Add a task to the queue and return a promise that resolves when the task is complete */
1239
+ async enqueue(task) {
1240
+ return new Promise((resolve, reject) => {
1241
+ this.queue.push(async () => {
1242
+ try {
1243
+ const result = await task();
1244
+ resolve(result);
1245
+ } catch (err) {
1246
+ reject(err);
1386
1247
  }
1387
- }
1388
- if (keyValueArgs) argsAsResolversArray.push(keyValueArgs);
1389
- return new ResolverFnClass(argsAsResolversArray);
1390
- } else {
1391
- throw new Error("Unknown value type");
1392
- }
1248
+ });
1249
+ this.processQueue();
1250
+ });
1393
1251
  }
1394
- async _parseContents() {
1395
- const rawContents = this.rawContents;
1396
- this.parsedFile = await tryCatch(
1397
- () => parseEnvSpecDotEnvFile(rawContents),
1398
- (error) => {
1399
- this.loadingError = new EnvSourceParseError(error.message, {
1400
- path: this.fullPath,
1401
- lineNumber: error.location.start.line,
1402
- colNumber: error.location.start.column,
1403
- lineStr: rawContents.split("\n")[error.location.start.line - 1]
1404
- });
1405
- this.loadingError.cause = error;
1252
+ async processQueue() {
1253
+ if (this.processing || this.queue.length === 0) {
1254
+ return;
1255
+ }
1256
+ this.processing = true;
1257
+ const task = this.queue.shift();
1258
+ if (task) {
1259
+ try {
1260
+ await task();
1261
+ } finally {
1262
+ this.processing = false;
1263
+ this.processQueue();
1406
1264
  }
1407
- );
1408
- if (this.loadingError) return;
1409
- if (!this.parsedFile) throw new Error("Failed to parse .env file");
1410
- this.decorators = this.parsedFile.decoratorsObject;
1411
- if (!this.graph) throw new Error("expected graph to be set");
1412
- for (const item of this.parsedFile.configItems) {
1413
- item.processExpansion();
1414
- this.configItemDefs[item.key] = {
1415
- resolver: this.convertParserValueToResolvers(item.expandedValue),
1416
- description: item.description,
1417
- decorators: item.decoratorsObject
1418
- };
1419
1265
  }
1420
1266
  }
1421
1267
  };
1422
- var ConfigItem = class {
1423
- constructor(envGraph, key) {
1424
- this.envGraph = envGraph;
1425
- this.key = key;
1268
+
1269
+ // ../env-graph/src/lib/resolver.ts
1270
+ var execAsync = promisify(exec);
1271
+ var Resolver = class {
1272
+ constructor(fnArgs) {
1273
+ this.fnArgs = fnArgs;
1426
1274
  }
1427
1275
  static {
1428
- __name(this, "ConfigItem");
1429
- }
1430
- defs = [];
1431
- addDef(itemDef, source) {
1432
- this.defs.unshift({ itemDef, source });
1276
+ __name(this, "Resolver");
1433
1277
  }
1434
- get description() {
1435
- for (const def of this.defs) {
1436
- if (def.itemDef.description) return def.itemDef.description;
1437
- }
1278
+ static fnName;
1279
+ inferredType;
1280
+ _schemaErrors = [];
1281
+ _depsObj = {};
1282
+ get childResolvers() {
1283
+ return this.fnArgs.flatMap((r) => my_dash_default.isPlainObject(r) ? my_dash_default.values(r) : r);
1438
1284
  }
1439
- get icon() {
1440
- const explicitIcon = this.getDecoratorValueString("icon");
1441
- if (explicitIcon) return explicitIcon;
1442
- return this.dataType?.icon;
1285
+ get schemaErrors() {
1286
+ return [
1287
+ ...this._schemaErrors,
1288
+ ...this.childResolvers.flatMap((r) => r.schemaErrors)
1289
+ ];
1443
1290
  }
1444
- get docsLinks() {
1445
- const links = [];
1446
- const docsUrl = this.getDecoratorValueString("docsUrl");
1447
- if (docsUrl) links.push({ url: docsUrl });
1448
- return links;
1291
+ get depsObj() {
1292
+ const mergedDepsObj = { ...this._depsObj };
1293
+ this.childResolvers.forEach((r) => Object.assign(mergedDepsObj, r.depsObj));
1294
+ return mergedDepsObj;
1449
1295
  }
1450
- get valueResolver() {
1451
- for (const def of this.defs) {
1452
- if (def.itemDef.resolver) return def.itemDef.resolver;
1453
- }
1296
+ get deps() {
1297
+ return Object.keys(this.depsObj);
1454
1298
  }
1455
- getDecorator(decoratorName) {
1456
- for (const def of this.defs) {
1457
- const defDecorators = def.itemDef.decorators || {};
1458
- if (decoratorName in defDecorators) {
1459
- return defDecorators[decoratorName];
1299
+ configItem;
1300
+ async process(configItem) {
1301
+ this.configItem = configItem;
1302
+ try {
1303
+ await this._process(configItem);
1304
+ } catch (error) {
1305
+ if (error instanceof SchemaError) {
1306
+ this._schemaErrors.push(error);
1307
+ } else if (error instanceof Error) {
1308
+ this._schemaErrors.push(new SchemaError(error));
1309
+ } else {
1310
+ throw new Error(`Non-error thrown while processing resolver - ${error}`);
1460
1311
  }
1461
1312
  }
1313
+ this.childResolvers.forEach((r) => r.process(configItem));
1462
1314
  }
1463
- getDecoratorValueRaw(decoratorName) {
1464
- for (const def of this.defs) {
1465
- const defDecorators = def.itemDef.decorators || {};
1466
- if (decoratorName in defDecorators) {
1467
- return defDecorators[decoratorName].value;
1468
- }
1315
+ // meant to be used by subclass _process methods
1316
+ addDep(key) {
1317
+ this._depsObj[key] = true;
1318
+ if (!this.configItem) throw new Error("expected configItem to be set");
1319
+ if (!this.configItem.envGraph.configSchema[key]) {
1320
+ this._schemaErrors.push(new SchemaError(`Unknown referenced key: ${key}`));
1469
1321
  }
1470
1322
  }
1471
- getDecoratorValueString(decoratorName) {
1472
- const dec = this.getDecoratorValueRaw(decoratorName);
1473
- if (dec instanceof ParsedEnvSpecStaticValue) return String(dec.value);
1323
+ async resolve() {
1324
+ const resolvedValue = await this._resolve();
1325
+ return resolvedValue;
1474
1326
  }
1475
- dataType;
1476
- schemaErrors = [];
1477
- get resolverSchemaErrors() {
1478
- return this.valueResolver?.schemaErrors || [];
1327
+ // meant to be used by subclass _resolve methods
1328
+ getDepValue(key) {
1329
+ const depItem = this.configItem?.envGraph.configSchema[key];
1330
+ if (!depItem) throw new Error(`Expected to find item - ${key}`);
1331
+ return depItem.resolvedValue;
1479
1332
  }
1480
- async process() {
1481
- const finalOverrideDef = this.envGraph.finalOverridesDataSource?.configItemDefs[this.key];
1482
- if (finalOverrideDef) {
1483
- this.defs.unshift({ itemDef: finalOverrideDef, source: this.envGraph.finalOverridesDataSource });
1484
- }
1485
- for (const def of this.defs) {
1486
- await def.itemDef.resolver?.process(this);
1487
- }
1488
- const typeDecoratorValue = this.getDecoratorValueRaw("type");
1489
- let dataTypeName;
1490
- let dataTypeArgs;
1491
- if (typeDecoratorValue instanceof ParsedEnvSpecStaticValue) {
1492
- dataTypeName = typeDecoratorValue.value;
1493
- } else if (typeDecoratorValue instanceof ParsedEnvSpecFunctionCall) {
1494
- dataTypeName = typeDecoratorValue.name;
1495
- dataTypeArgs = typeDecoratorValue.simplifiedArgs;
1496
- }
1497
- if (!dataTypeName) {
1498
- if (this.valueResolver?.inferredType) {
1499
- dataTypeName = this.valueResolver.inferredType;
1500
- }
1501
- }
1502
- dataTypeName ||= "string";
1503
- dataTypeArgs ||= [];
1504
- if (!(dataTypeName in this.envGraph.dataTypesRegistry)) {
1505
- this.schemaErrors.push(new SchemaError(`unknown data type: ${dataTypeName}`));
1506
- } else {
1507
- const dataTypeFactory = this.envGraph.dataTypesRegistry[dataTypeName];
1508
- this.dataType = dataTypeFactory(...my_dash_default.isPlainObject(dataTypeArgs) ? [dataTypeArgs] : dataTypeArgs);
1333
+ };
1334
+ var StaticValueResolver = class extends Resolver {
1335
+ constructor(staticValue) {
1336
+ super([]);
1337
+ this.staticValue = staticValue;
1338
+ if (staticValue !== void 0) {
1339
+ this.inferredType = typeof staticValue;
1509
1340
  }
1510
1341
  }
1511
- get isRequired() {
1512
- for (const def of this.defs) {
1513
- const defDecorators = def.itemDef.decorators || {};
1514
- if ("required" in defDecorators) {
1515
- const val = defDecorators.required.simplifiedValue;
1516
- if (typeof val === "boolean") return val;
1517
- if (typeof val === "string") return val === "true";
1518
- return Boolean(val);
1519
- }
1520
- if ("optional" in defDecorators) {
1521
- const val = defDecorators.optional.simplifiedValue;
1522
- if (typeof val === "boolean") return !val;
1523
- if (typeof val === "string") return val !== "true";
1524
- return !val;
1525
- }
1526
- if ("defaultRequired" in def.source.decorators) {
1527
- const val = def.source.decorators.defaultRequired.simplifiedValue;
1528
- if (val === "infer") {
1529
- if (def.source.type === "schema") {
1530
- const resolver = def.itemDef.resolver;
1531
- if (resolver instanceof StaticValueResolver) {
1532
- return resolver.staticValue !== void 0 && resolver.staticValue !== "";
1533
- } else {
1534
- return true;
1535
- }
1536
- } else {
1537
- continue;
1538
- }
1539
- }
1540
- return val;
1541
- }
1542
- }
1543
- return true;
1342
+ static {
1343
+ __name(this, "StaticValueResolver");
1544
1344
  }
1545
- get isSensitive() {
1546
- for (const def of this.defs) {
1547
- const defDecorators = def.itemDef.decorators || {};
1548
- if ("sensitive" in defDecorators) {
1549
- return defDecorators.sensitive.simplifiedValue;
1550
- } else if ("defaultSensitive" in def.source.decorators) {
1551
- const dec = def.source.decorators.defaultSensitive;
1552
- if (dec.value instanceof ParsedEnvSpecFunctionCall && dec.value.name === "inferFromPrefix") {
1553
- const args = dec.value.simplifiedArgs;
1554
- const prefix = Array.isArray(args) && args.length > 0 ? args[0] : void 0;
1555
- if (typeof prefix === "string" && this.key.startsWith(prefix)) {
1556
- return false;
1557
- }
1558
- return true;
1559
- }
1560
- return dec.simplifiedValue;
1561
- }
1562
- }
1563
- return true;
1345
+ label = "static";
1346
+ icon = "bi:dash";
1347
+ async _resolve() {
1348
+ return this.staticValue;
1564
1349
  }
1565
- get errors() {
1566
- return my_dash_default.compact([
1567
- ...this.schemaErrors || [],
1568
- ...this.resolverSchemaErrors || [],
1569
- this.resolutionError,
1570
- this.coercionError,
1571
- ...this.validationErrors || []
1572
- ]);
1350
+ async _process() {
1573
1351
  }
1574
- get validationState() {
1575
- const errors = this.errors;
1576
- if (!errors.length) return "valid";
1577
- return my_dash_default.some(errors, (e) => !e.isWarning) ? "error" : "warn";
1352
+ };
1353
+ var ErrorResolver = class extends Resolver {
1354
+ static {
1355
+ __name(this, "ErrorResolver");
1578
1356
  }
1579
- /** resolved value _before coercion_ */
1580
- resolvedRawValue;
1581
- isResolved = false;
1582
- /** resolved value after coercion */
1583
- resolvedValue;
1584
- isValidated = false;
1585
- resolutionError;
1586
- coercionError;
1587
- validationErrors;
1588
- get isCoerced() {
1589
- return this.resolvedRawValue !== this.resolvedValue;
1357
+ constructor(err) {
1358
+ super([]);
1359
+ this._schemaErrors.push(err);
1590
1360
  }
1591
- async resolve() {
1592
- if (this.schemaErrors.length) return;
1593
- if (this.resolverSchemaErrors.length) return;
1594
- if (!this.valueResolver) throw new Error("Expected a resolver to be set");
1595
- if (this.isResolved) {
1596
- return;
1597
- }
1598
- try {
1599
- this.resolvedRawValue = await this.valueResolver.resolve();
1600
- } catch (err) {
1601
- this.resolutionError = new ResolutionError(`error resolving value: ${err}`);
1602
- this.resolutionError.cause = err;
1603
- }
1604
- if (this.resolvedRawValue instanceof RegExp) {
1605
- this.resolutionError = new ResolutionError("regex() is meant to be used within function args, not as a final resolved value");
1606
- }
1607
- if (this.resolutionError) return;
1608
- this.isResolved = true;
1609
- if (this.resolvedRawValue === void 0 || this.resolvedRawValue === "") {
1610
- this.resolvedValue = this.resolvedRawValue;
1611
- if (this.isRequired) {
1612
- this.validationErrors = [new EmptyRequiredValueError(void 0)];
1613
- }
1614
- return;
1361
+ label = "error";
1362
+ icon = "bi:dash";
1363
+ async _resolve() {
1364
+ return void 0;
1365
+ }
1366
+ async _process() {
1367
+ }
1368
+ };
1369
+ var ConcatResolver = class extends Resolver {
1370
+ static {
1371
+ __name(this, "ConcatResolver");
1372
+ }
1373
+ static fnName = "concat";
1374
+ label = "concat";
1375
+ icon = "material-symbols:join";
1376
+ inferredType = "string";
1377
+ async _process() {
1378
+ if (this.fnArgs.some((arg) => my_dash_default.isPlainObject(arg))) {
1379
+ throw new SchemaError("concat() does not support key-value arguments");
1615
1380
  }
1616
- if (!this.dataType) throw new Error("expected dataType to be set");
1617
- try {
1618
- const coerceResult = this.dataType.coerce(this.resolvedRawValue);
1619
- if (coerceResult instanceof Error) throw coerceResult;
1620
- this.resolvedValue = coerceResult;
1621
- } catch (err) {
1622
- if (err instanceof CoercionError) {
1623
- this.coercionError = err;
1624
- return;
1625
- } else if (err instanceof Error) {
1626
- this.coercionError = new CoercionError("Unexpected error coercing value");
1627
- this.coercionError.cause = err;
1628
- } else {
1629
- this.coercionError = new CoercionError(`Unexpected non-error throw during coerce - ${err}`);
1630
- }
1631
- return;
1381
+ if (this.fnArgs.length < 2) {
1382
+ throw new SchemaError("concat() expects at least two arguments");
1632
1383
  }
1633
- try {
1634
- const validateResult = this.dataType.validate(this.resolvedValue);
1635
- if (validateResult instanceof Error || my_dash_default.isArray(validateResult) && validateResult[0] instanceof Error) throw validateResult;
1636
- if (validateResult === false) {
1637
- throw new ValidationError("validation failed with `false` return value");
1638
- }
1639
- this.isValidated = true;
1640
- } catch (err) {
1641
- if (my_dash_default.isArray(err)) {
1642
- this.validationErrors = err;
1643
- } else if (err instanceof ValidationError) {
1644
- this.validationErrors = [err];
1645
- } else if (err instanceof Error) {
1646
- const validationError = new ValidationError("Unexpected error during validation");
1647
- validationError.cause = err;
1648
- console.log(err);
1649
- this.validationErrors = [validationError];
1650
- } else {
1651
- const validationError = new ValidationError(`Unexpected non-error thrown during validation - ${err}`);
1652
- validationError.cause = err;
1653
- this.validationErrors = [validationError];
1384
+ }
1385
+ async _resolve() {
1386
+ const resolvedValues = [];
1387
+ for (const arg of this.fnArgs) {
1388
+ if (my_dash_default.isPlainObject(arg)) {
1389
+ throw new Error("concat() does not support key-value arguments");
1654
1390
  }
1655
- return;
1391
+ const resolvedChildValue = await arg.resolve();
1392
+ resolvedValues.push(String(resolvedChildValue ?? ""));
1656
1393
  }
1657
- }
1658
- get isValid() {
1659
- return this.validationState === "valid";
1394
+ return resolvedValues.join("");
1660
1395
  }
1661
1396
  };
1662
-
1663
- // ../env-graph/src/lib/data-types.ts
1664
- var EnvGraphDataType = class {
1665
- constructor(def, factory) {
1666
- this.def = def;
1667
- this.factory = factory;
1668
- }
1397
+ var FallbackResolver = class extends Resolver {
1669
1398
  static {
1670
- __name(this, "EnvGraphDataType");
1399
+ __name(this, "FallbackResolver");
1671
1400
  }
1672
- get name() {
1673
- return this.def.name;
1401
+ static fnName = "fallback";
1402
+ label = "fallback";
1403
+ icon = "memory:table-top-stairs-up";
1404
+ async _process() {
1405
+ if (this.fnArgs.some((arg) => my_dash_default.isPlainObject(arg))) {
1406
+ throw new SchemaError("fallback() does not support key-value arguments");
1407
+ }
1408
+ if (this.fnArgs.length < 2) {
1409
+ throw new SchemaError("fallback() expects at least two arguments");
1410
+ }
1674
1411
  }
1675
- get icon() {
1676
- return this.def.icon;
1412
+ async _resolve() {
1413
+ for (const arg of this.fnArgs) {
1414
+ if (my_dash_default.isPlainObject(arg)) throw new Error("fallback() does not support key-value arguments");
1415
+ const resolvedChildValue = await arg.resolve();
1416
+ if (resolvedChildValue !== void 0 && resolvedChildValue !== "") {
1417
+ return resolvedChildValue;
1418
+ }
1419
+ }
1677
1420
  }
1678
- /** @internal */
1679
- get _rawDef() {
1680
- return this.def;
1421
+ };
1422
+ var ExecResolver = class _ExecResolver extends Resolver {
1423
+ static {
1424
+ __name(this, "ExecResolver");
1681
1425
  }
1682
- coerce(val) {
1683
- return this.def.coerce ? this.def.coerce(val) : val;
1426
+ static fnName = "exec";
1427
+ label = "exec";
1428
+ icon = "iconoir:terminal";
1429
+ async _process() {
1430
+ if (this.fnArgs.length !== 1) {
1431
+ throw new SchemaError("exec() expects a single child arg");
1432
+ }
1433
+ if (this.fnArgs.some((arg) => my_dash_default.isPlainObject(arg))) {
1434
+ throw new SchemaError("exec() does not support key-value arguments");
1435
+ }
1684
1436
  }
1685
- validate(val) {
1686
- return this.def.validate ? this.def.validate(val) : true;
1437
+ static execQueue = new SimpleQueue();
1438
+ async _resolve() {
1439
+ if (my_dash_default.isPlainObject(this.fnArgs[0])) throw new Error("exec() does not support key-value arguments");
1440
+ const commandStr = await this.fnArgs[0].resolve();
1441
+ if (typeof commandStr !== "string") {
1442
+ throw new ResolutionError("exec() expects a string child arg");
1443
+ }
1444
+ try {
1445
+ const { stdout, stderr } = await _ExecResolver.execQueue.enqueue(() => execAsync(commandStr));
1446
+ return stdout.replace(/\n$/, "");
1447
+ } catch (err) {
1448
+ console.log("exec() failed", err);
1449
+ throw new ResolutionError(`exec() command failed: ${commandStr}`);
1450
+ }
1687
1451
  }
1688
1452
  };
1689
- function createEnvGraphDataType(dataTypeDef) {
1690
- const typeFactoryFn = /* @__PURE__ */ __name((...usageOpts) => {
1691
- return new EnvGraphDataType(
1692
- my_dash_default.isFunction(dataTypeDef) ? dataTypeDef(...usageOpts) : dataTypeDef,
1693
- typeFactoryFn
1694
- );
1695
- }, "typeFactoryFn");
1696
- typeFactoryFn._isEnvGraphDataTypeFactory = true;
1697
- const exampleInstance = typeFactoryFn(...[]);
1698
- typeFactoryFn.dataTypeName = exampleInstance.name;
1699
- return typeFactoryFn;
1700
- }
1701
- __name(createEnvGraphDataType, "createEnvGraphDataType");
1702
- function coerceToString(rawVal) {
1703
- if (rawVal === void 0 || rawVal === null) return "";
1704
- return my_dash_default.isString(rawVal) ? rawVal : String(rawVal);
1705
- }
1706
- __name(coerceToString, "coerceToString");
1707
- function coerceToNumber(rawVal) {
1708
- let numVal;
1709
- if (my_dash_default.isString(rawVal)) {
1710
- const parsed = parseFloat(rawVal);
1711
- if (my_dash_default.isNan(parsed) || parsed === Infinity || parsed === -Infinity) {
1712
- throw new CoercionError("Unable to coerce string to number");
1453
+ var RefResolver = class extends Resolver {
1454
+ static {
1455
+ __name(this, "RefResolver");
1456
+ }
1457
+ static fnName = "ref";
1458
+ label = "ref";
1459
+ icon = "mdi-light:content-duplicate";
1460
+ refKey;
1461
+ async _process() {
1462
+ if (this.fnArgs.length !== 1) {
1463
+ throw new SchemaError("ref() expects a single child arg");
1713
1464
  }
1714
- numVal = parsed;
1715
- } else if (my_dash_default.isNumber(rawVal)) {
1716
- if (numVal === Infinity || numVal === -Infinity) {
1717
- throw new CoercionError("Inifinity is not a valid number");
1465
+ if (!(this.fnArgs[0] instanceof StaticValueResolver)) {
1466
+ throw new SchemaError("ref() expects a single static value passed in");
1718
1467
  }
1719
- numVal = rawVal;
1720
- } else {
1721
- throw new CoercionError(`Cannot convert ${rawVal} to number`);
1468
+ const keyName = this.fnArgs[0].staticValue;
1469
+ if (typeof keyName !== "string") {
1470
+ throw new SchemaError("ref() expects a string keyname passed in");
1471
+ }
1472
+ this.refKey = keyName;
1473
+ this.addDep(keyName);
1722
1474
  }
1723
- return numVal;
1724
- }
1725
- __name(coerceToNumber, "coerceToNumber");
1726
- var StringDataType = createEnvGraphDataType(
1727
- (settings) => ({
1728
- name: "string",
1729
- icon: "carbon:string-text",
1730
- coerce: /* @__PURE__ */ __name((rawVal) => {
1731
- let val = coerceToString(rawVal);
1732
- if (settings?.toUpperCase) val = val.toUpperCase();
1733
- if (settings?.toLowerCase) val = val.toLowerCase();
1734
- return val;
1735
- }, "coerce"),
1736
- validate: /* @__PURE__ */ __name((val) => {
1737
- const errors = [];
1738
- if (settings?.minLength !== void 0 && val.length < settings.minLength) {
1739
- errors.push(new ValidationError(`Length must be more than ${settings.minLength}`));
1740
- }
1741
- if (settings?.maxLength !== void 0 && val.length > settings.maxLength) {
1742
- errors.push(new ValidationError(`Length must be less than ${settings.maxLength}`));
1743
- }
1744
- if (settings?.isLength !== void 0 && val.length !== settings.isLength) {
1745
- errors.push(new ValidationError(`Length must be exactly ${settings.isLength}`));
1746
- }
1747
- if (settings?.startsWith && !val.startsWith(settings.startsWith)) {
1748
- errors.push(new ValidationError(`Value must start with "${settings.startsWith}"`));
1749
- }
1750
- if (settings?.endsWith && !val.endsWith(settings.endsWith)) {
1751
- errors.push(new ValidationError(`Value must start with "${settings.endsWith}"`));
1752
- }
1753
- if (settings?.matches) {
1754
- const regex = my_dash_default.isString(settings.matches) ? new RegExp(settings.matches) : settings.matches;
1755
- const matches = val.match(regex);
1756
- if (!matches) {
1757
- errors.push(new ValidationError(`Value must match regex "${settings.matches}"`));
1758
- }
1759
- }
1760
- return errors.length ? errors : true;
1761
- }, "validate")
1762
- })
1763
- );
1764
- var NumberDataType = createEnvGraphDataType(
1765
- (settings) => ({
1766
- name: "number",
1767
- icon: "carbon:string-integer",
1768
- coerce(rawVal) {
1769
- let numVal = coerceToNumber(rawVal);
1770
- if (settings?.coerceToMinMaxRange) {
1771
- if (settings?.min !== void 0) numVal = Math.max(settings?.min, numVal);
1772
- if (settings?.max !== void 0) numVal = Math.min(settings?.max, numVal);
1773
- }
1774
- if (settings?.isInt === true || settings?.precision === 0) {
1775
- numVal = Math.round(numVal);
1776
- } else if (settings?.precision) {
1777
- const p = 10 ** settings.precision;
1778
- numVal = Math.round(numVal * p) / p;
1779
- }
1780
- return numVal;
1781
- },
1782
- validate(val) {
1783
- const errors = [];
1784
- if (settings?.min !== void 0 && val < settings?.min) {
1785
- errors.push(new ValidationError(`Min value is ${settings?.min}`));
1786
- }
1787
- if (settings?.max !== void 0 && val > settings?.max) {
1788
- errors.push(new ValidationError(`Max value is ${settings?.max}`));
1789
- }
1790
- if (settings?.isDivisibleBy !== void 0 && val % settings.isDivisibleBy !== 0) {
1791
- errors.push(new ValidationError(`Value must be divisible by ${settings?.isDivisibleBy}`));
1792
- }
1793
- return errors.length ? errors : true;
1475
+ async _resolve() {
1476
+ if (!this.refKey) throw new Error("expected refKey to be set");
1477
+ return this.getDepValue(this.refKey);
1478
+ }
1479
+ };
1480
+ var RegexResolver = class extends Resolver {
1481
+ static {
1482
+ __name(this, "RegexResolver");
1483
+ }
1484
+ static fnName = "regex";
1485
+ label = "regex";
1486
+ icon = "mdi:regex";
1487
+ regex;
1488
+ async _process() {
1489
+ if (this.fnArgs.length !== 1) {
1490
+ throw new SchemaError("regex() expects a single child arg");
1794
1491
  }
1795
- })
1796
- );
1797
- var BooleanDataType = createEnvGraphDataType({
1798
- name: "boolean",
1799
- icon: "carbon:boolean",
1800
- // probably want allow some settings
1801
- // - more strict about coercion or adding additional true/false values
1802
- // - coercing to other values - like 0,1
1803
- coerce(val) {
1804
- if (my_dash_default.isBoolean(val)) {
1805
- return val;
1806
- } else if (my_dash_default.isString(val)) {
1807
- const cleanVal = val.toLowerCase().trim();
1808
- if (["t", "true", "yes", "on", "1"].includes(cleanVal)) return true;
1809
- if (["f", "false", "no", "off", "0"].includes(cleanVal)) return false;
1810
- throw new CoercionError("Unable to coerce string value to boolean");
1811
- } else if (my_dash_default.isNumber(val)) {
1812
- if (val === 0) return false;
1813
- if (val === 1) return true;
1814
- throw new CoercionError("Unable to coerce number value to boolean (only 0 or 1 is valid)");
1815
- } else {
1816
- throw new CoercionError("Unable to coerce value to boolean");
1492
+ if (!(this.fnArgs[0] instanceof StaticValueResolver)) {
1493
+ throw new SchemaError("regex() expects a single static value passed in");
1817
1494
  }
1818
- },
1819
- // TODO: add settings to be more strict, or to allow other values to coerce to true/false
1820
- validate(val) {
1821
- if (my_dash_default.isBoolean(val)) return true;
1822
- return new ValidationError("Value must be `true` or `false`");
1495
+ const regexStr = this.fnArgs[0].staticValue;
1496
+ if (typeof regexStr !== "string") {
1497
+ throw new SchemaError("regex() expects a string");
1498
+ }
1499
+ this.regex = new RegExp(regexStr);
1823
1500
  }
1824
- });
1825
- var UrlDataType = createEnvGraphDataType(
1826
- (settings) => ({
1827
- name: "url",
1828
- icon: "carbon:url",
1829
- coerce(rawVal) {
1830
- const val = coerceToString(rawVal);
1831
- if (settings?.prependHttps && !val.startsWith("https://")) return `https://${val}`;
1832
- return val;
1833
- },
1834
- validate(val) {
1835
- const url = new URL(val);
1836
- if (settings?.allowedDomains && !settings.allowedDomains.includes(url.host.toLowerCase())) {
1837
- return new ValidationError(`Domain (${url.host}) is not in allowed list: ${settings.allowedDomains.join(",")}`);
1838
- }
1839
- return true;
1501
+ async _resolve() {
1502
+ if (!this.regex) throw new Error("expected regex to be set");
1503
+ return this.regex;
1504
+ }
1505
+ };
1506
+ var RemapResolver = class extends Resolver {
1507
+ static {
1508
+ __name(this, "RemapResolver");
1509
+ }
1510
+ static fnName = "remap";
1511
+ label = "remap";
1512
+ icon = "codicon:replace";
1513
+ remappings;
1514
+ async _process() {
1515
+ if (my_dash_default.isPlainObject(this.fnArgs[0])) {
1516
+ throw new SchemaError("remap() expects the first arg to be the value to remap");
1840
1517
  }
1841
- })
1842
- );
1843
- var SimpleObjectDataType = createEnvGraphDataType({
1844
- name: "simple-object",
1845
- icon: "tabler:code-dots",
1846
- // curly brackets with nothing inside
1847
- coerce(val) {
1848
- if (my_dash_default.isPlainObject(val)) return val;
1849
- if (my_dash_default.isString(val)) {
1850
- try {
1851
- const parsedObj = JSON.parse(val);
1852
- if (my_dash_default.isPlainObject(parsedObj)) return parsedObj;
1853
- return new CoercionError("Unable to coerce JSON parsed string to object");
1854
- } catch (err) {
1855
- return new CoercionError("Error parsing JSON string while coercing string to object");
1856
- }
1518
+ if (!my_dash_default.isPlainObject(this.fnArgs[1])) {
1519
+ throw new SchemaError("remap() expects the all args after the first to be key-value pairs of remappings");
1857
1520
  }
1858
- return new CoercionError("Cannot coerce value to object");
1859
- },
1860
- validate(val) {
1861
- if (my_dash_default.isPlainObject(val)) return true;
1862
- return new ValidationError("Value must be an object");
1521
+ if (this.fnArgs.length !== 2) {
1522
+ throw new SchemaError("remap() should not have any additional non key-value args after remappings");
1523
+ }
1524
+ this.remappings = this.fnArgs[1];
1863
1525
  }
1864
- });
1865
- var EnumDataType = createEnvGraphDataType(
1866
- (...enumOptions) => ({
1867
- name: "enum",
1868
- icon: "material-symbols-light:category",
1869
- // a few shapes... not sure about this one
1870
- coerce(val) {
1871
- if (my_dash_default.isString(val) || my_dash_default.isNumber(val) || my_dash_default.isBoolean(val)) return val;
1872
- return new CoercionError("Value must be a string, number, or boolean");
1873
- },
1874
- validate(val) {
1875
- const possibleValues = enumOptions || [];
1876
- if (!possibleValues.includes(val)) {
1877
- throw new ValidationError("Current value is not in list of possible values", {
1878
- tip: `Possible values are: "${possibleValues.join('", "')}"`
1879
- });
1880
- }
1881
- },
1882
- _rawEnumOptions: enumOptions
1883
- })
1884
- );
1885
- var EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
1886
- var EmailDataType = createEnvGraphDataType(
1887
- (settings) => ({
1888
- name: "email",
1889
- icon: "iconoir:at-sign",
1890
- typeDescription: "standard email address",
1891
- coerce(rawVal) {
1892
- let val = coerceToString(rawVal);
1893
- if (settings?.normalize) val = val.toLowerCase();
1894
- return val;
1895
- },
1896
- validate(val) {
1897
- const result = EMAIL_REGEX.test(val);
1898
- if (result) return true;
1899
- return new ValidationError("Value must be a valid email address");
1526
+ async _resolve() {
1527
+ if (my_dash_default.isPlainObject(this.fnArgs[0])) {
1528
+ throw new SchemaError("remap() expects the first arg to be the value to remap");
1900
1529
  }
1901
- })
1902
- );
1903
- var IP_V4_ADDRESS_REGEX = /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/;
1904
- var IP_V6_ADDRESS_REGEX = /^(?:(?:[a-fA-F\d]{1,4}:){7}(?:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){6}(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|:[a-fA-F\d]{1,4}|:)|(?:[a-fA-F\d]{1,4}:){5}(?::(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,2}|:)|(?:[a-fA-F\d]{1,4}:){4}(?:(?::[a-fA-F\d]{1,4}){0,1}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,3}|:)|(?:[a-fA-F\d]{1,4}:){3}(?:(?::[a-fA-F\d]{1,4}){0,2}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,4}|:)|(?:[a-fA-F\d]{1,4}:){2}(?:(?::[a-fA-F\d]{1,4}){0,3}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,5}|:)|(?:[a-fA-F\d]{1,4}:){1}(?:(?::[a-fA-F\d]{1,4}){0,4}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,6}|:)|(?::(?:(?::[a-fA-F\d]{1,4}){0,5}:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:\\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}|(?::[a-fA-F\d]{1,4}){1,7}|:)))(?:%[0-9a-zA-Z]{1,})?$/;
1905
- var ipAddressDataType = createEnvGraphDataType(
1906
- (settings) => ({
1907
- name: "ip",
1908
- icon: "iconoir:ip-address-tag",
1909
- typeDescription: "ip v4 or v6 address",
1910
- coerce(rawVal) {
1911
- let val = coerceToString(rawVal);
1912
- if (settings?.normalize) val = val.toLowerCase();
1913
- return val;
1914
- },
1915
- validate(val) {
1916
- const regex = settings?.version === 6 ? IP_V6_ADDRESS_REGEX : IP_V4_ADDRESS_REGEX;
1917
- const result = regex.test(val);
1918
- if (result) return true;
1919
- return new ValidationError("Value must be a valid IP address");
1530
+ if (!my_dash_default.isPlainObject(this.fnArgs[1])) {
1531
+ throw new SchemaError("remap() expects the all args after the first to be key-value pairs of remappings");
1920
1532
  }
1921
- })
1922
- );
1923
- var PortDataType = createEnvGraphDataType(
1924
- (settings) => ({
1925
- name: "port",
1926
- icon: "material-symbols:captive-portal",
1927
- //! globe with arrow - not sure about this one
1928
- typeDescription: "valid port number between 0 and 65535",
1929
- coerce(rawVal) {
1930
- if (my_dash_default.isString(rawVal)) {
1931
- if (rawVal.includes(".")) throw new CoercionError("Port number must be an integer");
1932
- if (rawVal.includes("e")) throw new CoercionError("Port number should be an integer, not in exponential notation");
1933
- }
1934
- return coerceToNumber(rawVal);
1935
- },
1936
- validate(val) {
1937
- if (settings?.min !== void 0 && val < settings?.min) {
1938
- return new ValidationError(`Min value is ${settings?.min}`);
1939
- }
1940
- if (settings?.max !== void 0 && val > settings?.max) {
1941
- return new ValidationError(`Max value is ${settings?.max}`);
1942
- }
1943
- if (val < 0 || val > 65535) {
1944
- return new ValidationError("Value must be a valid port number (0-65535)");
1533
+ const originalValue = await this.fnArgs[0].resolve();
1534
+ if (!this.remappings) throw new Error("expected remappings to be set");
1535
+ for (const [remappedVal, matchValResolver] of Object.entries(this.remappings)) {
1536
+ const matchVal = await matchValResolver.resolve();
1537
+ if (matchVal instanceof RegExp && originalValue !== void 0) {
1538
+ if (matchVal.test(String(originalValue))) return remappedVal;
1539
+ } else {
1540
+ if (matchVal === originalValue) return remappedVal;
1945
1541
  }
1946
- return true;
1947
- }
1948
- })
1949
- );
1950
- var SEMVER_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
1951
- var SemverDataType = createEnvGraphDataType(
1952
- (settings) => ({
1953
- name: "semver",
1954
- icon: "simple-icons:semver",
1955
- typeDescription: "semantic version string",
1956
- validate(val) {
1957
- const result = SEMVER_REGEX.test(val);
1958
- if (result) return true;
1959
- return new ValidationError("Value must be a valid semantic version string");
1960
1542
  }
1961
- })
1962
- );
1963
- var ISO_DATE_REGEX = /^(?:[+-]?\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24:?00)(?:[.,]\d+(?!:))?)?(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[zZ]|(?:[+-])(?:[01]\d|2[0-3]):?(?:[0-5]\d)?)?)?)?$/;
1964
- var IsoDateDataType = createEnvGraphDataType({
1965
- name: "isoDate",
1966
- icon: "formkit:datetime",
1967
- typeDescription: "ISO 8601 date string with optional time and milliseconds",
1968
- validate(val) {
1969
- const result = ISO_DATE_REGEX.test(val);
1970
- if (result) return true;
1971
- return new ValidationError("Value must be a valid ISO 8601 date string");
1972
- }
1973
- });
1974
- var UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1975
- var UuidDataType = createEnvGraphDataType({
1976
- name: "uuid",
1977
- icon: "mdi:identifier",
1978
- typeDescription: "UUID string V1-V5 per RFC4122, including NIL",
1979
- validate(val) {
1980
- const result = UUID_REGEX.test(val);
1981
- if (result) return true;
1982
- return new ValidationError("Value must be a valid UUID string");
1983
- }
1984
- });
1985
- var MD5_REGEX = /^[a-f0-9]{32}$/;
1986
- var Md5DataType = createEnvGraphDataType({
1987
- name: "md5",
1988
- typeDescription: "MD5 hash string",
1989
- validate(val) {
1990
- const result = MD5_REGEX.test(val);
1991
- if (result) return true;
1992
- return new ValidationError("Value must be a valid MD5 hash string");
1543
+ return originalValue;
1993
1544
  }
1994
- });
1995
- var BaseDataTypes = {
1996
- string: StringDataType,
1997
- number: NumberDataType,
1998
- boolean: BooleanDataType,
1999
- simpleObject: SimpleObjectDataType,
2000
- enum: EnumDataType,
2001
- email: EmailDataType,
2002
- url: UrlDataType,
2003
- ipAddress: ipAddressDataType,
2004
- port: PortDataType,
2005
- semver: SemverDataType,
2006
- isoDate: IsoDateDataType,
2007
- uuid: UuidDataType,
2008
- md5: Md5DataType
2009
1545
  };
1546
+ var BaseResolvers = [
1547
+ ConcatResolver,
1548
+ FallbackResolver,
1549
+ RefResolver,
1550
+ ExecResolver,
1551
+ RemapResolver,
1552
+ RegexResolver
1553
+ ];
2010
1554
 
2011
1555
  // ../env-graph/src/lib/graph-utils.ts
2012
1556
  function findGraphCycles(graph) {
@@ -2052,15 +1596,15 @@ var iconCacheFolderInit = false;
2052
1596
  var iconInMemoryCache = {};
2053
1597
  async function fetchIconSvg(iconifyName, color = "808080", iconCacheFolder = "/tmp/varlock-icon-cache") {
2054
1598
  if (!iconCacheFolderInit) {
2055
- fs2.mkdirSync(iconCacheFolder, { recursive: true });
1599
+ fs.mkdirSync(iconCacheFolder, { recursive: true });
2056
1600
  iconCacheFolderInit = true;
2057
1601
  }
2058
1602
  const iconPath = `${iconCacheFolder}/${iconifyName}-${ICON_SIZE}.svg`;
2059
1603
  let svgSrc;
2060
1604
  if (iconInMemoryCache[iconPath]) {
2061
1605
  svgSrc = iconInMemoryCache[iconPath];
2062
- } else if (fs2.existsSync(iconPath)) {
2063
- const svgFileBuffer = await fs2.promises.readFile(iconPath, "utf-8");
1606
+ } else if (fs.existsSync(iconPath)) {
1607
+ const svgFileBuffer = await fs.promises.readFile(iconPath, "utf-8");
2064
1608
  svgSrc = svgFileBuffer.toString();
2065
1609
  iconInMemoryCache[iconPath] = svgSrc;
2066
1610
  } else {
@@ -2072,7 +1616,7 @@ async function fetchIconSvg(iconifyName, color = "808080", iconCacheFolder = "/t
2072
1616
  }
2073
1617
  if (!svgSrc) return;
2074
1618
  if (svgSrc) {
2075
- await fs2.promises.writeFile(iconPath, svgSrc, "utf-8");
1619
+ await fs.promises.writeFile(iconPath, svgSrc, "utf-8");
2076
1620
  iconInMemoryCache[iconPath] = svgSrc;
2077
1621
  }
2078
1622
  }
@@ -2163,12 +1707,23 @@ export type EnvSchemaAsStrings = {
2163
1707
  : (CoercedEnvSchema[Property] extends boolean ? ('true' | 'false') : string)
2164
1708
  };
2165
1709
  `);
2166
- tsSrc.push(`
2167
- declare global {
1710
+ const IMPORT_META_AUGMENTATION = `
1711
+ // add types for global import.meta.env
1712
+ interface ImportMetaEnv extends EnvSchemaAsStrings {}
1713
+ interface ImportMeta {
1714
+ readonly env: ImportMetaEnv;
1715
+ }`;
1716
+ const PROCESS_ENV_AUGMENTATION = `
1717
+ // add types for global process.env
2168
1718
  namespace NodeJS {
2169
1719
  interface ProcessEnv extends EnvSchemaAsStrings {}
2170
- }
2171
- }`);
1720
+ }`;
1721
+ tsSrc.push(...[
1722
+ "declare global {",
1723
+ IMPORT_META_AUGMENTATION,
1724
+ PROCESS_ENV_AUGMENTATION,
1725
+ "}"
1726
+ ].filter(Boolean));
2172
1727
  return tsSrc.join("\n");
2173
1728
  }
2174
1729
  __name(generateTsTypesSrc, "generateTsTypesSrc");
@@ -2177,12 +1732,12 @@ async function generateTypes(graph, lang, outputPath) {
2177
1732
  const tsSrc = await generateTsTypesSrc(graph);
2178
1733
  if (!graph.basePath) return;
2179
1734
  const typesPath = path.join(graph.basePath, outputPath);
2180
- await fs2.promises.writeFile(typesPath, tsSrc, "utf-8");
1735
+ await fs.promises.writeFile(typesPath, tsSrc, "utf-8");
2181
1736
  }
2182
1737
  __name(generateTypes, "generateTypes");
2183
1738
 
2184
1739
  // ../env-graph/src/lib/env-graph.ts
2185
- var EnvGraph = class {
1740
+ var EnvGraph2 = class {
2186
1741
  static {
2187
1742
  __name(this, "EnvGraph");
2188
1743
  }
@@ -2227,241 +1782,654 @@ var EnvGraph = class {
2227
1782
  for (const dataType of my_dash_default.values(BaseDataTypes)) {
2228
1783
  this.registerDataType(dataType);
2229
1784
  }
2230
- for (const resolverClass of BaseResolvers) {
2231
- this.registerResolver(resolverClass);
1785
+ for (const resolverClass of BaseResolvers) {
1786
+ this.registerResolver(resolverClass);
1787
+ }
1788
+ }
1789
+ async finishLoad() {
1790
+ const sortedDataSources = this.sortedDataSources;
1791
+ for (const source of sortedDataSources) {
1792
+ if (source.loadingError) {
1793
+ throw source.loadingError;
1794
+ }
1795
+ if (source.type === "example") {
1796
+ source.disabled = true;
1797
+ continue;
1798
+ }
1799
+ if (source.decorators?.envFlag) {
1800
+ if (source.applyForEnv) {
1801
+ throw new Error(`@envFlag cannot be set from within an env-specific data source - ${source.label}`);
1802
+ } else if (this.envFlagKey) {
1803
+ throw new Error("only a single @envFlag setting is allowed");
1804
+ } else {
1805
+ const envFlagKey = source.decorators.envFlag.simplifiedValue;
1806
+ if (!my_dash_default.isString(envFlagKey)) {
1807
+ throw new Error("@envFlag must be a string");
1808
+ } else {
1809
+ this.envFlagKey = envFlagKey;
1810
+ }
1811
+ }
1812
+ }
1813
+ if (source.applyForEnv) {
1814
+ if (source.applyForEnv && this.envFlagValue !== source.applyForEnv) {
1815
+ source.disabled = true;
1816
+ continue;
1817
+ }
1818
+ }
1819
+ if (source.decorators?.disable && source.decorators.disable.simplifiedValue) {
1820
+ source.disabled = true;
1821
+ continue;
1822
+ }
1823
+ for (const itemKey in source.configItemDefs) {
1824
+ if (source.ignoreNewDefs && !this.configSchema[itemKey]) continue;
1825
+ const itemDef = source.configItemDefs[itemKey];
1826
+ this.configSchema[itemKey] ??= new ConfigItem3(this, itemKey);
1827
+ this.configSchema[itemKey].addDef(itemDef, source);
1828
+ }
1829
+ if (source.type === "schema" && this.envFlagKey) {
1830
+ if (!this.configSchema[this.envFlagKey]) {
1831
+ throw new Error(`@envFlag key ${this.envFlagKey} not found in schema`);
1832
+ }
1833
+ const envFlagItem = this.configSchema[this.envFlagKey];
1834
+ await envFlagItem.process();
1835
+ for (const depKey of envFlagItem.valueResolver?.deps || []) {
1836
+ const depItem = this.configSchema[depKey];
1837
+ if (!depItem) {
1838
+ throw new Error(`envFlag resolver is using non-existant dependency: ${depKey}`);
1839
+ }
1840
+ await depItem.process();
1841
+ if (depItem.valueResolver?.deps.length) {
1842
+ throw new Error("envFlag cannot follow a chain of dependencies");
1843
+ }
1844
+ await depItem.resolve();
1845
+ }
1846
+ await envFlagItem.resolve();
1847
+ if (!envFlagItem.isValid) {
1848
+ const err = new Error("resolved @envFlag value is not valid");
1849
+ err.cause = envFlagItem.errors[0];
1850
+ throw err;
1851
+ }
1852
+ if (envFlagItem.resolvedValue) {
1853
+ if (!my_dash_default.isString(envFlagItem.resolvedValue)) {
1854
+ throw new Error("expected resolved @envFlag value to be a string");
1855
+ }
1856
+ this.envFlagValue = envFlagItem.resolvedValue;
1857
+ }
1858
+ }
1859
+ }
1860
+ for (const itemKey in this.configSchema) {
1861
+ const item = this.configSchema[itemKey];
1862
+ await item.process();
1863
+ }
1864
+ const cycles = findGraphCycles(this.graphAdjacencyList);
1865
+ for (const cycleItemKeys of cycles) {
1866
+ for (const itemKey of cycleItemKeys) {
1867
+ const item = this.configSchema[itemKey];
1868
+ item.schemaErrors.push(
1869
+ new SchemaError(
1870
+ cycleItemKeys.length === 1 ? "Item cannot have dependency on itself" : `Dependency cycle detected: (${cycleItemKeys.join(", ")})`
1871
+ )
1872
+ );
1873
+ }
1874
+ }
1875
+ }
1876
+ get graphAdjacencyList() {
1877
+ const adjList = {};
1878
+ for (const itemKey in this.configSchema) {
1879
+ const item = this.configSchema[itemKey];
1880
+ adjList[itemKey] = item.valueResolver?.deps || [];
1881
+ }
1882
+ return adjList;
1883
+ }
1884
+ async resolveEnvValues() {
1885
+ const adjList = this.graphAdjacencyList;
1886
+ const reverseAdjList = {};
1887
+ for (const itemKey in adjList) {
1888
+ const itemDeps = adjList[itemKey];
1889
+ for (const dep of itemDeps) {
1890
+ reverseAdjList[dep] ??= [];
1891
+ reverseAdjList[dep].push(itemKey);
1892
+ }
1893
+ }
1894
+ const itemsToResolveStatus = my_dash_default.mapValues(this.configSchema, () => false);
1895
+ const deferred = new Promise((resolve, reject) => {
1896
+ const markItemCompleted = /* @__PURE__ */ __name((itemKey) => {
1897
+ delete itemsToResolveStatus[itemKey];
1898
+ if (reverseAdjList[itemKey]) {
1899
+ reverseAdjList[itemKey].forEach(resolveItem);
1900
+ }
1901
+ if (my_dash_default.keys(itemsToResolveStatus).length === 0) resolve();
1902
+ }, "markItemCompleted");
1903
+ const resolveItem = /* @__PURE__ */ __name(async (itemKey) => {
1904
+ if (itemsToResolveStatus[itemKey] !== false) return;
1905
+ const item = this.configSchema[itemKey];
1906
+ if (item.errors.length) {
1907
+ markItemCompleted(itemKey);
1908
+ return;
1909
+ }
1910
+ for (const depKey of adjList[itemKey]) {
1911
+ const depItem = this.configSchema[depKey];
1912
+ if (depItem.validationState === "error") {
1913
+ item.resolutionError = new ResolutionError(`Dependency ${depKey} is invalid`);
1914
+ markItemCompleted(itemKey);
1915
+ return;
1916
+ } else if (depKey in itemsToResolveStatus) {
1917
+ return;
1918
+ }
1919
+ }
1920
+ itemsToResolveStatus[itemKey] = true;
1921
+ await item.resolve();
1922
+ markItemCompleted(itemKey);
1923
+ }, "resolveItem");
1924
+ for (const itemKey in this.configSchema) {
1925
+ resolveItem(itemKey);
1926
+ }
1927
+ });
1928
+ return deferred;
1929
+ }
1930
+ getResolvedEnvObject() {
1931
+ const envObject = {};
1932
+ for (const itemKey in this.configSchema) {
1933
+ const item = this.configSchema[itemKey];
1934
+ envObject[itemKey] = item.resolvedValue;
1935
+ }
1936
+ return envObject;
1937
+ }
1938
+ getSerializedGraph() {
1939
+ const serializedGraph = {
1940
+ basePath: this.basePath,
1941
+ sources: [],
1942
+ config: {},
1943
+ settings: {}
1944
+ };
1945
+ for (const source of this.sortedDataSources) {
1946
+ serializedGraph.sources.push({
1947
+ label: source.label,
1948
+ enabled: !source.disabled,
1949
+ path: source instanceof FileBasedDataSource ? path.relative(this.basePath ?? "", source.fullPath) : void 0
1950
+ });
1951
+ }
1952
+ for (const itemKey in this.configSchema) {
1953
+ const item = this.configSchema[itemKey];
1954
+ serializedGraph.config[itemKey] = {
1955
+ value: item.resolvedValue,
1956
+ isSensitive: item.isSensitive
1957
+ };
1958
+ }
1959
+ serializedGraph.settings.redactLogs = this.getRootDecoratorValue("redactLogs") ?? true;
1960
+ serializedGraph.settings.preventLeaks = this.getRootDecoratorValue("preventLeaks") ?? true;
1961
+ return serializedGraph;
1962
+ }
1963
+ get isInvalid() {
1964
+ return my_dash_default.some(my_dash_default.values(this.configSchema), (i) => !i.isValid);
1965
+ }
1966
+ async generateTypes(lang, outputPath) {
1967
+ await generateTypes(this, lang, outputPath);
1968
+ }
1969
+ getRootDecoratorValue(decoratorName) {
1970
+ const dec = this.schemaDataSource?.decorators?.[decoratorName];
1971
+ return dec?.simplifiedValue;
1972
+ }
1973
+ };
1974
+
1975
+ // ../env-graph/src/lib/config-item.ts
1976
+ var ConfigItem3 = class {
1977
+ constructor(envGraph, key) {
1978
+ this.envGraph = envGraph;
1979
+ this.key = key;
1980
+ }
1981
+ static {
1982
+ __name(this, "ConfigItem");
1983
+ }
1984
+ defs = [];
1985
+ addDef(itemDef, source) {
1986
+ this.defs.unshift({ itemDef, source });
1987
+ }
1988
+ get description() {
1989
+ for (const def of this.defs) {
1990
+ if (def.itemDef.description) return def.itemDef.description;
1991
+ }
1992
+ }
1993
+ get icon() {
1994
+ const explicitIcon = this.getDecoratorValueString("icon");
1995
+ if (explicitIcon) return explicitIcon;
1996
+ return this.dataType?.icon;
1997
+ }
1998
+ get docsLinks() {
1999
+ const links = [];
2000
+ const docsUrl = this.getDecoratorValueString("docsUrl");
2001
+ if (docsUrl) links.push({ url: docsUrl });
2002
+ return links;
2003
+ }
2004
+ get valueResolver() {
2005
+ for (const def of this.defs) {
2006
+ if (def.itemDef.resolver) return def.itemDef.resolver;
2007
+ }
2008
+ }
2009
+ getDecorator(decoratorName) {
2010
+ for (const def of this.defs) {
2011
+ const defDecorators = def.itemDef.decorators || {};
2012
+ if (decoratorName in defDecorators) {
2013
+ return defDecorators[decoratorName];
2014
+ }
2015
+ }
2016
+ }
2017
+ getDecoratorValueRaw(decoratorName) {
2018
+ for (const def of this.defs) {
2019
+ const defDecorators = def.itemDef.decorators || {};
2020
+ if (decoratorName in defDecorators) {
2021
+ return defDecorators[decoratorName].value;
2022
+ }
2023
+ }
2024
+ }
2025
+ getDecoratorValueString(decoratorName) {
2026
+ const dec = this.getDecoratorValueRaw(decoratorName);
2027
+ if (dec instanceof ParsedEnvSpecStaticValue) return String(dec.value);
2028
+ }
2029
+ dataType;
2030
+ schemaErrors = [];
2031
+ get resolverSchemaErrors() {
2032
+ return this.valueResolver?.schemaErrors || [];
2033
+ }
2034
+ async process() {
2035
+ const finalOverrideDef = this.envGraph.finalOverridesDataSource?.configItemDefs[this.key];
2036
+ if (finalOverrideDef) {
2037
+ this.defs.unshift({ itemDef: finalOverrideDef, source: this.envGraph.finalOverridesDataSource });
2038
+ }
2039
+ for (const def of this.defs) {
2040
+ await def.itemDef.resolver?.process(this);
2041
+ }
2042
+ const typeDecoratorValue = this.getDecoratorValueRaw("type");
2043
+ let dataTypeName;
2044
+ let dataTypeArgs;
2045
+ if (typeDecoratorValue instanceof ParsedEnvSpecStaticValue) {
2046
+ dataTypeName = typeDecoratorValue.value;
2047
+ } else if (typeDecoratorValue instanceof ParsedEnvSpecFunctionCall) {
2048
+ dataTypeName = typeDecoratorValue.name;
2049
+ dataTypeArgs = typeDecoratorValue.simplifiedArgs;
2050
+ }
2051
+ if (!dataTypeName) {
2052
+ if (this.valueResolver?.inferredType) {
2053
+ dataTypeName = this.valueResolver.inferredType;
2054
+ }
2055
+ }
2056
+ dataTypeName ||= "string";
2057
+ dataTypeArgs ||= [];
2058
+ if (!(dataTypeName in this.envGraph.dataTypesRegistry)) {
2059
+ this.schemaErrors.push(new SchemaError(`unknown data type: ${dataTypeName}`));
2060
+ } else {
2061
+ const dataTypeFactory = this.envGraph.dataTypesRegistry[dataTypeName];
2062
+ this.dataType = dataTypeFactory(...my_dash_default.isPlainObject(dataTypeArgs) ? [dataTypeArgs] : dataTypeArgs);
2232
2063
  }
2233
2064
  }
2234
- async finishLoad() {
2235
- const sortedDataSources = this.sortedDataSources;
2236
- for (const source of sortedDataSources) {
2237
- if (source.loadingError) {
2238
- throw source.loadingError;
2065
+ get isRequired() {
2066
+ for (const def of this.defs) {
2067
+ const defDecorators = def.itemDef.decorators || {};
2068
+ if ("required" in defDecorators) {
2069
+ const val = defDecorators.required.simplifiedValue;
2070
+ if (typeof val === "boolean") return val;
2071
+ if (typeof val === "string") return val === "true";
2072
+ return Boolean(val);
2239
2073
  }
2240
- if (source.decorators?.envFlag) {
2241
- if (source.applyForEnv) {
2242
- throw new Error(`@envFlag cannot be set from within an env-specific data source - ${source.label}`);
2243
- } else if (this.envFlagKey) {
2244
- throw new Error("only a single @envFlag setting is allowed");
2245
- } else {
2246
- const envFlagKey = source.decorators.envFlag.simplifiedValue;
2247
- if (!my_dash_default.isString(envFlagKey)) {
2248
- throw new Error("@envFlag must be a string");
2074
+ if ("optional" in defDecorators) {
2075
+ const val = defDecorators.optional.simplifiedValue;
2076
+ if (typeof val === "boolean") return !val;
2077
+ if (typeof val === "string") return val !== "true";
2078
+ return !val;
2079
+ }
2080
+ if ("defaultRequired" in def.source.decorators) {
2081
+ const val = def.source.decorators.defaultRequired.simplifiedValue;
2082
+ if (val === "infer") {
2083
+ if (def.source.type === "schema") {
2084
+ const resolver = def.itemDef.resolver;
2085
+ if (resolver instanceof StaticValueResolver) {
2086
+ return resolver.staticValue !== void 0 && resolver.staticValue !== "";
2087
+ } else {
2088
+ return true;
2089
+ }
2249
2090
  } else {
2250
- this.envFlagKey = envFlagKey;
2091
+ continue;
2251
2092
  }
2252
2093
  }
2094
+ return val;
2253
2095
  }
2254
- if (source.applyForEnv) {
2255
- if (source.applyForEnv && this.envFlagValue !== source.applyForEnv) {
2256
- source.disabled = true;
2257
- continue;
2096
+ }
2097
+ return true;
2098
+ }
2099
+ get isSensitive() {
2100
+ for (const def of this.defs) {
2101
+ const defDecorators = def.itemDef.decorators || {};
2102
+ if ("sensitive" in defDecorators) {
2103
+ return defDecorators.sensitive.simplifiedValue;
2104
+ } else if ("defaultSensitive" in def.source.decorators) {
2105
+ const dec = def.source.decorators.defaultSensitive;
2106
+ if (dec.value instanceof ParsedEnvSpecFunctionCall && dec.value.name === "inferFromPrefix") {
2107
+ const args = dec.value.simplifiedArgs;
2108
+ const prefix = Array.isArray(args) && args.length > 0 ? args[0] : void 0;
2109
+ if (typeof prefix === "string" && this.key.startsWith(prefix)) {
2110
+ return false;
2111
+ }
2112
+ return true;
2258
2113
  }
2114
+ return dec.simplifiedValue;
2259
2115
  }
2260
- if (source.decorators?.disable && source.decorators.disable.simplifiedValue) {
2261
- source.disabled = true;
2262
- continue;
2116
+ }
2117
+ return true;
2118
+ }
2119
+ get errors() {
2120
+ return my_dash_default.compact([
2121
+ ...this.schemaErrors || [],
2122
+ ...this.resolverSchemaErrors || [],
2123
+ this.resolutionError,
2124
+ this.coercionError,
2125
+ ...this.validationErrors || []
2126
+ ]);
2127
+ }
2128
+ get validationState() {
2129
+ const errors = this.errors;
2130
+ if (!errors.length) return "valid";
2131
+ return my_dash_default.some(errors, (e) => !e.isWarning) ? "error" : "warn";
2132
+ }
2133
+ /** resolved value _before coercion_ */
2134
+ resolvedRawValue;
2135
+ isResolved = false;
2136
+ /** resolved value after coercion */
2137
+ resolvedValue;
2138
+ isValidated = false;
2139
+ resolutionError;
2140
+ coercionError;
2141
+ validationErrors;
2142
+ get isCoerced() {
2143
+ return this.resolvedRawValue !== this.resolvedValue;
2144
+ }
2145
+ async resolve() {
2146
+ if (this.schemaErrors.length) return;
2147
+ if (this.resolverSchemaErrors.length) return;
2148
+ if (!this.valueResolver) throw new Error("Expected a resolver to be set");
2149
+ if (this.isResolved) {
2150
+ return;
2151
+ }
2152
+ try {
2153
+ this.resolvedRawValue = await this.valueResolver.resolve();
2154
+ } catch (err) {
2155
+ this.resolutionError = new ResolutionError(`error resolving value: ${err}`);
2156
+ this.resolutionError.cause = err;
2157
+ }
2158
+ if (this.resolvedRawValue instanceof RegExp) {
2159
+ this.resolutionError = new ResolutionError("regex() is meant to be used within function args, not as a final resolved value");
2160
+ }
2161
+ if (this.resolutionError) return;
2162
+ this.isResolved = true;
2163
+ if (this.resolvedRawValue === void 0 || this.resolvedRawValue === "") {
2164
+ this.resolvedValue = this.resolvedRawValue;
2165
+ if (this.isRequired) {
2166
+ this.validationErrors = [new EmptyRequiredValueError(void 0)];
2263
2167
  }
2264
- for (const itemKey in source.configItemDefs) {
2265
- if (source.ignoreNewDefs && !this.configSchema[itemKey]) continue;
2266
- const itemDef = source.configItemDefs[itemKey];
2267
- this.configSchema[itemKey] ??= new ConfigItem(this, itemKey);
2268
- this.configSchema[itemKey].addDef(itemDef, source);
2168
+ return;
2169
+ }
2170
+ if (!this.dataType) throw new Error("expected dataType to be set");
2171
+ try {
2172
+ const coerceResult = this.dataType.coerce(this.resolvedRawValue);
2173
+ if (coerceResult instanceof Error) throw coerceResult;
2174
+ this.resolvedValue = coerceResult;
2175
+ } catch (err) {
2176
+ if (err instanceof CoercionError) {
2177
+ this.coercionError = err;
2178
+ return;
2179
+ } else if (err instanceof Error) {
2180
+ this.coercionError = new CoercionError("Unexpected error coercing value");
2181
+ this.coercionError.cause = err;
2182
+ } else {
2183
+ this.coercionError = new CoercionError(`Unexpected non-error throw during coerce - ${err}`);
2269
2184
  }
2270
- if (source.type === "schema" && this.envFlagKey) {
2271
- if (!this.configSchema[this.envFlagKey]) {
2272
- throw new Error(`@envFlag key ${this.envFlagKey} not found in schema`);
2273
- }
2274
- const envFlagItem = this.configSchema[this.envFlagKey];
2275
- await envFlagItem.process();
2276
- for (const depKey of envFlagItem.valueResolver?.deps || []) {
2277
- const depItem = this.configSchema[depKey];
2278
- if (!depItem) {
2279
- throw new Error(`envFlag resolver is using non-existant dependency: ${depKey}`);
2280
- }
2281
- await depItem.process();
2282
- if (depItem.valueResolver?.deps.length) {
2283
- throw new Error("envFlag cannot follow a chain of dependencies");
2284
- }
2285
- await depItem.resolve();
2286
- }
2287
- await envFlagItem.resolve();
2288
- if (!envFlagItem.isValid) {
2289
- const err = new Error("resolved @envFlag value is not valid");
2290
- err.cause = envFlagItem.errors[0];
2291
- throw err;
2292
- }
2293
- if (envFlagItem.resolvedValue) {
2294
- if (!my_dash_default.isString(envFlagItem.resolvedValue)) {
2295
- throw new Error("expected resolved @envFlag value to be a string");
2296
- }
2297
- this.envFlagValue = envFlagItem.resolvedValue;
2298
- }
2185
+ return;
2186
+ }
2187
+ try {
2188
+ const validateResult = this.dataType.validate(this.resolvedValue);
2189
+ if (validateResult instanceof Error || my_dash_default.isArray(validateResult) && validateResult[0] instanceof Error) throw validateResult;
2190
+ if (validateResult === false) {
2191
+ throw new ValidationError("validation failed with `false` return value");
2192
+ }
2193
+ this.isValidated = true;
2194
+ } catch (err) {
2195
+ if (my_dash_default.isArray(err)) {
2196
+ this.validationErrors = err;
2197
+ } else if (err instanceof ValidationError) {
2198
+ this.validationErrors = [err];
2199
+ } else if (err instanceof Error) {
2200
+ const validationError = new ValidationError("Unexpected error during validation");
2201
+ validationError.cause = err;
2202
+ console.log(err);
2203
+ this.validationErrors = [validationError];
2204
+ } else {
2205
+ const validationError = new ValidationError(`Unexpected non-error thrown during validation - ${err}`);
2206
+ validationError.cause = err;
2207
+ this.validationErrors = [validationError];
2208
+ }
2209
+ return;
2210
+ }
2211
+ }
2212
+ get isValid() {
2213
+ return this.validationState === "valid";
2214
+ }
2215
+ };
2216
+
2217
+ // ../env-graph/src/lib/data-source.ts
2218
+ var DATA_SOURCE_TYPES = Object.freeze({
2219
+ schema: {
2220
+ fileSuffixes: ["schema"],
2221
+ precedence: 0
2222
+ },
2223
+ example: {
2224
+ fileSuffixes: ["sample", "example"],
2225
+ precedence: 1
2226
+ },
2227
+ defaults: {
2228
+ fileSuffixes: ["default", "defaults"],
2229
+ precedence: 2
2230
+ },
2231
+ values: {
2232
+ fileSuffixes: [],
2233
+ precedence: 3
2234
+ },
2235
+ overrides: {
2236
+ fileSuffixes: ["local", "override"],
2237
+ precedence: 4
2238
+ }
2239
+ });
2240
+ var EnvGraphDataSource = class {
2241
+ static {
2242
+ __name(this, "EnvGraphDataSource");
2243
+ }
2244
+ static DATA_SOURCE_TYPES = DATA_SOURCE_TYPES;
2245
+ // reference back to the graph
2246
+ graph;
2247
+ type = "values";
2248
+ applyForEnv;
2249
+ disabled = false;
2250
+ ignoreNewDefs = false;
2251
+ /** an error encountered while loading/parsing the data source */
2252
+ loadingError;
2253
+ get isValid() {
2254
+ return !this.loadingError;
2255
+ }
2256
+ configItemDefs = {};
2257
+ decorators = {};
2258
+ getStaticValues() {
2259
+ const obj = {};
2260
+ for (const [key, def] of Object.entries(this.configItemDefs)) {
2261
+ if (def.resolver instanceof StaticValueResolver) {
2262
+ obj[key] = String(def.resolver.staticValue ?? "");
2299
2263
  }
2300
2264
  }
2301
- for (const itemKey in this.configSchema) {
2302
- const item = this.configSchema[itemKey];
2303
- await item.process();
2265
+ return obj;
2266
+ }
2267
+ };
2268
+ var ProcessEnvDataSource2 = class _ProcessEnvDataSource extends EnvGraphDataSource {
2269
+ static {
2270
+ __name(this, "ProcessEnvDataSource");
2271
+ }
2272
+ type = "overrides";
2273
+ typeLabel = "process";
2274
+ label = "process.env";
2275
+ ignoreNewDefs = true;
2276
+ static processEnvValues;
2277
+ // ? do we want to set decorator values from env vars here? -- ex: _ENV_FLAG_KEY
2278
+ // depends if we want those to work only within process.env
2279
+ constructor() {
2280
+ super();
2281
+ if (!_ProcessEnvDataSource.processEnvValues) {
2282
+ _ProcessEnvDataSource.processEnvValues = {};
2283
+ for (const itemKey of Object.keys(process.env)) {
2284
+ _ProcessEnvDataSource.processEnvValues[itemKey] = process.env[itemKey];
2285
+ }
2304
2286
  }
2305
- const cycles = findGraphCycles(this.graphAdjacencyList);
2306
- for (const cycleItemKeys of cycles) {
2307
- for (const itemKey of cycleItemKeys) {
2308
- const item = this.configSchema[itemKey];
2309
- item.schemaErrors.push(
2310
- new SchemaError(
2311
- cycleItemKeys.length === 1 ? "Item cannot have dependency on itself" : `Dependency cycle detected: (${cycleItemKeys.join(", ")})`
2312
- )
2313
- );
2287
+ for (const itemKey of Object.keys(_ProcessEnvDataSource.processEnvValues)) {
2288
+ this.configItemDefs[itemKey] = {
2289
+ resolver: new StaticValueResolver(_ProcessEnvDataSource.processEnvValues[itemKey])
2290
+ };
2291
+ }
2292
+ }
2293
+ };
2294
+ var EnvSourceParseError = class extends Error {
2295
+ constructor(message, location) {
2296
+ super(message);
2297
+ this.location = location;
2298
+ }
2299
+ static {
2300
+ __name(this, "EnvSourceParseError");
2301
+ }
2302
+ };
2303
+ var FileBasedDataSource = class extends EnvGraphDataSource {
2304
+ static {
2305
+ __name(this, "FileBasedDataSource");
2306
+ }
2307
+ isGitIgnored;
2308
+ fullPath;
2309
+ fileName;
2310
+ rawContents;
2311
+ get typeLabel() {
2312
+ return this.constructor.format;
2313
+ }
2314
+ get label() {
2315
+ return this.fileName;
2316
+ }
2317
+ static format = "unknown";
2318
+ // no abstract static
2319
+ static validFileExtensions = [];
2320
+ get validFileExtensions() {
2321
+ return this.constructor.validFileExtensions;
2322
+ }
2323
+ constructor(fullPath, opts) {
2324
+ super();
2325
+ this.fullPath = fullPath;
2326
+ this.fileName = path.basename(fullPath);
2327
+ if (opts?.overrideContents) {
2328
+ this.rawContents = opts.overrideContents;
2329
+ this.isGitIgnored = opts.overrideGitIgnored;
2330
+ }
2331
+ if (!this.fileName.startsWith(".env")) {
2332
+ throw new Error('file name must start with ".env"');
2333
+ }
2334
+ const fileNameParts = this.fileName.substring(1).split(".");
2335
+ const maybeExtension = fileNameParts[fileNameParts.length - 1];
2336
+ if (this.validFileExtensions.includes(maybeExtension)) {
2337
+ fileNameParts.pop();
2338
+ }
2339
+ const maybeFileType = fileNameParts[fileNameParts.length - 1];
2340
+ for (const [possibleSourceType, possibleSourceSpec] of Object.entries(DATA_SOURCE_TYPES)) {
2341
+ if (possibleSourceSpec.fileSuffixes.includes(maybeFileType)) {
2342
+ this.type = possibleSourceType;
2343
+ break;
2314
2344
  }
2315
2345
  }
2346
+ if (this.type !== "values") fileNameParts.pop();
2347
+ if (fileNameParts.length > 2) {
2348
+ throw Error(`Unsure how to interpret filename - ${this.fileName}`);
2349
+ } else if (fileNameParts.length === 2) {
2350
+ this.applyForEnv = fileNameParts[1];
2351
+ if (this.applyForEnv === "dev") this.applyForEnv = "development";
2352
+ if (this.applyForEnv === "stage") this.applyForEnv = "staging";
2353
+ if (this.applyForEnv === "prod") this.applyForEnv = "production";
2354
+ }
2316
2355
  }
2317
- get graphAdjacencyList() {
2318
- const adjList = {};
2319
- for (const itemKey in this.configSchema) {
2320
- const item = this.configSchema[itemKey];
2321
- adjList[itemKey] = item.valueResolver?.deps || [];
2356
+ // no async constructors... :(
2357
+ async finishInit() {
2358
+ if (!this.rawContents) {
2359
+ this.isGitIgnored = await checkIsFileGitIgnored(this.fullPath);
2360
+ this.rawContents = await fs2.readFile(this.fullPath, "utf8");
2322
2361
  }
2323
- return adjList;
2362
+ await this._parseContents();
2324
2363
  }
2325
- async resolveEnvValues() {
2326
- const adjList = this.graphAdjacencyList;
2327
- const reverseAdjList = {};
2328
- for (const itemKey in adjList) {
2329
- const itemDeps = adjList[itemKey];
2330
- for (const dep of itemDeps) {
2331
- reverseAdjList[dep] ??= [];
2332
- reverseAdjList[dep].push(itemKey);
2364
+ };
2365
+ var DotEnvFileDataSource = class extends FileBasedDataSource {
2366
+ static {
2367
+ __name(this, "DotEnvFileDataSource");
2368
+ }
2369
+ static format = ".env";
2370
+ static validFileExtensions = [];
2371
+ // no extension for dotenv files!
2372
+ parsedFile;
2373
+ convertParserValueToResolvers(value) {
2374
+ if (!this.graph) throw new Error("expected graph to be set");
2375
+ if (value === void 0) {
2376
+ return new StaticValueResolver(void 0);
2377
+ } else if (value instanceof ParsedEnvSpecStaticValue) {
2378
+ return new StaticValueResolver(value.unescapedValue);
2379
+ } else if (value instanceof ParsedEnvSpecFunctionCall) {
2380
+ const ResolverFnClass = this.graph.registeredResolverFunctions[value.name];
2381
+ if (!ResolverFnClass) {
2382
+ return new ErrorResolver(new SchemaError(`Unknown resolver function: ${value.name}()`));
2333
2383
  }
2334
- }
2335
- const itemsToResolveStatus = my_dash_default.mapValues(this.configSchema, () => false);
2336
- const deferred = new Promise((resolve, reject) => {
2337
- const markItemCompleted = /* @__PURE__ */ __name((itemKey) => {
2338
- delete itemsToResolveStatus[itemKey];
2339
- if (reverseAdjList[itemKey]) {
2340
- reverseAdjList[itemKey].forEach(resolveItem);
2341
- }
2342
- if (my_dash_default.keys(itemsToResolveStatus).length === 0) resolve();
2343
- }, "markItemCompleted");
2344
- const resolveItem = /* @__PURE__ */ __name(async (itemKey) => {
2345
- if (itemsToResolveStatus[itemKey] !== false) return;
2346
- const item = this.configSchema[itemKey];
2347
- if (item.errors.length) {
2348
- markItemCompleted(itemKey);
2349
- return;
2350
- }
2351
- for (const depKey of adjList[itemKey]) {
2352
- const depItem = this.configSchema[depKey];
2353
- if (depItem.validationState === "error") {
2354
- item.resolutionError = new ResolutionError(`Dependency ${depKey} is invalid`);
2355
- markItemCompleted(itemKey);
2356
- return;
2357
- } else if (depKey in itemsToResolveStatus) {
2358
- return;
2384
+ const argsFromParser = value.data.args.values;
2385
+ let keyValueArgs;
2386
+ const argsAsResolversArray = [];
2387
+ for (const arg of argsFromParser) {
2388
+ if (arg instanceof ParsedEnvSpecKeyValuePair) {
2389
+ keyValueArgs ??= {};
2390
+ keyValueArgs[arg.key] = this.convertParserValueToResolvers(arg.value);
2391
+ } else {
2392
+ if (keyValueArgs) {
2393
+ return new ErrorResolver(new SchemaError("After switching to key-value function args, cannot switch back"));
2359
2394
  }
2395
+ argsAsResolversArray.push(this.convertParserValueToResolvers(arg));
2360
2396
  }
2361
- itemsToResolveStatus[itemKey] = true;
2362
- await item.resolve();
2363
- markItemCompleted(itemKey);
2364
- }, "resolveItem");
2365
- for (const itemKey in this.configSchema) {
2366
- resolveItem(itemKey);
2367
2397
  }
2368
- });
2369
- return deferred;
2370
- }
2371
- getResolvedEnvObject() {
2372
- const envObject = {};
2373
- for (const itemKey in this.configSchema) {
2374
- const item = this.configSchema[itemKey];
2375
- envObject[itemKey] = item.resolvedValue;
2398
+ if (keyValueArgs) argsAsResolversArray.push(keyValueArgs);
2399
+ return new ResolverFnClass(argsAsResolversArray);
2400
+ } else {
2401
+ throw new Error("Unknown value type");
2376
2402
  }
2377
- return envObject;
2378
2403
  }
2379
- getSerializedGraph() {
2380
- const serializedGraph = {
2381
- sources: [],
2382
- config: {},
2383
- settings: {}
2384
- };
2385
- for (const source of this.sortedDataSources) {
2386
- serializedGraph.sources.push({
2387
- label: source.label,
2388
- enabled: !source.disabled
2389
- });
2390
- }
2391
- for (const itemKey in this.configSchema) {
2392
- const item = this.configSchema[itemKey];
2393
- serializedGraph.config[itemKey] = {
2394
- value: item.resolvedValue,
2395
- isSensitive: item.isSensitive
2404
+ async _parseContents() {
2405
+ const rawContents = this.rawContents;
2406
+ this.parsedFile = await tryCatch(
2407
+ () => parseEnvSpecDotEnvFile(rawContents),
2408
+ (error) => {
2409
+ this.loadingError = new EnvSourceParseError(error.message, {
2410
+ path: this.fullPath,
2411
+ lineNumber: error.location.start.line,
2412
+ colNumber: error.location.start.column,
2413
+ lineStr: rawContents.split("\n")[error.location.start.line - 1]
2414
+ });
2415
+ this.loadingError.cause = error;
2416
+ }
2417
+ );
2418
+ if (this.loadingError) return;
2419
+ if (!this.parsedFile) throw new Error("Failed to parse .env file");
2420
+ this.decorators = this.parsedFile.decoratorsObject;
2421
+ if (!this.graph) throw new Error("expected graph to be set");
2422
+ for (const item of this.parsedFile.configItems) {
2423
+ item.processExpansion();
2424
+ this.configItemDefs[item.key] = {
2425
+ resolver: this.convertParserValueToResolvers(item.expandedValue),
2426
+ description: item.description,
2427
+ decorators: item.decoratorsObject
2396
2428
  };
2397
2429
  }
2398
- serializedGraph.settings.redactLogs = this.getRootDecoratorValue("redactLogs") ?? true;
2399
- serializedGraph.settings.preventLeaks = this.getRootDecoratorValue("preventLeaks") ?? true;
2400
- return serializedGraph;
2401
- }
2402
- get isInvalid() {
2403
- return my_dash_default.some(my_dash_default.values(this.configSchema), (i) => !i.isValid);
2404
- }
2405
- async generateTypes(lang, outputPath) {
2406
- await generateTypes(this, lang, outputPath);
2407
- }
2408
- getRootDecoratorValue(decoratorName) {
2409
- const dec = this.schemaDataSource?.decorators?.[decoratorName];
2410
- return dec?.simplifiedValue;
2411
2430
  }
2412
2431
  };
2413
- var SKIP_FILE_TYPES = [".md", ".d.ts"];
2414
- async function findEnvFiles(opts) {
2415
- const cwd = opts?.cwd || process.cwd();
2416
- const envFiles = [];
2417
- const filesWithinDir = await fs.readdir(cwd);
2418
- for (const fileName of filesWithinDir) {
2419
- if (fileName.startsWith(".env")) {
2420
- let skip = false;
2421
- for (const fileType of SKIP_FILE_TYPES) {
2422
- if (fileName.endsWith(fileType)) skip = true;
2423
- }
2424
- if (skip) continue;
2425
- envFiles.push(path.join(cwd, fileName));
2426
- }
2427
- }
2428
- return envFiles;
2429
- }
2430
- __name(findEnvFiles, "findEnvFiles");
2431
-
2432
- // ../env-graph/src/lib/loader.ts
2433
- function autoDetectContextPath() {
2434
- const PWD = process.env.PWD;
2435
- if (!PWD) {
2436
- throw new Error("PWD is not set");
2437
- }
2438
- return PWD;
2439
- }
2440
- __name(autoDetectContextPath, "autoDetectContextPath");
2441
- async function loadEnvGraph(opts) {
2442
- const contextPath = opts?.contextPath ?? autoDetectContextPath();
2443
- const graph = new EnvGraph();
2444
- graph.basePath = contextPath;
2445
- if (opts?.afterInit) {
2446
- await opts.afterInit(graph);
2447
- }
2448
- if (opts?.currentEnvFallback) {
2449
- graph.envFlagValue = opts.currentEnvFallback;
2450
- }
2451
- const envFilePaths = await findEnvFiles({
2452
- cwd: contextPath
2453
- });
2454
- for (const envFilePath of envFilePaths) {
2455
- const fileDataSource = new DotEnvFileDataSource(envFilePath);
2456
- graph.addDataSource(fileDataSource);
2457
- await fileDataSource.finishInit();
2458
- }
2459
- graph.finalOverridesDataSource = new ProcessEnvDataSource();
2460
- await graph.finishLoad();
2461
- return graph;
2462
- }
2463
- __name(loadEnvGraph, "loadEnvGraph");
2464
2432
 
2465
- export { DotEnvFileDataSource, EnvSourceParseError, StaticValueResolver, checkIsFileGitIgnored, loadEnvGraph, my_dash_default };
2466
- //# sourceMappingURL=chunk-TYL3Q4QG.js.map
2467
- //# sourceMappingURL=chunk-TYL3Q4QG.js.map
2433
+ export { DotEnvFileDataSource, EnvGraph2 as EnvGraph, EnvSourceParseError, ProcessEnvDataSource2 as ProcessEnvDataSource, StaticValueResolver, checkIsFileGitIgnored, my_dash_default };
2434
+ //# sourceMappingURL=chunk-K2N2TG4M.js.map
2435
+ //# sourceMappingURL=chunk-K2N2TG4M.js.map