markdown-magic 4.0.5 → 4.1.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.
Files changed (3) hide show
  1. package/cli.js +1 -0
  2. package/package.json +2 -2
  3. package/src/cli-run.js +133 -1
package/cli.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ // @ts-ignore
2
3
  const mri = require('mri')
3
4
  const { runCli } = require('./src/cli-run')
4
5
  const argv = process.argv.slice(2)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdown-magic",
3
- "version": "4.0.5",
3
+ "version": "4.1.0",
4
4
  "description": "Automatically update markdown files with content from external sources",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -70,5 +70,5 @@
70
70
  "publishConfig": {
71
71
  "access": "public"
72
72
  },
73
- "gitHead": "7d81950b7a6d27d1192b1bc2d0f19d1d5ff0f321"
73
+ "gitHead": "4c7432d3518d9c6eac0019df43863ffc5857d417"
74
74
  }
package/src/cli-run.js CHANGED
@@ -1,8 +1,11 @@
1
1
  const path = require('path')
2
+ const fs = require('fs')
2
3
  const { loadConfig } = require('./utils/load-config')
3
4
  const { findUp } = require('./utils/fs')
4
5
  const { markdownMagic } = require('./')
6
+ const { processFile } = require('comment-block-replacer')
5
7
  const { parse } = require('oparser')
8
+ const defaultTransforms = require('./transforms')
6
9
  const { getGlobGroupsFromArgs } = require('./globparse')
7
10
  // const { deepLog } = require('./utils/logs')
8
11
  // const { uxParse } = require('./argparse/argparse')
@@ -10,6 +13,75 @@ const argv = process.argv.slice(2)
10
13
  const cwd = process.cwd()
11
14
  const defaultConfigPath = 'md.config.js'
12
15
 
16
+ /**
17
+ * Render markdown with ANSI styling for terminal output
18
+ * @param {string} content
19
+ */
20
+ // async function renderMarkdown(content) {
21
+ // const { render, themes } = await import('markdansi')
22
+ // const githubDark = {
23
+ // ...themes.default,
24
+ // heading: { color: 'white', bold: true },
25
+ // strong: { bold: true },
26
+ // emph: { italic: true },
27
+ // inlineCode: { color: 'yellow' },
28
+ // blockCode: { color: 'white' },
29
+ // link: { color: 'cyan', underline: true },
30
+ // quote: { color: 'gray', italic: true },
31
+ // hr: { color: 'gray', dim: true },
32
+ // listMarker: { color: 'blue' },
33
+ // tableHeader: { color: 'white', bold: true },
34
+ // tableCell: { color: 'white' },
35
+ // }
36
+ // return render(content, { theme: githubDark })
37
+ // }
38
+
39
+ /**
40
+ * Read all data from stdin
41
+ * @returns {Promise<string>}
42
+ */
43
+ function readStdin() {
44
+ return new Promise((resolve, reject) => {
45
+ let data = ''
46
+ process.stdin.setEncoding('utf8')
47
+ process.stdin.on('data', chunk => data += chunk)
48
+ process.stdin.on('end', () => resolve(data))
49
+ process.stdin.on('error', reject)
50
+ })
51
+ }
52
+
53
+ /**
54
+ * Interpret escape sequences in string (e.g., \n -> newline)
55
+ * @param {string} str
56
+ * @returns {string}
57
+ */
58
+ function interpretEscapes(str) {
59
+ if (!str) return str
60
+ return str.replace(/\\n/g, '\n').replace(/\\t/g, '\t')
61
+ }
62
+
63
+ /**
64
+ * Check if string looks like markdown content vs a file path
65
+ * @param {string} str
66
+ * @returns {boolean}
67
+ */
68
+ function isMarkdownContent(str) {
69
+ if (!str) return false
70
+ // Has newlines (real or escaped) = likely content
71
+ if (str.includes('\n') || str.includes('\\n')) return true
72
+ // Has markdown comment blocks = likely content
73
+ if (str.includes('<!--')) return true
74
+ // Check if file exists
75
+ try {
76
+ if (fs.existsSync(str)) return false
77
+ } catch (e) {
78
+ // ignore
79
+ }
80
+ // Has markdown heading at start = likely content
81
+ if (str.startsWith('#')) return true
82
+ return false
83
+ }
84
+
13
85
  async function getBaseDir(opts = {}) {
14
86
  const { currentDir = cwd } = opts
15
87
  const gitDir = await findUp(currentDir, '.git')
@@ -29,6 +101,9 @@ Options:
29
101
  --files, --file Files or glob patterns to process
30
102
  --config Path to config file (default: md.config.js)
31
103
  --output Output directory
104
+ --open Opening comment keyword (default: docs)
105
+ --close Closing comment keyword (default: /docs)
106
+ --pretty Render output with ANSI styling
32
107
  --dry Dry run - show what would be changed
33
108
  --debug Show debug output
34
109
  --help, -h Show this help message
@@ -38,16 +113,73 @@ Examples:
38
113
  md-magic README.md
39
114
  md-magic --files "**/*.md"
40
115
  md-magic --config ./my-config.js
116
+
117
+ Stdin/stdout mode:
118
+ cat file.md | md-magic
119
+ echo "<!-- docs TOC --><!-- /docs -->" | md-magic
120
+ md-magic "# Title\\n<!-- docs TOC --><!-- /docs -->"
41
121
  `)
42
122
  return
43
123
  }
44
124
 
45
125
  if (options.version || options.v) {
126
+ // @ts-ignore
46
127
  const pkg = require('../package.json')
47
- console.log(pkg.version)
128
+ console.log(`${pkg.name} v${pkg.version}`)
48
129
  return
49
130
  }
50
131
 
132
+ // Check if first positional arg is markdown content (before stdin check)
133
+ const firstArg = options._ && options._[0]
134
+ const openKeyword = options.open || 'docs'
135
+ const closeKeyword = options.close || (options.open && options.open !== 'docs' ? `/${options.open}` : '/docs')
136
+ if (firstArg && isMarkdownContent(firstArg)) {
137
+ const content = interpretEscapes(firstArg)
138
+ const result = await processFile({
139
+ content,
140
+ syntax: 'md',
141
+ open: openKeyword,
142
+ close: closeKeyword,
143
+ transforms: defaultTransforms,
144
+ dryRun: true,
145
+ })
146
+ // TODO future pretty option
147
+ // if (options.pretty) {
148
+ // console.log(await renderMarkdown(result.updatedContents))
149
+ // } else {
150
+ // console.log()
151
+ // console.log(result.updatedContents)
152
+ // }
153
+ console.log(result.updatedContents)
154
+ return
155
+ }
156
+
157
+ // Check for stdin pipe (when no positional file args provided)
158
+ const hasNoFileArgs = !options._ || options._.length === 0
159
+ const hasPipedInput = !process.stdin.isTTY && hasNoFileArgs
160
+ if (hasPipedInput) {
161
+ const content = await readStdin()
162
+ if (content.trim()) {
163
+ const result = await processFile({
164
+ content,
165
+ syntax: 'md',
166
+ open: openKeyword,
167
+ close: closeKeyword,
168
+ transforms: defaultTransforms,
169
+ dryRun: true, // Don't write files
170
+ })
171
+ // TODO future pretty option
172
+ // if (options.pretty) {
173
+ // console.log(await renderMarkdown(result.updatedContents))
174
+ // } else {
175
+ // console.log()
176
+ // console.log(result.updatedContents)
177
+ // }
178
+ console.log(result.updatedContents)
179
+ return
180
+ }
181
+ }
182
+
51
183
  let configFile
52
184
  let opts = {}
53
185