json5-manifest-sync 0.1.4 → 0.2.1

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/CHANGELOG.md CHANGED
@@ -2,12 +2,23 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
- ## [0.1.4] - 2026-05-05
5
+ ## [0.2.1] - 2026-05-06
6
6
 
7
7
  ### Changed
8
8
 
9
- - Renamed the CLI option for suppressing generated blank `//` spacer comments to clearer `--remove-empty-comments` and `--remove-blank-comments` forms.
10
- - Kept legacy `--no-empty-comment` and `--no-empty-comments` aliases working for compatibility.
9
+ - Republished the `0.2.0` blank-comment workflow changes as `0.2.1` so the npm release can proceed with a new package version.
10
+
11
+ ## [0.2.0] - 2026-05-06
12
+
13
+ ### Breaking Changes
14
+
15
+ - The default blank-comment mode is now `preserve` instead of the previous placeholder-generating behavior. Existing users who want generated blank `//` lines must now pass `--blank-comments=fill`.
16
+
17
+ ### Changed
18
+
19
+ - Replaced the old blank-comment toggle with `--blank-comments=preserve|fill|remove`.
20
+ - Changed the default blank-comment mode to `preserve` so sync no longer introduces placeholder `//` lines unless requested.
21
+ - Added `--warn-blank-comments` to warn after sync when blank `//` placeholders remain.
11
22
 
12
23
  ## [0.1.3] - 2026-02-27
13
24
 
package/README.md CHANGED
@@ -49,14 +49,16 @@ When values like `version`, `scripts`, or dependency versions change in `package
49
49
  - Skips paths ignored by your root `.gitignore`
50
50
  - For each matching `package.json5`, rewrites values from canonical `package.json` (including `version`, scripts, dependencies, and other manifest fields)
51
51
  - Preserves/migrates mapped `//` comments for keys and supported array items
52
- - Inserts a blank `//` comment line before keys with no mapped comment (enabled by default)
52
+ - Supports three blank-comment modes: `preserve`, `fill`, and `remove`
53
53
  - Writes stable JSON5 formatting with trailing commas for cleaner diffs
54
54
 
55
55
  ### Current limitations
56
56
 
57
57
  - Per-item comment preservation is most reliable for arrays of strings.
58
- - Arrays of objects or numbers still serialize correctly, but item-level comments may be dropped or replaced by an empty `//` spacer on sync.
59
- - If you prefer to avoid regenerated blank spacer comments in those cases, run the CLI with `--remove-empty-comments`.
58
+ - Arrays of objects or numbers still serialize correctly, but item-level comments may be dropped.
59
+ - Use `--blank-comments=preserve` to keep existing blank `//` lines without adding new ones.
60
+ - Use `--blank-comments=fill` to add blank `//` placeholders where comments are omitted.
61
+ - Use `--blank-comments=remove` to strip blank `//` lines from the output.
60
62
 
61
63
  Repository: https://github.com/BBaysinger/json5-manifest-sync
62
64
 
@@ -125,13 +127,15 @@ For the current full output style, see this repo's live example: [`package.json5
125
127
 
126
128
  ### Options
127
129
 
128
- By default, the tool inserts an empty `//` line before keys that do not already have a mapped comment. Disable that behavior with one of the following:
130
+ By default, the tool runs with `--blank-comments=preserve`.
129
131
 
130
- - `--remove-empty-comments` or `--remove-blank-comments`
131
- - `--empty-comment=false`
132
- - env var: `SYNC_JSON5_ADD_EMPTY_COMMENT=false`
132
+ Choose a blank-comment mode with one of the following:
133
133
 
134
- Legacy aliases `--no-empty-comment` and `--no-empty-comments` are still accepted for compatibility.
134
+ - `--blank-comments=preserve`
135
+ - `--blank-comments=fill`
136
+ - `--blank-comments=remove`
137
+
138
+ To warn after sync when blank `//` placeholders remain, add `--warn-blank-comments`. That warning applies to `preserve` and `fill`; `remove` strips those lines.
135
139
 
136
140
  ### Formatting note
137
141
 
@@ -26,21 +26,18 @@
26
26
  * - Array item comment mapping is primarily intended for arrays of strings; arrays of
27
27
  * objects/numbers will serialize correctly but per-item comment preservation is limited.
28
28
  */
29
+ export type BlankCommentMode = "preserve" | "fill" | "remove";
29
30
  export type SyncOptions = {
30
31
  /**
31
- * When true, insert a blank comment line (`//`) before any key that has no
32
- * preceding comment captured from the existing JSON5. This helps visually
33
- * separate entries like:
32
+ * Controls how blank comment lines (`//`) are handled.
34
33
  *
35
- * "private": true,
36
- * //
37
- * "type": "module",
34
+ * - `preserve`: keep existing blank comment lines, but do not add new ones
35
+ * - `fill`: keep existing blank comment lines and add them where comments are omitted
36
+ * - `remove`: remove blank comment lines from the output
38
37
  *
39
- * Defaults to true. Can be disabled via CLI flags like
40
- * `--remove-empty-comments` or the environment variable
41
- * `SYNC_JSON5_ADD_EMPTY_COMMENT=false`.
38
+ * Defaults to `preserve`.
42
39
  */
43
- addEmptyCommentIfMissing?: boolean;
40
+ blankCommentMode?: BlankCommentMode;
44
41
  };
45
42
  /**
46
43
  * Synchronizes a JSON5 file with its canonical JSON source while preserving formatting.
@@ -4,6 +4,32 @@ import path from "path";
4
4
  import { fileURLToPath } from "url";
5
5
  import { sync as globSync } from "glob";
6
6
  import ignore from "ignore";
7
+ function isBlankCommentLine(line) {
8
+ return /^\s*\/\/\s*$/.test(line);
9
+ }
10
+ function normalizePrecedingComments(preceding, blankCommentMode) {
11
+ const comments = preceding ?? [];
12
+ if (blankCommentMode !== "remove") {
13
+ return comments;
14
+ }
15
+ return comments.filter((line) => !isBlankCommentLine(line));
16
+ }
17
+ function collectBlankCommentLineNumbers(raw) {
18
+ return raw
19
+ .split("\n")
20
+ .map((line, index) => ({ line, lineNumber: index + 1 }))
21
+ .filter(({ line }) => isBlankCommentLine(line))
22
+ .map(({ lineNumber }) => lineNumber);
23
+ }
24
+ function warnAboutBlankComments(filePath, blankCommentLines) {
25
+ if (blankCommentLines.length === 0) {
26
+ return;
27
+ }
28
+ const preview = blankCommentLines.slice(0, 8).join(", ");
29
+ const remainder = blankCommentLines.length > 8 ? ", ..." : "";
30
+ const plural = blankCommentLines.length === 1 ? "placeholder" : "placeholders";
31
+ console.warn(`[warn:blank-comments] ${path.basename(filePath)} contains ${blankCommentLines.length} blank comment ${plural} at line${blankCommentLines.length === 1 ? "" : "s"} ${preview}${remainder}. Fill them in with real notes, or rerun with --blank-comments=remove if you do not want placeholders.`);
32
+ }
7
33
  /**
8
34
  * Quotes an object key for consistent JSON5 formatting.
9
35
  * Always returns a quoted key to maintain consistency across all properties.
@@ -202,12 +228,10 @@ function generateScriptComment() {
202
228
  * @param source - Parsed JSON object from the canonical package.json
203
229
  * @returns The updated JSON5 content as a formatted string
204
230
  */
205
- export function syncJson5(raw, source, options = { addEmptyCommentIfMissing: true }) {
231
+ export function syncJson5(raw, source, options = { blankCommentMode: "preserve" }) {
206
232
  const lines = raw.split("\n");
207
233
  const comments = buildCommentMap(lines);
208
- const addEmptyCommentIfMissing = options.addEmptyCommentIfMissing !== undefined
209
- ? options.addEmptyCommentIfMissing
210
- : true;
234
+ const blankCommentMode = options.blankCommentMode ?? "preserve";
211
235
  /**
212
236
  * Recursively writes an object in normalized JSON5 style with mapped comments.
213
237
  *
@@ -230,13 +254,14 @@ export function syncJson5(raw, source, options = { addEmptyCommentIfMissing: tru
230
254
  const val = obj[key];
231
255
  const comma = ","; // Always add trailing comma for version control benefits
232
256
  const commentInfo = comments[fullPath];
257
+ const precedingComments = normalizePrecedingComments(commentInfo?.preceding, blankCommentMode);
233
258
  // Add any preceding comments above this key
234
- if (commentInfo?.preceding && commentInfo.preceding.length > 0) {
235
- for (const c of commentInfo.preceding) {
259
+ if (precedingComments.length > 0) {
260
+ for (const c of precedingComments) {
236
261
  result.push(indent(c, level));
237
262
  }
238
263
  }
239
- else if (addEmptyCommentIfMissing &&
264
+ else if (blankCommentMode === "fill" &&
240
265
  !comments.hasOwnProperty(fullPath)) {
241
266
  // No preceding comment captured — optionally add a blank one for spacing
242
267
  // Applies to any section, not just scripts
@@ -265,13 +290,14 @@ export function syncJson5(raw, source, options = { addEmptyCommentIfMissing: tru
265
290
  for (let j = 0; j < val.length; j++) {
266
291
  const itemPath = [...path, key, j.toString()].join(".");
267
292
  const itemCommentInfo = comments[itemPath];
293
+ const itemPrecedingComments = normalizePrecedingComments(itemCommentInfo?.preceding, blankCommentMode);
268
294
  // Add preceding comments for this array item
269
- if (itemCommentInfo?.preceding) {
270
- for (const c of itemCommentInfo.preceding) {
295
+ if (itemPrecedingComments.length > 0) {
296
+ for (const c of itemPrecedingComments) {
271
297
  result.push(indent(c, level + indentSize));
272
298
  }
273
299
  }
274
- else if (addEmptyCommentIfMissing &&
300
+ else if (blankCommentMode === "fill" &&
275
301
  !comments.hasOwnProperty(itemPath)) {
276
302
  const autoComment = generateScriptComment();
277
303
  result.push(indent(autoComment, level + indentSize));
@@ -329,29 +355,19 @@ export function runCli(args = process.argv.slice(2)) {
329
355
  ignore: ["**/node_modules/**"],
330
356
  absolute: true,
331
357
  });
332
- // Parse simple CLI flags / env for options
333
- let addEmptyCommentIfMissing = true;
334
- // Env toggle: SYNC_JSON5_ADD_EMPTY_COMMENT=false
335
- if (typeof process.env.SYNC_JSON5_ADD_EMPTY_COMMENT === "string" &&
336
- process.env.SYNC_JSON5_ADD_EMPTY_COMMENT.toLowerCase() === "false") {
337
- addEmptyCommentIfMissing = false;
338
- }
339
- // CLI toggles: --remove-empty-comments, --remove-blank-comments
358
+ // Parse CLI flags for options
359
+ let blankCommentMode = "preserve";
360
+ let warnOnBlankComments = false;
340
361
  for (const arg of args) {
341
- if (arg === "--remove-empty-comment" ||
342
- arg === "--remove-empty-comments" ||
343
- arg === "--remove-blank-comment" ||
344
- arg === "--remove-blank-comments" ||
345
- arg === "--no-empty-comment" ||
346
- arg === "--no-empty-comments") {
347
- addEmptyCommentIfMissing = false;
348
- }
349
- else if (arg.startsWith("--empty-comment=")) {
362
+ if (arg.startsWith("--blank-comments=")) {
350
363
  const v = arg.split("=", 2)[1]?.toLowerCase();
351
- if (v === "false" || v === "0" || v === "no") {
352
- addEmptyCommentIfMissing = false;
364
+ if (v === "preserve" || v === "fill" || v === "remove") {
365
+ blankCommentMode = v;
353
366
  }
354
367
  }
368
+ else if (arg === "--warn-blank-comments") {
369
+ warnOnBlankComments = true;
370
+ }
355
371
  }
356
372
  // Process each package.json to sync with its package.json5 counterpart
357
373
  for (const packageJsonPath of packageJsonPaths) {
@@ -369,11 +385,14 @@ export function runCli(args = process.argv.slice(2)) {
369
385
  const rawJson5 = fs.readFileSync(json5Path, "utf8");
370
386
  const sourceJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
371
387
  const updated = syncJson5(rawJson5, sourceJson, {
372
- addEmptyCommentIfMissing,
388
+ blankCommentMode,
373
389
  });
374
390
  // Write the synchronized result
375
391
  fs.writeFileSync(json5Path, updated);
376
392
  console.info(`✅ Synced ${relPath} → ${path.basename(json5Path)}`);
393
+ if (warnOnBlankComments && blankCommentMode !== "remove") {
394
+ warnAboutBlankComments(json5Path, collectBlankCommentLineNumbers(updated));
395
+ }
377
396
  }
378
397
  }
379
398
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json5-manifest-sync",
3
- "version": "0.1.4",
3
+ "version": "0.2.1",
4
4
  "description": "Sync package.json5 files from canonical package.json while preserving key comments.",
5
5
  "author": {
6
6
  "name": "Bradley Baysinger",
@@ -25,7 +25,7 @@
25
25
  ],
26
26
  "scripts": {
27
27
  "build": "tsc -p tsconfig.json",
28
- "sync:json5": "node ./dist/json5-manifest-sync.js",
28
+ "sync:json5": "node ./dist/json5-manifest-sync.js --blank-comments=fill",
29
29
  "warn:blank-comments": "node ./scripts/warn-blank-comments.mjs",
30
30
  "format": "prettier . --write",
31
31
  "format:check": "prettier . --check",