@songmu/mdhq 0.0.3 → 0.0.4

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
@@ -30,10 +30,13 @@ mdhq root
30
30
 
31
31
  `mdhq get` accepts multiple URLs as arguments or one URL per line on standard
32
32
  input; both sources are merged. It prints one absolute Markdown path per URL
33
- to stdout by default. Warnings are written to stderr. `--json` returns one
34
- result object for a single URL, or an array for multiple URLs. Requests are
35
- limited to eight in parallel, with requests to the same host serialized and
36
- spaced one second apart; image downloads use the same limits.
33
+ to stdout by default. Warnings are written to stderr. `--json` writes one
34
+ compact JSON result object per URL as JSON Lines. Results are written as soon
35
+ as each URL finishes, so parallel requests can produce output in completion
36
+ order rather than input order. If a later request fails, results already
37
+ written to stdout remain available.
38
+ Requests are limited to eight in parallel, with requests to the same host
39
+ serialized and spaced one second apart; image downloads use the same limits.
37
40
 
38
41
  `mdhq list` recursively lists `.md` files below the storage root, one per
39
42
  line, in sorted root-relative form. Use `-p` or `--full-path` to print absolute
package/dist/cli.js CHANGED
@@ -69,7 +69,7 @@ export function createProgram(io = process) {
69
69
  .option("--update", "update an existing page")
70
70
  .option("--user-agent <value>", "HTTP User-Agent")
71
71
  .option("--header <header>", "additional HTTP header", collect, [])
72
- .addOption(new Option("--json", "print a structured result"))
72
+ .addOption(new Option("--json", "print results as JSON Lines"))
73
73
  .action(async (urls, options) => {
74
74
  const inputUrls = await readStdinUrls(io.stdin);
75
75
  const requestedUrls = [...(urls ?? []), ...inputUrls]
@@ -79,7 +79,6 @@ export function createProgram(io = process) {
79
79
  throw new MdhqError("INVALID_URL", "At least one URL is required");
80
80
  }
81
81
  const scheduler = new RequestScheduler();
82
- const results = [];
83
82
  let nextIndex = 0;
84
83
  const worker = async () => {
85
84
  while (nextIndex < requestedUrls.length) {
@@ -89,7 +88,7 @@ export function createProgram(io = process) {
89
88
  if (url === undefined) {
90
89
  continue;
91
90
  }
92
- results[index] = await getPage({
91
+ const result = await getPage({
93
92
  url,
94
93
  ...(options.root ? { root: options.root } : {}),
95
94
  ...(options.assets === false ? { assets: false } : {}),
@@ -99,12 +98,21 @@ export function createProgram(io = process) {
99
98
  scheduler,
100
99
  onWarning: (warning) => io.stderr.write(`warning: ${warning.message}\n`)
101
100
  });
101
+ io.stdout.write(`${options.json ? JSON.stringify(result) : result.path}\n`);
102
102
  }
103
103
  };
104
- await Promise.all(Array.from({ length: Math.min(8, requestedUrls.length) }, () => worker()));
105
- io.stdout.write(options.json
106
- ? `${JSON.stringify(results.length === 1 ? results[0] : results, null, 2)}\n`
107
- : `${results.map((result) => result.path).join("\n")}\n`);
104
+ const failures = [];
105
+ await Promise.all(Array.from({ length: Math.min(8, requestedUrls.length) }, async () => {
106
+ try {
107
+ await worker();
108
+ }
109
+ catch (error) {
110
+ failures.push(error);
111
+ }
112
+ }));
113
+ if (failures.length > 0) {
114
+ throw failures[0];
115
+ }
108
116
  });
109
117
  program
110
118
  .command("list")
@@ -21,13 +21,13 @@ Runtime requirements:
21
21
  The executable provides three subcommands:
22
22
 
23
23
  ```text
24
- mdhq get [options] <url>
24
+ mdhq get [options] [urls...]
25
25
  mdhq list [options]
26
26
  mdhq root [options]
27
27
  ```
28
28
 
29
- `mdhq get` accepts exactly one URL per invocation. Parallel or multi-URL
30
- processing is delegated to external tools such as `xargs`.
29
+ `mdhq get` accepts multiple URL arguments and one URL per line from standard
30
+ input. Both sources are merged, and up to eight URLs are processed in parallel.
31
31
 
32
32
  ### `get` options
33
33
 
@@ -37,22 +37,19 @@ processing is delegated to external tools such as `xargs`.
37
37
  | `--update` | Fetch and replace an existing document with the same URL identity. |
38
38
  | `--user-agent <value>` | Override the default HTTP User-Agent. |
39
39
  | `--header <header>` | Add an HTTP header. The option is repeatable and uses `Name: value` syntax. |
40
- | `--json` | Write a structured result instead of only the Markdown path. |
41
-
42
- On success without `--json`, stdout contains exactly one absolute Markdown
43
- path followed by a newline. Warnings are written to stderr.
44
-
45
- With `--json`, stdout contains an object with this shape:
46
-
47
- ```json
48
- {
49
- "requestedUrl": "https://example.com/start",
50
- "sourceUrl": "https://example.com/article",
51
- "path": "/data/mdhq/example.com/article.md",
52
- "status": "saved",
53
- "assets": [],
54
- "warnings": []
55
- }
40
+ | `--json` | Write one result per line as JSON Lines instead of only the Markdown path. |
41
+
42
+ Without `--json`, stdout receives one absolute Markdown path per requested URL,
43
+ with each path followed by a newline. Each result is written as soon as that
44
+ URL finishes, so parallel requests can produce output in completion order
45
+ rather than input order.
46
+ Warnings are written to stderr.
47
+
48
+ With `--json`, stdout contains one compact JSON object per requested URL,
49
+ also written as soon as the URL finishes. Each line has this shape:
50
+
51
+ ```jsonl
52
+ {"requestedUrl":"https://example.com/start","sourceUrl":"https://example.com/article","path":"/data/mdhq/example.com/article.md","status":"saved","assets":[],"warnings":[]}
56
53
  ```
57
54
 
58
55
  `status` is one of:
@@ -63,7 +60,8 @@ With `--json`, stdout contains an object with this shape:
63
60
  body, including an HTTP 304 response.
64
61
  - `skipped`: an existing same-identity file was kept.
65
62
 
66
- An error is written to stderr and causes exit status `1`.
63
+ An error is written to stderr and causes exit status `1`. Results written to
64
+ stdout before the error remain available to downstream consumers.
67
65
 
68
66
  ### `list`
69
67
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@songmu/mdhq",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "Save web pages as Markdown in a ghq-inspired filesystem layout.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -69,6 +69,6 @@
69
69
  "@types/node": "^26.4.0",
70
70
  "@types/proper-lockfile": "4.1.4",
71
71
  "typescript": "^7.0.2",
72
- "vitest": "^4.1.11"
72
+ "vitest": "^5.0.0"
73
73
  }
74
74
  }