@aspruyt/json-config-sync 3.8.0 → 3.10.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.
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![npm downloads](https://img.shields.io/npm/dw/@aspruyt/json-config-sync.svg)](https://www.npmjs.com/package/@aspruyt/json-config-sync)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
7
 
8
- A CLI tool that syncs JSON, YAML, or text configuration files across multiple GitHub and Azure DevOps repositories by creating pull requests. Output format is automatically detected from the target filename extension (`.json` → JSON, `.yaml`/`.yml` → YAML, other → text).
8
+ A CLI tool that syncs JSON, JSON5, YAML, or text configuration files across multiple GitHub and Azure DevOps repositories by creating pull requests. Output format is automatically detected from the target filename extension (`.json` → JSON, `.json5` → JSON5, `.yaml`/`.yml` → YAML, other → text).
9
9
 
10
10
  ## Table of Contents
11
11
 
@@ -536,7 +536,7 @@ repos:
536
536
  - **String content** (`content: |-`) - Direct text output with environment variable interpolation. Merging always replaces the base.
537
537
  - **Lines array** (`content: ['line1', 'line2']`) - Each line joined with newlines. Supports merge strategies (`append`, `prepend`, `replace`).
538
538
 
539
- **Validation:** JSON/YAML file extensions (`.json`, `.yaml`, `.yml`) require object content. Other extensions require string or string[] content.
539
+ **Validation:** JSON/JSON5/YAML file extensions (`.json`, `.json5`, `.yaml`, `.yml`) require object content. Other extensions require string or string[] content.
540
540
 
541
541
  ### Executable Files
542
542
 
@@ -630,7 +630,7 @@ repos:
630
630
 
631
631
  - File references start with `@` followed by a relative path
632
632
  - Paths are resolved relative to the config file's directory
633
- - JSON/YAML files are parsed as objects, other files as strings
633
+ - JSON/JSON5/YAML files are parsed as objects, other files as strings
634
634
  - Metadata fields (`header`, `schemaUrl`, `createOnly`, `mergeStrategy`) remain in the config
635
635
  - Per-repo overlays still work - they merge onto the resolved file content
636
636
 
@@ -728,7 +728,7 @@ flowchart TB
728
728
 
729
729
  subgraph Processing["For Each Repository"]
730
730
  CLONE[Clone Repo] --> BRANCH[Create/Checkout Branch<br/>--branch or chore/sync-config]
731
- BRANCH --> WRITE[Write All Config Files<br/>JSON or YAML]
731
+ BRANCH --> WRITE[Write All Config Files<br/>JSON, JSON5, or YAML]
732
732
  WRITE --> CHECK{Changes?}
733
733
  CHECK -->|No| SKIP[Skip - No Changes]
734
734
  CHECK -->|Yes| COMMIT[Commit Changes]
@@ -758,7 +758,7 @@ For each repository in the config, the tool:
758
758
  4. Cleans the temporary workspace
759
759
  5. Clones the repository
760
760
  6. Creates/checks out branch (custom `--branch` or default `chore/sync-config`)
761
- 7. Writes all config files (JSON or YAML based on filename extension)
761
+ 7. Writes all config files (JSON, JSON5, or YAML based on filename extension)
762
762
  8. Checks for changes (skips if no changes)
763
763
  9. Commits and pushes changes
764
764
  10. Creates a pull request
@@ -1,4 +1,4 @@
1
- export type OutputFormat = "json" | "yaml";
1
+ export type OutputFormat = "json" | "json5" | "yaml";
2
2
  /**
3
3
  * Options for content conversion.
4
4
  */
@@ -7,6 +7,9 @@ export function detectOutputFormat(fileName) {
7
7
  if (ext === "yaml" || ext === "yml") {
8
8
  return "yaml";
9
9
  }
10
+ if (ext === "json5") {
11
+ return "json5";
12
+ }
10
13
  return "json";
11
14
  }
12
15
  /**
@@ -87,6 +90,11 @@ export function convertContentToString(content, fileName, options) {
87
90
  }
88
91
  return stringify(doc, { indent: 2 });
89
92
  }
93
+ if (format === "json5") {
94
+ // JSON5 format - output standard JSON (which is valid JSON5)
95
+ // Using JSON.stringify for standard JSON output that's compatible everywhere
96
+ return JSON.stringify(content, null, 2) + "\n";
97
+ }
90
98
  // JSON format - comments not supported, ignore header/schemaUrl
91
99
  return JSON.stringify(content, null, 2) + "\n";
92
100
  }
@@ -19,7 +19,7 @@ function isObjectContent(content) {
19
19
  */
20
20
  function isStructuredFileExtension(fileName) {
21
21
  const ext = fileName.toLowerCase().split(".").pop();
22
- return ext === "json" || ext === "yaml" || ext === "yml";
22
+ return ext === "json" || ext === "json5" || ext === "yaml" || ext === "yml";
23
23
  }
24
24
  /**
25
25
  * Validates raw config structure before normalization.
@@ -1,5 +1,6 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { resolve, isAbsolute, normalize, extname } from "node:path";
3
+ import JSON5 from "json5";
3
4
  import { parse as parseYaml } from "yaml";
4
5
  /**
5
6
  * Check if a value is a file reference (string starting with @)
@@ -52,6 +53,15 @@ export function resolveFileReference(reference, configDir) {
52
53
  throw new Error(`Invalid JSON in "${reference}": ${msg}`);
53
54
  }
54
55
  }
56
+ if (ext === ".json5") {
57
+ try {
58
+ return JSON5.parse(content);
59
+ }
60
+ catch (error) {
61
+ const msg = error instanceof Error ? error.message : String(error);
62
+ throw new Error(`Invalid JSON5 in "${reference}": ${msg}`);
63
+ }
64
+ }
55
65
  if (ext === ".yaml" || ext === ".yml") {
56
66
  try {
57
67
  return parseYaml(content);
package/dist/index.js CHANGED
@@ -26,14 +26,14 @@ program
26
26
  .option("-w, --work-dir <path>", "Temporary directory for cloning", "./tmp")
27
27
  .option("-r, --retries <number>", "Number of retries for network operations (0 to disable)", (v) => parseInt(v, 10), 3)
28
28
  .option("-b, --branch <name>", "Override the branch name (default: chore/sync-{filename} or chore/sync-config)")
29
- .option("-m, --merge <mode>", "PR merge mode: manual (default), auto (merge when checks pass), force (bypass requirements)", (value) => {
29
+ .option("-m, --merge <mode>", "PR merge mode: manual, auto (default, merge when checks pass), force (bypass requirements)", (value) => {
30
30
  const valid = ["manual", "auto", "force"];
31
31
  if (!valid.includes(value)) {
32
32
  throw new Error(`Invalid merge mode: ${value}. Valid: ${valid.join(", ")}`);
33
33
  }
34
34
  return value;
35
35
  })
36
- .option("--merge-strategy <strategy>", "Merge strategy: merge (default), squash, rebase", (value) => {
36
+ .option("--merge-strategy <strategy>", "Merge strategy: merge, squash (default), rebase", (value) => {
37
37
  const valid = ["merge", "squash", "rebase"];
38
38
  if (!valid.includes(value)) {
39
39
  throw new Error(`Invalid merge strategy: ${value}. Valid: ${valid.join(", ")}`);
@@ -143,14 +143,14 @@ export class RepositoryProcessor {
143
143
  retries,
144
144
  });
145
145
  // Step 10: Handle merge options if configured
146
- const mergeMode = repoConfig.prOptions?.merge ?? "manual";
146
+ const mergeMode = repoConfig.prOptions?.merge ?? "auto";
147
147
  let mergeResult;
148
148
  if (prResult.success && prResult.url && mergeMode !== "manual") {
149
149
  this.log.info(`Handling merge (mode: ${mergeMode})...`);
150
150
  const mergeConfig = {
151
151
  mode: mergeMode,
152
- strategy: repoConfig.prOptions?.mergeStrategy,
153
- deleteBranch: repoConfig.prOptions?.deleteBranch,
152
+ strategy: repoConfig.prOptions?.mergeStrategy ?? "squash",
153
+ deleteBranch: repoConfig.prOptions?.deleteBranch ?? true,
154
154
  bypassReason: repoConfig.prOptions?.bypassReason,
155
155
  };
156
156
  const result = await mergePR({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aspruyt/json-config-sync",
3
- "version": "3.8.0",
3
+ "version": "3.10.0",
4
4
  "description": "CLI tool to sync JSON or YAML configuration files across multiple GitHub and Azure DevOps repositories",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -46,6 +46,7 @@
46
46
  "dependencies": {
47
47
  "chalk": "^5.3.0",
48
48
  "commander": "^14.0.2",
49
+ "json5": "^2.2.3",
49
50
  "p-retry": "^7.1.1",
50
51
  "yaml": "^2.4.5"
51
52
  },