@flowscripter/dynamic-cli-framework 12.0.1 → 12.2.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 (80) 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/runtime/runner.d.ts.map +1 -1
  9. package/dist/src/runtime/runner.js +4 -1
  10. package/dist/src/service/configuration/ConfigurationServiceProvider.d.ts +33 -15
  11. package/dist/src/service/configuration/ConfigurationServiceProvider.d.ts.map +1 -1
  12. package/dist/src/service/configuration/ConfigurationServiceProvider.js +80 -173
  13. package/dist/src/service/configuration/DefaultConfigurationService.d.ts +78 -0
  14. package/dist/src/service/configuration/DefaultConfigurationService.d.ts.map +1 -0
  15. package/dist/src/service/configuration/DefaultConfigurationService.js +296 -0
  16. package/dist/src/service/configuration/DefaultKeyValueService.d.ts.map +1 -1
  17. package/dist/src/service/configuration/DefaultKeyValueService.js +7 -3
  18. package/dist/src/service/configuration/DefaultSecretService.d.ts +17 -2
  19. package/dist/src/service/configuration/DefaultSecretService.d.ts.map +1 -1
  20. package/dist/src/service/configuration/DefaultSecretService.js +44 -5
  21. package/dist/src/service/configuration/KeyValueServiceProvider.d.ts +3 -1
  22. package/dist/src/service/configuration/KeyValueServiceProvider.d.ts.map +1 -1
  23. package/dist/src/service/configuration/KeyValueServiceProvider.js +6 -3
  24. package/dist/src/service/configuration/command/ConfigDumpSubCommand.d.ts +3 -7
  25. package/dist/src/service/configuration/command/ConfigDumpSubCommand.d.ts.map +1 -1
  26. package/dist/src/service/configuration/command/ConfigDumpSubCommand.js +5 -10
  27. package/dist/src/service/configuration/command/ConfigGetSubCommand.d.ts +16 -0
  28. package/dist/src/service/configuration/command/ConfigGetSubCommand.d.ts.map +1 -0
  29. package/dist/src/service/configuration/command/ConfigGetSubCommand.js +137 -0
  30. package/dist/src/service/configuration/command/ConfigSetSubCommand.d.ts +18 -0
  31. package/dist/src/service/configuration/command/ConfigSetSubCommand.d.ts.map +1 -0
  32. package/dist/src/service/configuration/command/ConfigSetSubCommand.js +289 -0
  33. package/dist/src/service/configuration/command/ConfigUnsetSubCommand.d.ts +15 -0
  34. package/dist/src/service/configuration/command/ConfigUnsetSubCommand.d.ts.map +1 -0
  35. package/dist/src/service/configuration/command/ConfigUnsetSubCommand.js +101 -0
  36. package/dist/src/service/configuration/configTargets.d.ts +91 -0
  37. package/dist/src/service/configuration/configTargets.d.ts.map +1 -0
  38. package/dist/src/service/configuration/configTargets.js +348 -0
  39. package/dist/src/service/configuration/format/ConfigFormat.d.ts +42 -0
  40. package/dist/src/service/configuration/format/ConfigFormat.d.ts.map +1 -0
  41. package/dist/src/service/configuration/format/ConfigFormat.js +0 -0
  42. package/dist/src/service/configuration/format/JsonConfigFormat.d.ts +7 -0
  43. package/dist/src/service/configuration/format/JsonConfigFormat.d.ts.map +1 -0
  44. package/dist/src/service/configuration/format/JsonConfigFormat.js +17 -0
  45. package/dist/src/service/configuration/format/TomlConfigFormat.d.ts +10 -0
  46. package/dist/src/service/configuration/format/TomlConfigFormat.d.ts.map +1 -0
  47. package/dist/src/service/configuration/format/TomlConfigFormat.js +78 -0
  48. package/dist/src/service/configuration/format/YamlConfigFormat.d.ts +9 -0
  49. package/dist/src/service/configuration/format/YamlConfigFormat.d.ts.map +1 -0
  50. package/dist/src/service/configuration/format/YamlConfigFormat.js +63 -0
  51. package/dist/src/service/configuration/resolveSecrets.d.ts.map +1 -1
  52. package/dist/src/service/configuration/resolveSecrets.js +7 -1
  53. package/dist/toml.d.ts +2 -0
  54. package/dist/toml.d.ts.map +1 -0
  55. package/dist/toml.js +1 -0
  56. package/dist/yaml.d.ts +2 -0
  57. package/dist/yaml.d.ts.map +1 -0
  58. package/dist/yaml.js +1 -0
  59. package/index.ts +3 -0
  60. package/package.json +27 -3
  61. package/src/cli/BaseCLI.ts +4 -0
  62. package/src/cli/BaseCLIFeatureOptions.ts +6 -0
  63. package/src/runtime/runner.ts +4 -1
  64. package/src/service/configuration/ConfigurationServiceProvider.ts +108 -214
  65. package/src/service/configuration/DefaultConfigurationService.ts +378 -0
  66. package/src/service/configuration/DefaultKeyValueService.ts +9 -3
  67. package/src/service/configuration/DefaultSecretService.ts +51 -8
  68. package/src/service/configuration/KeyValueServiceProvider.ts +7 -2
  69. package/src/service/configuration/command/ConfigDumpSubCommand.ts +6 -10
  70. package/src/service/configuration/command/ConfigGetSubCommand.ts +198 -0
  71. package/src/service/configuration/command/ConfigSetSubCommand.ts +401 -0
  72. package/src/service/configuration/command/ConfigUnsetSubCommand.ts +126 -0
  73. package/src/service/configuration/configTargets.ts +481 -0
  74. package/src/service/configuration/format/ConfigFormat.ts +42 -0
  75. package/src/service/configuration/format/JsonConfigFormat.ts +22 -0
  76. package/src/service/configuration/format/TomlConfigFormat.ts +92 -0
  77. package/src/service/configuration/format/YamlConfigFormat.ts +72 -0
  78. package/src/service/configuration/resolveSecrets.ts +7 -1
  79. package/toml.ts +1 -0
  80. package/yaml.ts +1 -0
@@ -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;
@@ -27,7 +27,13 @@ export default async function resolveSecrets<T>(
27
27
  }
28
28
  const resolved: Record<string, unknown> = {};
29
29
  for (const [key, val] of Object.entries(value)) {
30
- resolved[key] = await resolveSecrets(val, resolveSecret);
30
+ // defineProperty so a "__proto__" key is an own property rather than replacing the prototype
31
+ Object.defineProperty(resolved, key, {
32
+ value: await resolveSecrets(val, resolveSecret),
33
+ enumerable: true,
34
+ writable: true,
35
+ configurable: true,
36
+ });
31
37
  }
32
38
  return resolved as unknown as T;
33
39
  }
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";