@flowscripter/dynamic-cli-framework 12.0.1 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -0
  4. package/dist/src/cli/BaseCLI.d.ts.map +1 -1
  5. package/dist/src/cli/BaseCLI.js +3 -1
  6. package/dist/src/cli/BaseCLIFeatureOptions.d.ts +6 -0
  7. package/dist/src/cli/BaseCLIFeatureOptions.d.ts.map +1 -1
  8. package/dist/src/service/configuration/ConfigurationServiceProvider.d.ts +11 -3
  9. package/dist/src/service/configuration/ConfigurationServiceProvider.d.ts.map +1 -1
  10. package/dist/src/service/configuration/ConfigurationServiceProvider.js +28 -11
  11. package/dist/src/service/configuration/format/ConfigFormat.d.ts +42 -0
  12. package/dist/src/service/configuration/format/ConfigFormat.d.ts.map +1 -0
  13. package/dist/src/service/configuration/format/ConfigFormat.js +0 -0
  14. package/dist/src/service/configuration/format/JsonConfigFormat.d.ts +7 -0
  15. package/dist/src/service/configuration/format/JsonConfigFormat.d.ts.map +1 -0
  16. package/dist/src/service/configuration/format/JsonConfigFormat.js +17 -0
  17. package/dist/src/service/configuration/format/TomlConfigFormat.d.ts +10 -0
  18. package/dist/src/service/configuration/format/TomlConfigFormat.d.ts.map +1 -0
  19. package/dist/src/service/configuration/format/TomlConfigFormat.js +78 -0
  20. package/dist/src/service/configuration/format/YamlConfigFormat.d.ts +9 -0
  21. package/dist/src/service/configuration/format/YamlConfigFormat.d.ts.map +1 -0
  22. package/dist/src/service/configuration/format/YamlConfigFormat.js +63 -0
  23. package/dist/toml.d.ts +2 -0
  24. package/dist/toml.d.ts.map +1 -0
  25. package/dist/toml.js +1 -0
  26. package/dist/yaml.d.ts +2 -0
  27. package/dist/yaml.d.ts.map +1 -0
  28. package/dist/yaml.js +1 -0
  29. package/index.ts +3 -0
  30. package/package.json +27 -3
  31. package/src/cli/BaseCLI.ts +3 -0
  32. package/src/cli/BaseCLIFeatureOptions.ts +6 -0
  33. package/src/service/configuration/ConfigurationServiceProvider.ts +36 -10
  34. package/src/service/configuration/format/ConfigFormat.ts +42 -0
  35. package/src/service/configuration/format/JsonConfigFormat.ts +22 -0
  36. package/src/service/configuration/format/TomlConfigFormat.ts +92 -0
  37. package/src/service/configuration/format/YamlConfigFormat.ts +72 -0
  38. package/toml.ts +1 -0
  39. package/yaml.ts +1 -0
package/dist/index.d.ts CHANGED
@@ -36,6 +36,9 @@ export { default as DefaultSecretService } from "./src/service/configuration/Def
36
36
  export type { SecretsApi } from "./src/service/configuration/DefaultSecretService.ts";
37
37
  export { default as ConfigCommand } from "./src/service/configuration/command/ConfigCommand.ts";
38
38
  export { default as ConfigurationServiceProvider, type KeyValueServiceScopeType, } from "./src/service/configuration/ConfigurationServiceProvider.ts";
39
+ export type { default as ConfigFormat } from "./src/service/configuration/format/ConfigFormat.ts";
40
+ export type { ConfigData } from "./src/service/configuration/format/ConfigFormat.ts";
41
+ export { default as jsonFormat } from "./src/service/configuration/format/JsonConfigFormat.ts";
39
42
  export { default as KeyValueServiceProvider } from "./src/service/configuration/KeyValueServiceProvider.ts";
40
43
  export { PRINTER_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
41
44
  export type { PrinterService } from "@flowscripter/dynamic-cli-framework-api";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,QAAQ,EAAE,MAAM,yCAAyC,CAAC;AACxE,YAAY,EACV,eAAe,EACf,MAAM,EACN,SAAS,EACT,wBAAwB,EACxB,eAAe,EACf,kBAAkB,GACnB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC9F,YAAY,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,oCAAoC,EAAE,MAAM,yCAAyC,CAAC;AAC/F,YAAY,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAClF,OAAO,EAAE,2BAA2B,EAAE,MAAM,yCAAyC,CAAC;AACtF,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACrF,YAAY,EAAE,MAAM,EAAE,MAAM,yCAAyC,CAAC;AACtE,YAAY,EAAE,UAAU,EAAE,MAAM,yCAAyC,CAAC;AAG1E,YAAY,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,YAAY,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACrF,YAAY,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC5E,YAAY,EAAE,UAAU,EAAE,MAAM,yCAAyC,CAAC;AAC1E,YAAY,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAG5E,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAG5F,YAAY,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,YAAY,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAGvF,OAAO,EAAE,iCAAiC,EAAE,MAAM,yCAAyC,CAAC;AAC5F,YAAY,EAAE,2BAA2B,EAAE,MAAM,yCAAyC,CAAC;AAC3F,YAAY,EACV,kBAAkB,EAClB,qBAAqB,EACrB,WAAW,EACX,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,GACnB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,kCAAkC,EAAE,MAAM,0EAA0E,CAAC;AACzI,OAAO,EAAE,OAAO,IAAI,mCAAmC,EAAE,MAAM,2EAA2E,CAAC;AAC3I,OAAO,EAAE,OAAO,IAAI,qCAAqC,EAAE,MAAM,mFAAmF,CAAC;AACrJ,YAAY,EACV,kBAAkB,EAClB,2BAA2B,GAC5B,MAAM,mFAAmF,CAAC;AAE3F,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AAE/F,OAAO,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACnF,YAAY,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACjF,YAAY,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,YAAY,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,uDAAuD,CAAC;AAC1G,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,qDAAqD,CAAC;AACtG,YAAY,EAAE,UAAU,EAAE,MAAM,qDAAqD,CAAC;AACtF,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,sDAAsD,CAAC;AAChG,OAAO,EACL,OAAO,IAAI,4BAA4B,EACvC,KAAK,wBAAwB,GAC9B,MAAM,6DAA6D,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,wDAAwD,CAAC;AAE5G,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,YAAY,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AACnG,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AAClG,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iDAAiD,CAAC;AAEpG,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAC9E,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC7F,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,kDAAkD,CAAC;AACrG,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAEvG,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,YAAY,EACV,cAAc,EACd,WAAW,EACX,kBAAkB,EAClB,eAAe,GAChB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AAClG,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,iDAAiD,CAAC;AAEpG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAC1F,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAE9F,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAC3E,YAAY,EACV,YAAY,EACZ,WAAW,EACX,YAAY,GACb,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AAC5F,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AAE9F,OAAO,EAAE,6BAA6B,EAAE,MAAM,yCAAyC,CAAC;AACxF,YAAY,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACxF,YAAY,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,+BAA+B,EAAE,MAAM,oEAAoE,CAAC;AAChI,OAAO,EAAE,OAAO,IAAI,gCAAgC,EAAE,MAAM,qEAAqE,CAAC;AAElI,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACpF,YAAY,EAAE,oBAAoB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,4DAA4D,CAAC;AACpH,OAAO,EAAE,OAAO,IAAI,4BAA4B,EAAE,MAAM,6DAA6D,CAAC;AAEtH,OAAO,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACnF,YAAY,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,0DAA0D,CAAC;AACjH,OAAO,EAAE,OAAO,IAAI,2BAA2B,EAAE,MAAM,2DAA2D,CAAC;AAEnH,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAClF,YAAY,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAClF,YAAY,EAAE,QAAQ,EAAE,MAAM,yCAAyC,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,wDAAwD,CAAC;AAC9G,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,yDAAyD,CAAC;AAEhH,OAAO,EAAE,0BAA0B,EAAE,MAAM,yCAAyC,CAAC;AACrF,YAAY,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACrF,OAAO,EACL,KAAK,EACL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,YAAY,GAClB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,yCAAyC,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,4BAA4B,EAAE,MAAM,8DAA8D,CAAC;AACvH,OAAO,EAAE,OAAO,IAAI,6BAA6B,EAAE,MAAM,+DAA+D,CAAC;AAEzH,OAAO,EAAE,8BAA8B,EAAE,MAAM,yCAAyC,CAAC;AACzF,YAAY,EAAE,wBAAwB,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,EACL,KAAK,cAAc,EACnB,UAAU,EACV,KAAK,sBAAsB,GAC5B,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,+BAA+B,EAAE,MAAM,oEAAoE,CAAC;AAChI,OAAO,EAAE,OAAO,IAAI,gCAAgC,EAAE,MAAM,qEAAqE,CAAC;AAElI,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,YAAY,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AACjF,OAAO,EAAE,KAAK,cAAc,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,sDAAsD,CAAC;AAC3G,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,uDAAuD,CAAC;AAE7G,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAC9E,YAAY,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EACL,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,UAAU,GACX,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,kDAAkD,CAAC;AACrG,OAAO,EACL,uBAAuB,EACvB,KAAK,qBAAqB,GAC3B,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAEvG,OAAO,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AACvF,YAAY,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AACvF,YAAY,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,8BAA8B,EAAE,MAAM,kEAAkE,CAAC;AAC7H,OAAO,EAAE,OAAO,IAAI,+BAA+B,EAAE,MAAM,mEAAmE,CAAC;AAG/H,YAAY,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,YAAY,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,YAAY,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,MAAM,yCAAyC,CAAC;AAC1F,YAAY,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3F,YAAY,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,YAAY,EAAE,GAAG,EAAE,MAAM,yCAAyC,CAAC;AAGnE,OAAO,EACL,iCAAiC,EACjC,8BAA8B,GAC/B,MAAM,8CAA8C,CAAC;AACtD,OAAO,EACL,gCAAgC,EAChC,6BAA6B,GAC9B,MAAM,6CAA6C,CAAC;AAGrD,YAAY,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAC9E,OAAO,EAAE,qDAAqD,EAAE,MAAM,yCAAyC,CAAC;AAChH,YAAY,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACtF,OAAO,EAAE,8DAA8D,EAAE,MAAM,yCAAyC,CAAC;AACzH,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,+CAA+C,CAAC;AAGjG,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EACL,yBAAyB,EACzB,wBAAwB,EACxB,8BAA8B,EAC9B,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,EACzB,gCAAgC,EAChC,kCAAkC,EAClC,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,mCAAmC,EACnC,8BAA8B,EAC9B,uBAAuB,EACvB,kCAAkC,EAClC,2BAA2B,EAC3B,8BAA8B,EAC9B,sCAAsC,GACvC,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAG9E,YAAY,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACtE,YAAY,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,OAAO,IAAI,SAAS,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGzE,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -14,6 +14,7 @@ export { default as DefaultKeyValueService } from "./src/service/configuration/D
14
14
  export { default as DefaultSecretService } from "./src/service/configuration/DefaultSecretService.js";
15
15
  export { default as ConfigCommand } from "./src/service/configuration/command/ConfigCommand.js";
16
16
  export { default as ConfigurationServiceProvider, } from "./src/service/configuration/ConfigurationServiceProvider.js";
17
+ export { default as jsonFormat } from "./src/service/configuration/format/JsonConfigFormat.js";
17
18
  export { default as KeyValueServiceProvider } from "./src/service/configuration/KeyValueServiceProvider.js";
18
19
  export { PRINTER_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
19
20
  export { Icon, Level, ProgressStyle, SpinnerStyle } from "@flowscripter/dynamic-cli-framework-api";
@@ -1 +1 @@
1
- {"version":3,"file":"BaseCLI.d.ts","sourceRoot":"","sources":["../../../src/cli/BaseCLI.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yCAAyC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAGvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsBzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAU3E,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,MAAM,MAAM,uBAAuB,CAAC;AAEhD,OAAO,KAAK,SAAS,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,qBAAqB,MAAM,4BAA4B,CAAC;AAqCpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,CAAC,OAAO,OAAO,OAAQ,YAAW,GAAG;;IAazC,YACE,SAAS,EAAE,SAAS,EACpB,oBAAoB,EAAE,cAAc,EACpC,oBAAoB,EAAE,cAAc,EACpC,aAAa,EAAE,OAAO,EACtB,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,QAAQ,EACxB,cAAc,EAAE,QAAQ,EACxB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,OAAO,CAAC,EAAE,qBAAqB,EAuEhC;IAED;;;;;;;OAOG;IACI,kBAAkB,CAAC,eAAe,EAAE,eAAe,QAEzD;IAED;;;;;;;;OAQG;IACH;;;;;OAKG;IACI,cAAc,CAAC,IAAI,EAAE,WAAW,QAEtC;IAEM,UAAU,CAAC,OAAO,EAAE,OAAO,QAQjC;IAEK,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CA2QzD;CACF"}
1
+ {"version":3,"file":"BaseCLI.d.ts","sourceRoot":"","sources":["../../../src/cli/BaseCLI.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,yCAAyC,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAGvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAsBzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yCAAyC,CAAC;AAW3E,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AAGpD,OAAO,KAAK,MAAM,MAAM,uBAAuB,CAAC;AAEhD,OAAO,KAAK,SAAS,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,qBAAqB,MAAM,4BAA4B,CAAC;AAqCpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,MAAM,CAAC,OAAO,OAAO,OAAQ,YAAW,GAAG;;IAazC,YACE,SAAS,EAAE,SAAS,EACpB,oBAAoB,EAAE,cAAc,EACpC,oBAAoB,EAAE,cAAc,EACpC,aAAa,EAAE,OAAO,EACtB,aAAa,EAAE,OAAO,EACtB,cAAc,EAAE,QAAQ,EACxB,cAAc,EAAE,QAAQ,EACxB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,GAAG,SAAS,EAChC,OAAO,CAAC,EAAE,qBAAqB,EAwEhC;IAED;;;;;;;OAOG;IACI,kBAAkB,CAAC,eAAe,EAAE,eAAe,QAEzD;IAED;;;;;;;;OAQG;IACH;;;;;OAKG;IACI,cAAc,CAAC,IAAI,EAAE,WAAW,QAEtC;IAEM,UAAU,CAAC,OAAO,EAAE,OAAO,QAQjC;IAEK,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,CA4QzD;CACF"}
@@ -12,6 +12,7 @@ import CommandValidator from "../runtime/command/CommandValidator.js";
12
12
  import ShutdownServiceProvider from "../service/shutdown/ShutdownServiceProvider.js";
13
13
  import StartupServiceProvider from "../service/startup/StartupServiceProvider.js";
14
14
  import { shutdownState } from "../service/shutdown/ShutdownState.js";
15
+ import jsonFormat from "../service/configuration/format/JsonConfigFormat.js";
15
16
  import ConfigurationServiceProvider from "../service/configuration/ConfigurationServiceProvider.js";
16
17
  import KeyValueServiceProvider from "../service/configuration/KeyValueServiceProvider.js";
17
18
  import PrinterServiceProvider from "../service/printer/PrinterServiceProvider.js";
@@ -100,6 +101,7 @@ export default class BaseCLI {
100
101
  }
101
102
  this.#cliConfig = cliConfig;
102
103
  this.#options = {
104
+ configFormat: jsonFormat,
103
105
  configFileSupportEnabled: false,
104
106
  envVarsSupportEnabled: false,
105
107
  keyValueServiceEnabled: false,
@@ -245,7 +247,7 @@ export default class BaseCLI {
245
247
  if (this.#options.pluginServiceEnabled) {
246
248
  this.addServiceProvider(new PluginServiceProvider(PLUGIN_SERVICE_PRIORITY, this.#options.pluginServiceRemoteConfig, this.#options.pluginServiceLocalConfig, this.#commandRegistry, this.#serviceProviderRegistry));
247
249
  }
248
- const configurationServiceProvider = new ConfigurationServiceProvider(CONFIGURATION_SERVICE_PRIORITY, this.#options.envVarsSupportEnabled, this.#options.configFileSupportEnabled, this.#options.secretServiceEnabled);
250
+ const configurationServiceProvider = new ConfigurationServiceProvider(CONFIGURATION_SERVICE_PRIORITY, this.#options.envVarsSupportEnabled, this.#options.configFileSupportEnabled, this.#options.secretServiceEnabled, this.#options.configFormat);
249
251
  this.addServiceProvider(configurationServiceProvider);
250
252
  const keyValueServiceProvider = new KeyValueServiceProvider(KEY_VALUE_SERVICE_PRIORITY, configurationServiceProvider, this.#options.keyValueServiceEnabled, this.#options.secretServiceEnabled);
251
253
  this.addServiceProvider(keyValueServiceProvider);
@@ -1,7 +1,13 @@
1
+ import type ConfigFormat from "../service/configuration/format/ConfigFormat.ts";
1
2
  import type { UpgradeLocationsConfig } from "../service/upgrade/UpgradeLocationsConfig.ts";
2
3
  import type { NpmjsPluginRepositoryConfig, NpmPluginRepositoryConfig } from "@flowscripter/dynamic-plugin-framework";
3
4
  export default interface BaseCLIFeatureOptions {
4
5
  readonly configFileSupportEnabled?: boolean;
6
+ /**
7
+ * The syntax of the configuration file. Defaults to JSON. YAML and TOML are available from the
8
+ * `@flowscripter/dynamic-cli-framework/yaml` and `@flowscripter/dynamic-cli-framework/toml` entry points.
9
+ */
10
+ readonly configFormat?: ConfigFormat;
5
11
  readonly envVarsSupportEnabled?: boolean;
6
12
  readonly keyValueServiceEnabled?: boolean;
7
13
  readonly secretServiceEnabled?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"BaseCLIFeatureOptions.d.ts","sourceRoot":"","sources":["../../../src/cli/BaseCLIFeatureOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8CAA8C,CAAC;AAC3F,OAAO,KAAK,EACV,2BAA2B,EAC3B,yBAAyB,EAC1B,MAAM,wCAAwC,CAAC;AAEhD,MAAM,CAAC,OAAO,WAAW,qBAAqB;IAC5C,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IAClD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IAC9C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IACzD;;;OAGG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,2BAA2B,CAAC;IACjE,QAAQ,CAAC,wBAAwB,CAAC,EAAE,yBAAyB,CAAC;IAC9D,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC"}
1
+ {"version":3,"file":"BaseCLIFeatureOptions.d.ts","sourceRoot":"","sources":["../../../src/cli/BaseCLIFeatureOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,iDAAiD,CAAC;AAChF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8CAA8C,CAAC;AAC3F,OAAO,KAAK,EACV,2BAA2B,EAC3B,yBAAyB,EAC1B,MAAM,wCAAwC,CAAC;AAEhD,MAAM,CAAC,OAAO,WAAW,qBAAqB;IAC5C,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IACrC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IAClD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IAC9C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,sBAAsB,CAAC;IACzD;;;OAGG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IACxC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,2BAA2B,CAAC;IACjE,QAAQ,CAAC,wBAAwB,CAAC,EAAE,yBAAyB,CAAC;IAC9D,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CACrC"}
@@ -2,6 +2,7 @@ import type { ServiceInfo, ServiceProvider } from "@flowscripter/dynamic-cli-fra
2
2
  import type { SingleValueType, Values, ValueNode, PopulatedValues, PopulatedValueType } from "@flowscripter/dynamic-cli-framework-api";
3
3
  import type { Context } from "@flowscripter/dynamic-cli-framework-api";
4
4
  import type { GroupCommand } from "@flowscripter/dynamic-cli-framework-api";
5
+ import type ConfigFormat from "./format/ConfigFormat.ts";
5
6
  import type { Command } from "@flowscripter/dynamic-cli-framework-api";
6
7
  import type { CLIConfig } from "@flowscripter/dynamic-cli-framework-api";
7
8
  export type KeyValueServiceScopeType = "command" | "service";
@@ -26,7 +27,7 @@ export type KeyValueServiceScopeType = "command" | "service";
26
27
  *
27
28
  * *Configuration File*
28
29
  *
29
- * A JSON file where the structure matches {@link Values} and the defaults are stored
30
+ * A file (JSON by default, see {@link ConfigFormat}) where the structure matches {@link Values} and the defaults are stored
30
31
  * under a top level `defaults` property. The second level of properties is used to refer to {@link Command.name}
31
32
  * (or `<group name>:<member name>` for a member of a {@link GroupCommand}) and the contained values are treated as
32
33
  * command {@link Values}. As an example:
@@ -57,7 +58,12 @@ export type KeyValueServiceScopeType = "command" | "service";
57
58
  * }
58
59
  * ```
59
60
  *
60
- * The default location of the configuration file is `$HOME/.<application_name>.json`. If `$HOME` is not defined no
61
+ * The syntax of the file is set by the `configFormat` constructor argument: JSON (the default), or YAML or TOML
62
+ * from the `yaml` and `toml` entry points of this package. The format is never inferred from the file name or
63
+ * extension and existing files are not migrated between formats. For YAML and TOML, comments and layout in the
64
+ * existing file are preserved when it is written back.
65
+ *
66
+ * The default location of the configuration file is `$HOME/.<application_name>.<format extension>`. If `$HOME` is not defined no
61
67
  * default configuration will be used. The location of the configuration file can be modified via the
62
68
  * {@link ConfigCommand}.
63
69
  *
@@ -113,6 +119,7 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
113
119
  readonly envVarsEnabled: boolean;
114
120
  readonly configEnabled: boolean;
115
121
  readonly secretServiceEnabled: boolean;
122
+ readonly configFormat: ConfigFormat;
116
123
  configLocation: string | undefined;
117
124
  defaultsData: Map<string, Values | SingleValueType>;
118
125
  /**
@@ -123,8 +130,9 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
123
130
  * @param configEnabled optionally enable configuration file support for default argument values.
124
131
  * @param secretServiceEnabled optionally enable OS-native secret storage via Bun.secrets for resolving
125
132
  * secrets embedded in default argument values: `configEnabled` must be true in this case
133
+ * @param configFormat optionally set the syntax of the configuration file, defaults to JSON.
126
134
  */
127
- constructor(servicePriority: number, envVarsEnabled?: boolean, configEnabled?: boolean, secretServiceEnabled?: boolean);
135
+ constructor(servicePriority: number, envVarsEnabled?: boolean, configEnabled?: boolean, secretServiceEnabled?: boolean, configFormat?: ConfigFormat);
128
136
  getServiceInfo(cliConfig: CLIConfig): Promise<ServiceInfo>;
129
137
  setConfigLocation(configLocation: string): void;
130
138
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ConfigurationServiceProvider.d.ts","sourceRoot":"","sources":["../../../../src/service/configuration/ConfigurationServiceProvider.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAE5F,OAAO,KAAK,EACV,eAAe,EACf,MAAM,EACN,SAAS,EACT,eAAe,EACf,kBAAkB,EACnB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAU5E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAOvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQzE,MAAM,MAAM,wBAAwB,GAAG,SAAS,GAAG,SAAS,CAAC;AAkB7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoGG;AACH,MAAM,CAAC,OAAO,OAAO,4BAA6B,YAAW,eAAe;;IAC1E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAA4B;IACtD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAEjC,SAAgB,cAAc,EAAE,OAAO,CAAC;IACxC,SAAgB,aAAa,EAAE,OAAO,CAAC;IACvC,SAAgB,oBAAoB,EAAE,OAAO,CAAC;IAGvC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAKnC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAAC,CAAa;IAqBvE;;;;;;;;OAQG;IACH,YACE,eAAe,EAAE,MAAM,EACvB,cAAc,UAAQ,EACtB,aAAa,UAAQ,EACrB,oBAAoB,UAAQ,EAW7B;IAEM,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAiBhE;IAEM,iBAAiB,CAAC,cAAc,EAAE,MAAM,QAE9C;IAED;;;;;;;;;OASG;IACU,wBAAwB,CACnC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,GAAG,kBAAkB,GAAG,SAAS,CAAC,CAsD3D;IAED;;;;;;OAMG;IACI,eAAe,CACpB,SAAS,EAAE,wBAAwB,EACnC,QAAQ,EAAE,MAAM,GACf,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAOxB;IAED;;;;;;OAMG;IACU,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQzD;IAEY,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CxD;IA4DM,eAAe,IAAI,MAAM,CAgC/B;CACF"}
1
+ {"version":3,"file":"ConfigurationServiceProvider.d.ts","sourceRoot":"","sources":["../../../../src/service/configuration/ConfigurationServiceProvider.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAE5F,OAAO,KAAK,EACV,eAAe,EACf,MAAM,EACN,SAAS,EACT,eAAe,EACf,kBAAkB,EACnB,MAAM,yCAAyC,CAAC;AAEjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAS5E,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAC;AAIzD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAC;AAOvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQzE,MAAM,MAAM,wBAAwB,GAAG,SAAS,GAAG,SAAS,CAAC;AAkB7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyGG;AACH,MAAM,CAAC,OAAO,OAAO,4BAA6B,YAAW,eAAe;;IAC1E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAA4B;IACtD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IAEjC,SAAgB,cAAc,EAAE,OAAO,CAAC;IACxC,SAAgB,aAAa,EAAE,OAAO,CAAC;IACvC,SAAgB,oBAAoB,EAAE,OAAO,CAAC;IAC9C,SAAgB,YAAY,EAAE,YAAY,CAAC;IAGpC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAQnC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAAC,CAAa;IAqBvE;;;;;;;;;OASG;IACH,YACE,eAAe,EAAE,MAAM,EACvB,cAAc,UAAQ,EACtB,aAAa,UAAQ,EACrB,oBAAoB,UAAQ,EAC5B,YAAY,GAAE,YAAyB,EAYxC;IAEM,cAAc,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAiBhE;IAEM,iBAAiB,CAAC,cAAc,EAAE,MAAM,QAE9C;IAED;;;;;;;;;OASG;IACU,wBAAwB,CACnC,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,YAAY,GAC1B,OAAO,CAAC,eAAe,GAAG,kBAAkB,GAAG,SAAS,CAAC,CAsD3D;IAED;;;;;;OAMG;IACI,eAAe,CACpB,SAAS,EAAE,wBAAwB,EACnC,QAAQ,EAAE,MAAM,GACf,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAOxB;IAED;;;;;;OAMG;IACU,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQzD;IAEY,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CxD;IAgEM,eAAe,IAAI,MAAM,CAE/B;CAmCF"}
@@ -8,6 +8,7 @@ import ConfigDumpSubCommand from "./command/ConfigDumpSubCommand.js";
8
8
  import ConfigGroupCommand from "./command/ConfigGroupCommand.js";
9
9
  import { CONFIGURATION_SERVICE_ID, SECRET_SENTINEL_PREFIX, } from "@flowscripter/dynamic-cli-framework-api";
10
10
  import DefaultSecretService from "./DefaultSecretService.js";
11
+ import jsonFormat from "./format/JsonConfigFormat.js";
11
12
  import resolveSecrets from "./resolveSecrets.js";
12
13
  import argumentValueMerge from "../../runtime/values/argumentValueMerge.js";
13
14
  import { isGlobalCommand, isGlobalModifierCommand, isSubCommand, } from "../../runtime/command/CommandTypeGuards.js";
@@ -46,7 +47,7 @@ class ConfigurationServiceImpl {
46
47
  *
47
48
  * *Configuration File*
48
49
  *
49
- * A JSON file where the structure matches {@link Values} and the defaults are stored
50
+ * A file (JSON by default, see {@link ConfigFormat}) where the structure matches {@link Values} and the defaults are stored
50
51
  * under a top level `defaults` property. The second level of properties is used to refer to {@link Command.name}
51
52
  * (or `<group name>:<member name>` for a member of a {@link GroupCommand}) and the contained values are treated as
52
53
  * command {@link Values}. As an example:
@@ -77,7 +78,12 @@ class ConfigurationServiceImpl {
77
78
  * }
78
79
  * ```
79
80
  *
80
- * The default location of the configuration file is `$HOME/.<application_name>.json`. If `$HOME` is not defined no
81
+ * The syntax of the file is set by the `configFormat` constructor argument: JSON (the default), or YAML or TOML
82
+ * from the `yaml` and `toml` entry points of this package. The format is never inferred from the file name or
83
+ * extension and existing files are not migrated between formats. For YAML and TOML, comments and layout in the
84
+ * existing file are preserved when it is written back.
85
+ *
86
+ * The default location of the configuration file is `$HOME/.<application_name>.<format extension>`. If `$HOME` is not defined no
81
87
  * default configuration will be used. The location of the configuration file can be modified via the
82
88
  * {@link ConfigCommand}.
83
89
  *
@@ -132,8 +138,11 @@ export default class ConfigurationServiceProvider {
132
138
  envVarsEnabled;
133
139
  configEnabled;
134
140
  secretServiceEnabled;
141
+ configFormat;
135
142
  // the location of the currently managed configuration data
136
143
  configLocation;
144
+ // the format specific handle for the text last read or written, used to preserve comments and layout on write
145
+ #configHandle;
137
146
  // the configuration data to be used by the CLI runner implementation when setting command defaults.
138
147
  // SingleValueType is for GlobalCommandArgument values, Values is for
139
148
  // SubCommandArgument values.
@@ -162,8 +171,9 @@ export default class ConfigurationServiceProvider {
162
171
  * @param configEnabled optionally enable configuration file support for default argument values.
163
172
  * @param secretServiceEnabled optionally enable OS-native secret storage via Bun.secrets for resolving
164
173
  * secrets embedded in default argument values: `configEnabled` must be true in this case
174
+ * @param configFormat optionally set the syntax of the configuration file, defaults to JSON.
165
175
  */
166
- constructor(servicePriority, envVarsEnabled = false, configEnabled = false, secretServiceEnabled = false) {
176
+ constructor(servicePriority, envVarsEnabled = false, configEnabled = false, secretServiceEnabled = false, configFormat = jsonFormat) {
167
177
  if (!configEnabled && secretServiceEnabled) {
168
178
  throw new Error("configEnabled must be true if secretServiceEnabled is true");
169
179
  }
@@ -171,6 +181,7 @@ export default class ConfigurationServiceProvider {
171
181
  this.envVarsEnabled = envVarsEnabled;
172
182
  this.configEnabled = configEnabled;
173
183
  this.secretServiceEnabled = secretServiceEnabled;
184
+ this.configFormat = configFormat;
174
185
  this.#configurationService = new ConfigurationServiceImpl(this);
175
186
  }
176
187
  getServiceInfo(cliConfig) {
@@ -284,10 +295,10 @@ export default class ConfigurationServiceProvider {
284
295
  let isDefault = false;
285
296
  if (this.configLocation === undefined) {
286
297
  isDefault = true;
287
- // default to `$HOME/.<application_name>.json`
298
+ // default to `$HOME/.<application_name>.<format extension>`
288
299
  const home = process.env["HOME"];
289
300
  if (home) {
290
- this.configLocation = path.join(home, `.${context.cliConfig.name.replace(/\W/g, "")}.json`);
301
+ this.configLocation = path.join(home, `.${context.cliConfig.name.replace(/\W/g, "")}.${this.configFormat.fileExtension}`);
291
302
  }
292
303
  }
293
304
  if (this.configLocation === undefined) {
@@ -316,10 +327,8 @@ export default class ConfigurationServiceProvider {
316
327
  try {
317
328
  logger.debug("Reading config from: %s", location);
318
329
  const data = await fs.readFile(location);
319
- const config = JSON.parse(data.toString());
320
- if (config === undefined) {
321
- return;
322
- }
330
+ const { data: config, handle } = this.configFormat.parse(data.toString());
331
+ this.#configHandle = handle;
323
332
  this.defaultsData.clear();
324
333
  this.#commandKeyValueData.clear();
325
334
  this.#serviceKeyValueData.clear();
@@ -355,13 +364,21 @@ export default class ConfigurationServiceProvider {
355
364
  async #writeConfig(location) {
356
365
  logger.debug("Writing config to: %s", location);
357
366
  try {
358
- await fs.writeFile(location, this.getConfigString());
367
+ const config = this.#getConfigData();
368
+ const text = this.#configHandle === undefined
369
+ ? this.configFormat.serialize(config)
370
+ : this.configFormat.apply(this.#configHandle, config);
371
+ await fs.writeFile(location, text);
372
+ this.#configHandle = this.configFormat.parse(text).handle;
359
373
  }
360
374
  catch (err) {
361
375
  throw new Error(`Failed to write config at location: '${this.configLocation}': ${err}`);
362
376
  }
363
377
  }
364
378
  getConfigString() {
379
+ return this.configFormat.serialize(this.#getConfigData());
380
+ }
381
+ #getConfigData() {
365
382
  const config = {};
366
383
  if (this.defaultsData.size > 0) {
367
384
  config.defaults = Object.fromEntries(this.defaultsData);
@@ -385,6 +402,6 @@ export default class ConfigurationServiceProvider {
385
402
  }
386
403
  }
387
404
  }
388
- return JSON.stringify(config, null, 2);
405
+ return config;
389
406
  }
390
407
  }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The top level structure of a configuration file: `defaults` and `key-values` objects.
3
+ */
4
+ export type ConfigData = Record<string, any>;
5
+ /**
6
+ * Defines the on-disk syntax of the CLI configuration file.
7
+ *
8
+ * The built-in implementation is JSON (the default). YAML and TOML implementations are available
9
+ * from the `@flowscripter/dynamic-cli-framework/yaml` and `@flowscripter/dynamic-cli-framework/toml`
10
+ * entry points. Third party formats can be supplied by implementing this interface.
11
+ */
12
+ export default interface ConfigFormat {
13
+ /**
14
+ * The extension (without the leading dot) used for the default configuration file name,
15
+ * e.g. `json`.
16
+ */
17
+ readonly fileExtension: string;
18
+ /**
19
+ * Parse configuration file text.
20
+ *
21
+ * @returns the parsed `data` and an opaque `handle` retaining whatever the format needs to write
22
+ * changes back while preserving comments and layout (`undefined` if the format has nothing to retain).
23
+ * @throws if the text is not valid for this format.
24
+ */
25
+ parse(text: string): {
26
+ data: ConfigData;
27
+ handle: unknown;
28
+ };
29
+ /**
30
+ * Produce updated file text from a `handle` returned by {@link parse}.
31
+ *
32
+ * @param handle the handle returned by {@link parse} for the text being updated.
33
+ * @param changes the complete updated configuration data. The format reconciles the existing text
34
+ * with it, leaving unchanged content (including comments) untouched.
35
+ */
36
+ apply(handle: unknown, changes: ConfigData): string;
37
+ /**
38
+ * Produce new file text from scratch.
39
+ */
40
+ serialize(data: ConfigData): string;
41
+ }
42
+ //# sourceMappingURL=ConfigFormat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigFormat.d.ts","sourceRoot":"","sources":["../../../../../src/service/configuration/format/ConfigFormat.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAE7C;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,WAAW,YAAY;IACnC;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAE/B;;;;;;OAMG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAE3D;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,CAAC;IAEpD;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAAC;CACrC"}
@@ -0,0 +1,7 @@
1
+ import type ConfigFormat from "./ConfigFormat.ts";
2
+ /**
3
+ * The built-in JSON {@link ConfigFormat}. The file is regenerated on write: JSON has no comments to preserve.
4
+ */
5
+ declare const jsonFormat: ConfigFormat;
6
+ export default jsonFormat;
7
+ //# sourceMappingURL=JsonConfigFormat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonConfigFormat.d.ts","sourceRoot":"","sources":["../../../../../src/service/configuration/format/JsonConfigFormat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAOlD;;GAEG;AACH,QAAA,MAAM,UAAU,EAAE,YASjB,CAAC;eAEa,UAAU"}
@@ -0,0 +1,17 @@
1
+ function serialize(data) {
2
+ return JSON.stringify(data, null, 2);
3
+ }
4
+ /**
5
+ * The built-in JSON {@link ConfigFormat}. The file is regenerated on write: JSON has no comments to preserve.
6
+ */
7
+ const jsonFormat = {
8
+ fileExtension: "json",
9
+ parse(text) {
10
+ return { data: JSON.parse(text), handle: undefined };
11
+ },
12
+ apply(_handle, changes) {
13
+ return serialize(changes);
14
+ },
15
+ serialize,
16
+ };
17
+ export default jsonFormat;
@@ -0,0 +1,10 @@
1
+ import type ConfigFormat from "./ConfigFormat.ts";
2
+ /**
3
+ * A TOML {@link ConfigFormat} which preserves comments, whitespace and layout when writing changes back.
4
+ * Dates and times are not supported as configuration values.
5
+ *
6
+ * Requires the optional `@decimalturn/toml-patch` peer dependency.
7
+ */
8
+ declare const tomlFormat: ConfigFormat;
9
+ export default tomlFormat;
10
+ //# sourceMappingURL=TomlConfigFormat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TomlConfigFormat.d.ts","sourceRoot":"","sources":["../../../../../src/service/configuration/format/TomlConfigFormat.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAoElD;;;;;GAKG;AACH,QAAA,MAAM,UAAU,EAAE,YAajB,CAAC;eAEa,UAAU"}
@@ -0,0 +1,78 @@
1
+ import { isDeepStrictEqual } from "node:util";
2
+ import { parse, patch, stringify } from "@decimalturn/toml-patch";
3
+ // new tables nested deeper than this (e.g. `defaults.<command>.<option>`) are left to patch() to
4
+ // lay out as inline tables
5
+ const MAX_TABLE_HEADER_DEPTH = 3;
6
+ function isPlainObject(value) {
7
+ return typeof value === "object" && value !== null && !Array.isArray(value);
8
+ }
9
+ function formatKey(key) {
10
+ return /^[A-Za-z0-9_-]+$/.test(key) ? key : JSON.stringify(key);
11
+ }
12
+ function collectNewTables(existing, updated, path, newTables) {
13
+ for (const [key, value] of Object.entries(updated)) {
14
+ if (!isPlainObject(value) || path.length + 1 > MAX_TABLE_HEADER_DEPTH) {
15
+ continue;
16
+ }
17
+ const childPath = [...path, key];
18
+ const existingChild = isPlainObject(existing) ? existing[key] : undefined;
19
+ if (existingChild === undefined) {
20
+ newTables.push(childPath);
21
+ }
22
+ collectNewTables(existingChild, value, childPath, newTables);
23
+ }
24
+ }
25
+ // parse() results do not share prototypes with plain objects
26
+ function plain(value) {
27
+ return JSON.parse(JSON.stringify(value));
28
+ }
29
+ /**
30
+ * Append an empty `[table]` header for every new table, so that patch() fills it in at the end
31
+ * of the file rather than hoisting it to the top as a dotted key. Returns the original text if the
32
+ * result is not equivalent to it plus the empty tables (e.g. the parent is an inline table which
33
+ * cannot be extended).
34
+ */
35
+ function addNewTableHeaders(text, existing, changes) {
36
+ const newTables = [];
37
+ collectNewTables(existing, changes, [], newTables);
38
+ if (newTables.length === 0) {
39
+ return text;
40
+ }
41
+ const expected = structuredClone(existing);
42
+ for (const tablePath of newTables) {
43
+ let node = expected;
44
+ for (const key of tablePath.slice(0, -1)) {
45
+ node = (node[key] ??= {});
46
+ }
47
+ node[tablePath[tablePath.length - 1]] ??= {};
48
+ }
49
+ const headers = newTables.map((tablePath) => `[${tablePath.map(formatKey).join(".")}]`);
50
+ const withHeaders = `${text.trimEnd()}\n\n${headers.join("\n\n")}\n`;
51
+ try {
52
+ return isDeepStrictEqual(plain(parse(withHeaders)), plain(expected)) ? withHeaders : text;
53
+ }
54
+ catch {
55
+ return text;
56
+ }
57
+ }
58
+ /**
59
+ * A TOML {@link ConfigFormat} which preserves comments, whitespace and layout when writing changes back.
60
+ * Dates and times are not supported as configuration values.
61
+ *
62
+ * Requires the optional `@decimalturn/toml-patch` peer dependency.
63
+ */
64
+ const tomlFormat = {
65
+ fileExtension: "toml",
66
+ parse(text) {
67
+ return { data: parse(text), handle: text };
68
+ },
69
+ apply(handle, changes) {
70
+ const text = handle;
71
+ const existing = parse(text);
72
+ return patch(addNewTableHeaders(text, existing, changes), changes);
73
+ },
74
+ serialize(data) {
75
+ return stringify(data);
76
+ },
77
+ };
78
+ export default tomlFormat;
@@ -0,0 +1,9 @@
1
+ import type ConfigFormat from "./ConfigFormat.ts";
2
+ /**
3
+ * A YAML {@link ConfigFormat} which preserves comments, blank lines and key order when writing changes back.
4
+ *
5
+ * Requires the optional `yaml` peer dependency.
6
+ */
7
+ declare const yamlFormat: ConfigFormat;
8
+ export default yamlFormat;
9
+ //# sourceMappingURL=YamlConfigFormat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"YamlConfigFormat.d.ts","sourceRoot":"","sources":["../../../../../src/service/configuration/format/YamlConfigFormat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAqClD;;;;GAIG;AACH,QAAA,MAAM,UAAU,EAAE,YA0BjB,CAAC;eAEa,UAAU"}
@@ -0,0 +1,63 @@
1
+ import { Document, isMap, isSeq, parseDocument, stringify } from "yaml";
2
+ function isPlainObject(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ function reconcile(doc, path, existing, updated) {
6
+ if (isPlainObject(existing) && isPlainObject(updated)) {
7
+ for (const key of Object.keys(existing)) {
8
+ if (!(key in updated)) {
9
+ doc.deleteIn([...path, key]);
10
+ }
11
+ }
12
+ for (const key of Object.keys(updated)) {
13
+ if (key in existing) {
14
+ reconcile(doc, [...path, key], existing[key], updated[key]);
15
+ }
16
+ else {
17
+ doc.setIn([...path, key], updated[key]);
18
+ }
19
+ }
20
+ }
21
+ else if (Array.isArray(existing) &&
22
+ Array.isArray(updated) &&
23
+ existing.length === updated.length) {
24
+ updated.forEach((value, index) => reconcile(doc, [...path, index], existing[index], value));
25
+ }
26
+ else if (JSON.stringify(existing) !== JSON.stringify(updated)) {
27
+ doc.setIn(path, updated);
28
+ }
29
+ }
30
+ /**
31
+ * A YAML {@link ConfigFormat} which preserves comments, blank lines and key order when writing changes back.
32
+ *
33
+ * Requires the optional `yaml` peer dependency.
34
+ */
35
+ const yamlFormat = {
36
+ fileExtension: "yaml",
37
+ parse(text) {
38
+ const doc = parseDocument(text);
39
+ if (doc.errors.length > 0) {
40
+ throw new Error(doc.errors.map((error) => error.message).join("; "));
41
+ }
42
+ const data = doc.toJS() ?? {};
43
+ if (!isPlainObject(data)) {
44
+ throw new Error("top level YAML value must be a mapping");
45
+ }
46
+ return { data, handle: doc };
47
+ },
48
+ apply(handle, changes) {
49
+ const doc = handle;
50
+ const existing = doc.toJS() ?? {};
51
+ if (!isMap(doc.contents) && !isSeq(doc.contents)) {
52
+ doc.contents = doc.createNode(changes);
53
+ }
54
+ else {
55
+ reconcile(doc, [], existing, changes);
56
+ }
57
+ return doc.toString();
58
+ },
59
+ serialize(data) {
60
+ return stringify(data);
61
+ },
62
+ };
63
+ export default yamlFormat;
package/dist/toml.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default as tomlFormat } from "./src/service/configuration/format/TomlConfigFormat.ts";
2
+ //# sourceMappingURL=toml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toml.d.ts","sourceRoot":"","sources":["../toml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,wDAAwD,CAAC"}
package/dist/toml.js ADDED
@@ -0,0 +1 @@
1
+ export { default as tomlFormat } from "./src/service/configuration/format/TomlConfigFormat.js";
package/dist/yaml.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { default as yamlFormat } from "./src/service/configuration/format/YamlConfigFormat.ts";
2
+ //# sourceMappingURL=yaml.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yaml.d.ts","sourceRoot":"","sources":["../yaml.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,wDAAwD,CAAC"}
package/dist/yaml.js ADDED
@@ -0,0 +1 @@
1
+ export { default as yamlFormat } from "./src/service/configuration/format/YamlConfigFormat.js";
package/index.ts CHANGED
@@ -68,6 +68,9 @@ export {
68
68
  default as ConfigurationServiceProvider,
69
69
  type KeyValueServiceScopeType,
70
70
  } from "./src/service/configuration/ConfigurationServiceProvider.ts";
71
+ export type { default as ConfigFormat } from "./src/service/configuration/format/ConfigFormat.ts";
72
+ export type { ConfigData } from "./src/service/configuration/format/ConfigFormat.ts";
73
+ export { default as jsonFormat } from "./src/service/configuration/format/JsonConfigFormat.ts";
71
74
  export { default as KeyValueServiceProvider } from "./src/service/configuration/KeyValueServiceProvider.ts";
72
75
 
73
76
  export { PRINTER_SERVICE_ID } from "@flowscripter/dynamic-cli-framework-api";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowscripter/dynamic-cli-framework",
3
- "version": "12.0.1",
3
+ "version": "12.1.0",
4
4
  "description": "A framework for developing CLI applications which supports dynamic discovery and installation of new commands",
5
5
  "keywords": [
6
6
  "bun",
@@ -22,6 +22,8 @@
22
22
  "src",
23
23
  "index.ts",
24
24
  "cli-plugin.ts",
25
+ "yaml.ts",
26
+ "toml.ts",
25
27
  "README.md",
26
28
  "LICENSE"
27
29
  ],
@@ -40,6 +42,16 @@
40
42
  "bun": "./cli-plugin.ts",
41
43
  "types": "./dist/cli-plugin.d.ts",
42
44
  "default": "./dist/cli-plugin.js"
45
+ },
46
+ "./yaml": {
47
+ "bun": "./yaml.ts",
48
+ "types": "./dist/yaml.d.ts",
49
+ "default": "./dist/yaml.js"
50
+ },
51
+ "./toml": {
52
+ "bun": "./toml.ts",
53
+ "types": "./dist/toml.d.ts",
54
+ "default": "./dist/toml.js"
43
55
  }
44
56
  },
45
57
  "publishConfig": {
@@ -61,14 +73,26 @@
61
73
  "supports-terminal-graphics": "^0.1.0"
62
74
  },
63
75
  "devDependencies": {
76
+ "@decimalturn/toml-patch": "^3.3.1",
64
77
  "@types/bun": "^1.4.3",
65
78
  "@types/node": "^26.6.5",
66
79
  "@types/semver": "^7.8.0",
67
80
  "oxfmt": "0.74.0",
68
- "oxlint": "1.89.0"
81
+ "oxlint": "1.89.0",
82
+ "yaml": "^2.9.1"
69
83
  },
70
84
  "peerDependencies": {
71
- "typescript": "^7.0.2"
85
+ "@decimalturn/toml-patch": "^3.3.1",
86
+ "typescript": "^7.0.2",
87
+ "yaml": "^2.9.1"
88
+ },
89
+ "peerDependenciesMeta": {
90
+ "yaml": {
91
+ "optional": true
92
+ },
93
+ "@decimalturn/toml-patch": {
94
+ "optional": true
95
+ }
72
96
  },
73
97
  "typedocOptions": {
74
98
  "readme": "none",
@@ -31,6 +31,7 @@ import ShutdownServiceProvider from "../service/shutdown/ShutdownServiceProvider
31
31
  import StartupServiceProvider from "../service/startup/StartupServiceProvider.ts";
32
32
  import type { StartupTask } from "@flowscripter/dynamic-cli-framework-api";
33
33
  import { shutdownState } from "../service/shutdown/ShutdownState.ts";
34
+ import jsonFormat from "../service/configuration/format/JsonConfigFormat.ts";
34
35
  import ConfigurationServiceProvider from "../service/configuration/ConfigurationServiceProvider.ts";
35
36
  import KeyValueServiceProvider from "../service/configuration/KeyValueServiceProvider.ts";
36
37
  import PrinterServiceProvider from "../service/printer/PrinterServiceProvider.ts";
@@ -162,6 +163,7 @@ export default class BaseCLI implements CLI {
162
163
  }
163
164
  this.#cliConfig = cliConfig;
164
165
  this.#options = {
166
+ configFormat: jsonFormat,
165
167
  configFileSupportEnabled: false,
166
168
  envVarsSupportEnabled: false,
167
169
  keyValueServiceEnabled: false,
@@ -392,6 +394,7 @@ export default class BaseCLI implements CLI {
392
394
  this.#options.envVarsSupportEnabled,
393
395
  this.#options.configFileSupportEnabled,
394
396
  this.#options.secretServiceEnabled,
397
+ this.#options.configFormat,
395
398
  );
396
399
  this.addServiceProvider(configurationServiceProvider);
397
400
  const keyValueServiceProvider = new KeyValueServiceProvider(
@@ -1,3 +1,4 @@
1
+ import type ConfigFormat from "../service/configuration/format/ConfigFormat.ts";
1
2
  import type { UpgradeLocationsConfig } from "../service/upgrade/UpgradeLocationsConfig.ts";
2
3
  import type {
3
4
  NpmjsPluginRepositoryConfig,
@@ -6,6 +7,11 @@ import type {
6
7
 
7
8
  export default interface BaseCLIFeatureOptions {
8
9
  readonly configFileSupportEnabled?: boolean;
10
+ /**
11
+ * The syntax of the configuration file. Defaults to JSON. YAML and TOML are available from the
12
+ * `@flowscripter/dynamic-cli-framework/yaml` and `@flowscripter/dynamic-cli-framework/toml` entry points.
13
+ */
14
+ readonly configFormat?: ConfigFormat;
9
15
  readonly envVarsSupportEnabled?: boolean;
10
16
  readonly keyValueServiceEnabled?: boolean;
11
17
  readonly secretServiceEnabled?: boolean;
@@ -22,6 +22,9 @@ import {
22
22
  } from "@flowscripter/dynamic-cli-framework-api";
23
23
  import type { ConfigurationService } from "@flowscripter/dynamic-cli-framework-api";
24
24
  import DefaultSecretService from "./DefaultSecretService.ts";
25
+ import type ConfigFormat from "./format/ConfigFormat.ts";
26
+ import type { ConfigData } from "./format/ConfigFormat.ts";
27
+ import jsonFormat from "./format/JsonConfigFormat.ts";
25
28
  import resolveSecrets from "./resolveSecrets.ts";
26
29
  import type { Command } from "@flowscripter/dynamic-cli-framework-api";
27
30
  import argumentValueMerge from "../../runtime/values/argumentValueMerge.ts";
@@ -77,7 +80,7 @@ class ConfigurationServiceImpl implements ConfigurationService {
77
80
  *
78
81
  * *Configuration File*
79
82
  *
80
- * A JSON file where the structure matches {@link Values} and the defaults are stored
83
+ * A file (JSON by default, see {@link ConfigFormat}) where the structure matches {@link Values} and the defaults are stored
81
84
  * under a top level `defaults` property. The second level of properties is used to refer to {@link Command.name}
82
85
  * (or `<group name>:<member name>` for a member of a {@link GroupCommand}) and the contained values are treated as
83
86
  * command {@link Values}. As an example:
@@ -108,7 +111,12 @@ class ConfigurationServiceImpl implements ConfigurationService {
108
111
  * }
109
112
  * ```
110
113
  *
111
- * The default location of the configuration file is `$HOME/.<application_name>.json`. If `$HOME` is not defined no
114
+ * The syntax of the file is set by the `configFormat` constructor argument: JSON (the default), or YAML or TOML
115
+ * from the `yaml` and `toml` entry points of this package. The format is never inferred from the file name or
116
+ * extension and existing files are not migrated between formats. For YAML and TOML, comments and layout in the
117
+ * existing file are preserved when it is written back.
118
+ *
119
+ * The default location of the configuration file is `$HOME/.<application_name>.<format extension>`. If `$HOME` is not defined no
112
120
  * default configuration will be used. The location of the configuration file can be modified via the
113
121
  * {@link ConfigCommand}.
114
122
  *
@@ -164,10 +172,14 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
164
172
  public readonly envVarsEnabled: boolean;
165
173
  public readonly configEnabled: boolean;
166
174
  public readonly secretServiceEnabled: boolean;
175
+ public readonly configFormat: ConfigFormat;
167
176
 
168
177
  // the location of the currently managed configuration data
169
178
  public configLocation: string | undefined;
170
179
 
180
+ // the format specific handle for the text last read or written, used to preserve comments and layout on write
181
+ #configHandle: unknown;
182
+
171
183
  // the configuration data to be used by the CLI runner implementation when setting command defaults.
172
184
  // SingleValueType is for GlobalCommandArgument values, Values is for
173
185
  // SubCommandArgument values.
@@ -200,12 +212,14 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
200
212
  * @param configEnabled optionally enable configuration file support for default argument values.
201
213
  * @param secretServiceEnabled optionally enable OS-native secret storage via Bun.secrets for resolving
202
214
  * secrets embedded in default argument values: `configEnabled` must be true in this case
215
+ * @param configFormat optionally set the syntax of the configuration file, defaults to JSON.
203
216
  */
204
217
  public constructor(
205
218
  servicePriority: number,
206
219
  envVarsEnabled = false,
207
220
  configEnabled = false,
208
221
  secretServiceEnabled = false,
222
+ configFormat: ConfigFormat = jsonFormat,
209
223
  ) {
210
224
  if (!configEnabled && secretServiceEnabled) {
211
225
  throw new Error("configEnabled must be true if secretServiceEnabled is true");
@@ -214,6 +228,7 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
214
228
  this.envVarsEnabled = envVarsEnabled;
215
229
  this.configEnabled = configEnabled;
216
230
  this.secretServiceEnabled = secretServiceEnabled;
231
+ this.configFormat = configFormat;
217
232
 
218
233
  this.#configurationService = new ConfigurationServiceImpl(this);
219
234
  }
@@ -355,10 +370,13 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
355
370
  let isDefault = false;
356
371
  if (this.configLocation === undefined) {
357
372
  isDefault = true;
358
- // default to `$HOME/.<application_name>.json`
373
+ // default to `$HOME/.<application_name>.<format extension>`
359
374
  const home = process.env["HOME"];
360
375
  if (home) {
361
- this.configLocation = path.join(home, `.${context.cliConfig.name.replace(/\W/g, "")}.json`);
376
+ this.configLocation = path.join(
377
+ home,
378
+ `.${context.cliConfig.name.replace(/\W/g, "")}.${this.configFormat.fileExtension}`,
379
+ );
362
380
  }
363
381
  }
364
382
  if (this.configLocation === undefined) {
@@ -396,11 +414,9 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
396
414
  logger.debug("Reading config from: %s", location);
397
415
 
398
416
  const data = await fs.readFile(location);
399
- const config = JSON.parse(data.toString());
417
+ const { data: config, handle } = this.configFormat.parse(data.toString());
418
+ this.#configHandle = handle;
400
419
 
401
- if (config === undefined) {
402
- return;
403
- }
404
420
  this.defaultsData.clear();
405
421
  this.#commandKeyValueData.clear();
406
422
  this.#serviceKeyValueData.clear();
@@ -443,13 +459,23 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
443
459
  logger.debug("Writing config to: %s", location);
444
460
 
445
461
  try {
446
- await fs.writeFile(location, this.getConfigString());
462
+ const config = this.#getConfigData();
463
+ const text =
464
+ this.#configHandle === undefined
465
+ ? this.configFormat.serialize(config)
466
+ : this.configFormat.apply(this.#configHandle, config);
467
+ await fs.writeFile(location, text);
468
+ this.#configHandle = this.configFormat.parse(text).handle;
447
469
  } catch (err) {
448
470
  throw new Error(`Failed to write config at location: '${this.configLocation}': ${err}`);
449
471
  }
450
472
  }
451
473
 
452
474
  public getConfigString(): string {
475
+ return this.configFormat.serialize(this.#getConfigData());
476
+ }
477
+
478
+ #getConfigData(): ConfigData {
453
479
  const config: {
454
480
  defaults?: Record<string, Values | SingleValueType>;
455
481
  "key-values"?: {
@@ -480,6 +506,6 @@ export default class ConfigurationServiceProvider implements ServiceProvider {
480
506
  }
481
507
  }
482
508
  }
483
- return JSON.stringify(config, null, 2);
509
+ return config;
484
510
  }
485
511
  }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The top level structure of a configuration file: `defaults` and `key-values` objects.
3
+ */
4
+ export type ConfigData = Record<string, any>;
5
+
6
+ /**
7
+ * Defines the on-disk syntax of the CLI configuration file.
8
+ *
9
+ * The built-in implementation is JSON (the default). YAML and TOML implementations are available
10
+ * from the `@flowscripter/dynamic-cli-framework/yaml` and `@flowscripter/dynamic-cli-framework/toml`
11
+ * entry points. Third party formats can be supplied by implementing this interface.
12
+ */
13
+ export default interface ConfigFormat {
14
+ /**
15
+ * The extension (without the leading dot) used for the default configuration file name,
16
+ * e.g. `json`.
17
+ */
18
+ readonly fileExtension: string;
19
+
20
+ /**
21
+ * Parse configuration file text.
22
+ *
23
+ * @returns the parsed `data` and an opaque `handle` retaining whatever the format needs to write
24
+ * changes back while preserving comments and layout (`undefined` if the format has nothing to retain).
25
+ * @throws if the text is not valid for this format.
26
+ */
27
+ parse(text: string): { data: ConfigData; handle: unknown };
28
+
29
+ /**
30
+ * Produce updated file text from a `handle` returned by {@link parse}.
31
+ *
32
+ * @param handle the handle returned by {@link parse} for the text being updated.
33
+ * @param changes the complete updated configuration data. The format reconciles the existing text
34
+ * with it, leaving unchanged content (including comments) untouched.
35
+ */
36
+ apply(handle: unknown, changes: ConfigData): string;
37
+
38
+ /**
39
+ * Produce new file text from scratch.
40
+ */
41
+ serialize(data: ConfigData): string;
42
+ }
@@ -0,0 +1,22 @@
1
+ import type ConfigFormat from "./ConfigFormat.ts";
2
+ import type { ConfigData } from "./ConfigFormat.ts";
3
+
4
+ function serialize(data: ConfigData): string {
5
+ return JSON.stringify(data, null, 2);
6
+ }
7
+
8
+ /**
9
+ * The built-in JSON {@link ConfigFormat}. The file is regenerated on write: JSON has no comments to preserve.
10
+ */
11
+ const jsonFormat: ConfigFormat = {
12
+ fileExtension: "json",
13
+ parse(text: string) {
14
+ return { data: JSON.parse(text) as ConfigData, handle: undefined };
15
+ },
16
+ apply(_handle: unknown, changes: ConfigData): string {
17
+ return serialize(changes);
18
+ },
19
+ serialize,
20
+ };
21
+
22
+ export default jsonFormat;
@@ -0,0 +1,92 @@
1
+ import { isDeepStrictEqual } from "node:util";
2
+ import { parse, patch, stringify } from "@decimalturn/toml-patch";
3
+ import type ConfigFormat from "./ConfigFormat.ts";
4
+ import type { ConfigData } from "./ConfigFormat.ts";
5
+
6
+ // new tables nested deeper than this (e.g. `defaults.<command>.<option>`) are left to patch() to
7
+ // lay out as inline tables
8
+ const MAX_TABLE_HEADER_DEPTH = 3;
9
+
10
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
11
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12
+ }
13
+
14
+ function formatKey(key: string): string {
15
+ return /^[A-Za-z0-9_-]+$/.test(key) ? key : JSON.stringify(key);
16
+ }
17
+
18
+ function collectNewTables(
19
+ existing: unknown,
20
+ updated: Record<string, unknown>,
21
+ path: Array<string>,
22
+ newTables: Array<Array<string>>,
23
+ ): void {
24
+ for (const [key, value] of Object.entries(updated)) {
25
+ if (!isPlainObject(value) || path.length + 1 > MAX_TABLE_HEADER_DEPTH) {
26
+ continue;
27
+ }
28
+ const childPath = [...path, key];
29
+ const existingChild = isPlainObject(existing) ? existing[key] : undefined;
30
+ if (existingChild === undefined) {
31
+ newTables.push(childPath);
32
+ }
33
+ collectNewTables(existingChild, value, childPath, newTables);
34
+ }
35
+ }
36
+
37
+ // parse() results do not share prototypes with plain objects
38
+ function plain(value: unknown): unknown {
39
+ return JSON.parse(JSON.stringify(value));
40
+ }
41
+
42
+ /**
43
+ * Append an empty `[table]` header for every new table, so that patch() fills it in at the end
44
+ * of the file rather than hoisting it to the top as a dotted key. Returns the original text if the
45
+ * result is not equivalent to it plus the empty tables (e.g. the parent is an inline table which
46
+ * cannot be extended).
47
+ */
48
+ function addNewTableHeaders(text: string, existing: ConfigData, changes: ConfigData): string {
49
+ const newTables: Array<Array<string>> = [];
50
+ collectNewTables(existing, changes, [], newTables);
51
+ if (newTables.length === 0) {
52
+ return text;
53
+ }
54
+ const expected = structuredClone(existing);
55
+ for (const tablePath of newTables) {
56
+ let node = expected;
57
+ for (const key of tablePath.slice(0, -1)) {
58
+ node = (node[key] ??= {}) as ConfigData;
59
+ }
60
+ node[tablePath[tablePath.length - 1]!] ??= {};
61
+ }
62
+ const headers = newTables.map((tablePath) => `[${tablePath.map(formatKey).join(".")}]`);
63
+ const withHeaders = `${text.trimEnd()}\n\n${headers.join("\n\n")}\n`;
64
+ try {
65
+ return isDeepStrictEqual(plain(parse(withHeaders)), plain(expected)) ? withHeaders : text;
66
+ } catch {
67
+ return text;
68
+ }
69
+ }
70
+
71
+ /**
72
+ * A TOML {@link ConfigFormat} which preserves comments, whitespace and layout when writing changes back.
73
+ * Dates and times are not supported as configuration values.
74
+ *
75
+ * Requires the optional `@decimalturn/toml-patch` peer dependency.
76
+ */
77
+ const tomlFormat: ConfigFormat = {
78
+ fileExtension: "toml",
79
+ parse(text: string) {
80
+ return { data: parse(text) as ConfigData, handle: text };
81
+ },
82
+ apply(handle: unknown, changes: ConfigData): string {
83
+ const text = handle as string;
84
+ const existing = parse(text) as ConfigData;
85
+ return patch(addNewTableHeaders(text, existing, changes), changes);
86
+ },
87
+ serialize(data: ConfigData): string {
88
+ return stringify(data);
89
+ },
90
+ };
91
+
92
+ export default tomlFormat;
@@ -0,0 +1,72 @@
1
+ import { Document, isMap, isSeq, parseDocument, stringify } from "yaml";
2
+ import type ConfigFormat from "./ConfigFormat.ts";
3
+ import type { ConfigData } from "./ConfigFormat.ts";
4
+
5
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ }
8
+
9
+ function reconcile(
10
+ doc: Document,
11
+ path: Array<string | number>,
12
+ existing: unknown,
13
+ updated: unknown,
14
+ ): void {
15
+ if (isPlainObject(existing) && isPlainObject(updated)) {
16
+ for (const key of Object.keys(existing)) {
17
+ if (!(key in updated)) {
18
+ doc.deleteIn([...path, key]);
19
+ }
20
+ }
21
+ for (const key of Object.keys(updated)) {
22
+ if (key in existing) {
23
+ reconcile(doc, [...path, key], existing[key], updated[key]);
24
+ } else {
25
+ doc.setIn([...path, key], updated[key]);
26
+ }
27
+ }
28
+ } else if (
29
+ Array.isArray(existing) &&
30
+ Array.isArray(updated) &&
31
+ existing.length === updated.length
32
+ ) {
33
+ updated.forEach((value, index) => reconcile(doc, [...path, index], existing[index], value));
34
+ } else if (JSON.stringify(existing) !== JSON.stringify(updated)) {
35
+ doc.setIn(path, updated);
36
+ }
37
+ }
38
+
39
+ /**
40
+ * A YAML {@link ConfigFormat} which preserves comments, blank lines and key order when writing changes back.
41
+ *
42
+ * Requires the optional `yaml` peer dependency.
43
+ */
44
+ const yamlFormat: ConfigFormat = {
45
+ fileExtension: "yaml",
46
+ parse(text: string) {
47
+ const doc = parseDocument(text);
48
+ if (doc.errors.length > 0) {
49
+ throw new Error(doc.errors.map((error) => error.message).join("; "));
50
+ }
51
+ const data = doc.toJS() ?? {};
52
+ if (!isPlainObject(data)) {
53
+ throw new Error("top level YAML value must be a mapping");
54
+ }
55
+ return { data, handle: doc };
56
+ },
57
+ apply(handle: unknown, changes: ConfigData): string {
58
+ const doc = handle as Document;
59
+ const existing = doc.toJS() ?? {};
60
+ if (!isMap(doc.contents) && !isSeq(doc.contents)) {
61
+ doc.contents = doc.createNode(changes);
62
+ } else {
63
+ reconcile(doc, [], existing, changes);
64
+ }
65
+ return doc.toString();
66
+ },
67
+ serialize(data: ConfigData): string {
68
+ return stringify(data);
69
+ },
70
+ };
71
+
72
+ export default yamlFormat;
package/toml.ts ADDED
@@ -0,0 +1 @@
1
+ export { default as tomlFormat } from "./src/service/configuration/format/TomlConfigFormat.ts";
package/yaml.ts ADDED
@@ -0,0 +1 @@
1
+ export { default as yamlFormat } from "./src/service/configuration/format/YamlConfigFormat.ts";