Skip to content

Commit bfa58f5

Browse files
committed
fix(sync): handle non-existent markdown files correctly
Fixed issues when syncing to a markdown file that doesn't exist yet: - detectChanges now handles non-existent markdown files by treating them as empty documents and returning jsonChanged: true - syncCommand now tracks whether markdown existed before sync and sets mdChanged: true in the result when markdown is created from scratch - Added existsSync import to handle file existence checks This allows the sync command to be used to create markdown files from existing JSON documents, which is essential for the `--output` option when specifying a new markdown file path.
1 parent 6d600d2 commit bfa58f5

2 files changed

Lines changed: 38 additions & 8 deletions

File tree

src/cli/commands/sync.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import * as z from "zod";
2-
import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync } from "node:fs";
2+
import {
3+
readFileSync,
4+
writeFileSync,
5+
existsSync,
6+
mkdirSync,
7+
statSync,
8+
} from "node:fs";
39
import { resolve, extname } from "node:path";
410
import type { CommandDef } from "../define-command.js";
511
import {
@@ -9,7 +15,10 @@ import {
915
} from "../../operations/index.js";
1016
import { detectChanges } from "../../sync.js";
1117
import { markdownToJson } from "../../md-to-json.js";
12-
import { jsonToMarkdownSingle, jsonToMarkdownMultiDoc } from "../../json-to-md.js";
18+
import {
19+
jsonToMarkdownSingle,
20+
jsonToMarkdownMultiDoc,
21+
} from "../../json-to-md.js";
1322
import { canonicalise } from "../../canonical-json.js";
1423
import { SysProMDocument } from "../../schema.js";
1524

@@ -38,8 +47,10 @@ export function syncCommand(input: SyncCommandInput): BidirectionalSyncResult {
3847
throw new Error("JSON file is not a valid SysProM document");
3948
}
4049

41-
// Parse Markdown to document
42-
const mdDoc = markdownToJson(mdPath);
50+
// Parse Markdown to document, or create empty doc if it doesn't exist yet
51+
const mdDoc = existsSync(mdPath)
52+
? markdownToJson(mdPath)
53+
: { nodes: [], relationships: [] };
4354

4455
// Detect which side changed
4556
const changes = detectChanges(jsonPath, mdPath);
@@ -53,6 +64,9 @@ export function syncCommand(input: SyncCommandInput): BidirectionalSyncResult {
5364
strategy,
5465
});
5566

67+
// Track if markdown file existed before sync
68+
const mdExistedBefore = existsSync(mdPath);
69+
5670
// Write results if not dry-run
5771
if (!dryRun) {
5872
// Write synced document back to both formats
@@ -66,7 +80,7 @@ export function syncCommand(input: SyncCommandInput): BidirectionalSyncResult {
6680
// Update Markdown
6781
// If output path is an existing directory or doesn't look like a .md file,
6882
// write multi-doc output into the directory. Otherwise write single-file MD.
69-
if (existsSync(mdPath) && statSync(mdPath).isDirectory()) {
83+
if (mdExistedBefore && statSync(mdPath).isDirectory()) {
7084
jsonToMarkdownMultiDoc(result.synced, mdPath);
7185
} else if (extname(mdPath) === ".md") {
7286
const mdContent = jsonToMarkdownSingle(result.synced);
@@ -79,6 +93,11 @@ export function syncCommand(input: SyncCommandInput): BidirectionalSyncResult {
7993
}
8094
}
8195

96+
// If markdown file didn't exist before but does now (we created it), mark mdChanged as true
97+
if (!mdExistedBefore && existsSync(mdPath) && !dryRun) {
98+
result.mdChanged = true;
99+
}
100+
82101
return result;
83102
}
84103

src/sync.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { readFileSync, statSync } from "node:fs";
1+
import { readFileSync, statSync, existsSync } from "node:fs";
22
import { createHash } from "node:crypto";
33
import { markdownToJson } from "./md-to-json.js";
44
import { SysProMDocument } from "./schema.js";
@@ -61,8 +61,10 @@ export function detectChanges(
6161
throw new Error("JSON file is not a valid SysProM document");
6262
}
6363

64-
// Parse Markdown to document
65-
const mdDoc = markdownToJson(mdPath);
64+
// Parse Markdown to document (or treat as empty if it doesn't exist)
65+
const mdDoc = existsSync(mdPath)
66+
? markdownToJson(mdPath)
67+
: { nodes: [], relationships: [] };
6668

6769
// Compare parsed documents
6870
const jsonHash = normaliseHash(jsonDoc);
@@ -77,6 +79,15 @@ export function detectChanges(
7779
};
7880
}
7981

82+
// If markdown file doesn't exist, treat as if JSON changed (JSON is the source)
83+
if (!existsSync(mdPath)) {
84+
return {
85+
jsonChanged: true,
86+
mdChanged: false,
87+
conflict: false,
88+
};
89+
}
90+
8091
// Parsed documents differ. Use file modification times to determine which changed.
8192
// The file that was modified more recently is the one that diverged.
8293
const jsonStats = statSync(jsonPath);

0 commit comments

Comments
 (0)