md4x 0.0.1 → 0.0.3
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/lib/cli.mjs +94 -15
- package/package.json +3 -2
package/lib/cli.mjs
CHANGED
|
@@ -22,22 +22,44 @@ const { values, positionals } = parseArgs({
|
|
|
22
22
|
},
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
const _tty = process.stderr.isTTY;
|
|
26
|
+
const c = (code) => (s) => _tty ? `\x1b[${code}m${s}\x1b[0m` : s;
|
|
27
|
+
const _b = c(1);
|
|
28
|
+
const _d = c(2);
|
|
29
|
+
const _c = c(36);
|
|
30
|
+
const _g = c(32);
|
|
31
|
+
|
|
25
32
|
function usage() {
|
|
26
33
|
process.stderr.write(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
`${_b("md4x")} — Markdown renderer
|
|
35
|
+
|
|
36
|
+
${_g("Usage:")} ${_b("md4x")} ${_d("[OPTION]... [FILE]")}
|
|
37
|
+
|
|
38
|
+
${_g("General options:")}
|
|
39
|
+
${_c("-o")}, ${_c("--output")}=${_d("FILE")} Output file ${_d("(default: stdout)")}
|
|
40
|
+
${_c("-t")}, ${_c("--format")}=${_d("FORMAT")} Output format: html, json, ansi ${_d("(default: ansi for TTY, html otherwise)")}
|
|
41
|
+
${_c("-s")}, ${_c("--stat")} Measure parsing time
|
|
42
|
+
${_c("-h")}, ${_c("--help")} Display this help and exit
|
|
43
|
+
${_c("-v")}, ${_c("--version")} Display version and exit
|
|
44
|
+
|
|
45
|
+
${_g("Input:")}
|
|
46
|
+
File path, ${_c("-")} for stdin, HTTP/HTTPS URL, or shorthand:
|
|
47
|
+
${_c("gh:")}${_d("<owner>/<repo>[/path]")} GitHub raw content
|
|
48
|
+
${_c("npm:")}${_d("<package>[@version][/path]")} npm package via unpkg
|
|
49
|
+
|
|
50
|
+
${_g("HTML options:")}
|
|
51
|
+
${_c("-f")}, ${_c("--full-html")} Full HTML document with header
|
|
52
|
+
${_c("--html-title")}=${_d("TITLE")} Document title
|
|
53
|
+
${_c("--html-css")}=${_d("URL")} CSS link
|
|
54
|
+
|
|
55
|
+
${_g("Examples:")}
|
|
56
|
+
${_d("$")} ${_b("md4x")} README.md ${_d("# Render to terminal")}
|
|
57
|
+
${_d("$")} ${_b("md4x")} ${_c("-t html")} doc.md ${_d("# HTML output")}
|
|
58
|
+
${_d("$")} ${_b("md4x")} ${_c("-t json")} doc.md ${_d("# JSON AST output")}
|
|
59
|
+
${_d("$")} ${_b("md4x")} ${_c("gh:")}pi0/md4x ${_d("# GitHub repo README")}
|
|
60
|
+
${_d("$")} ${_b("md4x")} ${_c("npm:")}vue@3 ${_d("# npm package README")}
|
|
61
|
+
${_d("$")} echo "# Hello" | ${_b("md4x")} ${_d("# Pipe from stdin")}
|
|
62
|
+
${_d("$")} ${_b("md4x")} ${_c("-f --html-css")}=style.css doc.md ${_d("# Full HTML with CSS")}
|
|
41
63
|
`,
|
|
42
64
|
);
|
|
43
65
|
}
|
|
@@ -62,7 +84,23 @@ if (!["html", "json", "ansi"].includes(format)) {
|
|
|
62
84
|
process.exit(1);
|
|
63
85
|
}
|
|
64
86
|
|
|
65
|
-
|
|
87
|
+
let inputPath = positionals[0];
|
|
88
|
+
// gh:owner/repo[/path] → https://github.com/owner/repo[/path]
|
|
89
|
+
if (inputPath && /^gh:/i.test(inputPath)) {
|
|
90
|
+
inputPath = `https://github.com/${inputPath.slice(3)}`;
|
|
91
|
+
}
|
|
92
|
+
// npm:package[@version][/path] → https://unpkg.com/package[@version][/path]
|
|
93
|
+
if (inputPath && /^npm:/i.test(inputPath)) {
|
|
94
|
+
const spec = inputPath.slice(4);
|
|
95
|
+
// Check if spec includes a file path (after the package name + optional version)
|
|
96
|
+
// Scoped: @scope/pkg[@ver][/path] — path starts after 2nd slash
|
|
97
|
+
// Unscoped: pkg[@ver][/path] — path starts after 1st slash
|
|
98
|
+
const slashIdx = spec.startsWith("@")
|
|
99
|
+
? spec.indexOf("/", spec.indexOf("/") + 1)
|
|
100
|
+
: spec.indexOf("/");
|
|
101
|
+
const hasPath = slashIdx > 0;
|
|
102
|
+
inputPath = `https://unpkg.com/${spec}${hasPath ? "" : "/README.md"}`;
|
|
103
|
+
}
|
|
66
104
|
let input;
|
|
67
105
|
if (!inputPath || inputPath === "-") {
|
|
68
106
|
if (process.stdin.isTTY) {
|
|
@@ -75,6 +113,23 @@ if (!inputPath || inputPath === "-") {
|
|
|
75
113
|
usage();
|
|
76
114
|
process.exit(1);
|
|
77
115
|
}
|
|
116
|
+
} else if (/^https?:\/\//i.test(inputPath)) {
|
|
117
|
+
const fetchUrl = toRawUrl(inputPath);
|
|
118
|
+
try {
|
|
119
|
+
const res = await fetch(fetchUrl, {
|
|
120
|
+
headers: { Accept: "text/markdown, text/plain;q=0.9, */*;q=0.1" },
|
|
121
|
+
});
|
|
122
|
+
if (!res.ok) {
|
|
123
|
+
process.stderr.write(
|
|
124
|
+
`Failed to fetch ${inputPath}: ${res.status} ${res.statusText}\n`,
|
|
125
|
+
);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
input = await res.text();
|
|
129
|
+
} catch (err) {
|
|
130
|
+
process.stderr.write(`Failed to fetch ${inputPath}: ${err.message}\n`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
78
133
|
} else {
|
|
79
134
|
try {
|
|
80
135
|
input = readFileSync(inputPath, "utf8");
|
|
@@ -136,3 +191,27 @@ if (values.output && values.output !== "-") {
|
|
|
136
191
|
} else {
|
|
137
192
|
process.stdout.write(result);
|
|
138
193
|
}
|
|
194
|
+
|
|
195
|
+
// --- internal helpers ---
|
|
196
|
+
|
|
197
|
+
/** Convert GitHub web URLs to raw content URLs */
|
|
198
|
+
function toRawUrl(url) {
|
|
199
|
+
const u = new URL(url);
|
|
200
|
+
if (u.hostname === "github.com" || u.hostname === "www.github.com") {
|
|
201
|
+
// github.com/:owner/:repo/blob/:ref/path → raw.githubusercontent.com/:owner/:repo/:ref/path
|
|
202
|
+
const blob = u.pathname.match(/^\/([^/]+\/[^/]+)\/blob\/(.+)/);
|
|
203
|
+
if (blob) {
|
|
204
|
+
return `https://raw.githubusercontent.com/${blob[1]}/${blob[2]}`;
|
|
205
|
+
}
|
|
206
|
+
// github.com/:owner/:repo → raw.githubusercontent.com/:owner/:repo/HEAD/README.md
|
|
207
|
+
const repo = u.pathname.match(/^\/([^/]+\/[^/]+)\/?$/);
|
|
208
|
+
if (repo) {
|
|
209
|
+
return `https://raw.githubusercontent.com/${repo[1]}/HEAD/README.md`;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// gist.github.com/:user/:id → gist.githubusercontent.com/:user/:id/raw
|
|
213
|
+
if (u.hostname === "gist.github.com") {
|
|
214
|
+
return `https://gist.githubusercontent.com${u.pathname}/raw`;
|
|
215
|
+
}
|
|
216
|
+
return url;
|
|
217
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "md4x",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"build",
|
|
26
|
-
"lib"
|
|
26
|
+
"lib",
|
|
27
|
+
"README.md"
|
|
27
28
|
],
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@milkdown/crepe": "^7.18.0",
|