markdown-magic 2.6.1 → 3.0.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/README.md +47 -37
- package/cli.js +5 -82
- package/lib/block-parser-js.test.js +171 -0
- package/lib/block-parser.js +382 -0
- package/lib/block-parser.test.js +479 -0
- package/lib/cli.js +245 -0
- package/lib/cli.test.js +409 -0
- package/lib/defaults.js +12 -0
- package/lib/globals.d.ts +66 -0
- package/lib/index.js +353 -184
- package/lib/index.test.js +11 -0
- package/lib/process-contents.js +371 -0
- package/lib/process-file.js +37 -0
- package/lib/transforms/code.js +67 -28
- package/lib/transforms/file.js +17 -17
- package/lib/transforms/index.js +0 -114
- package/lib/transforms/remote.js +8 -6
- package/lib/transforms/sectionToc.js +18 -0
- package/lib/transforms/toc.js +12 -265
- package/lib/transforms/wordCount.js +5 -0
- package/lib/types.js +11 -0
- package/lib/utils/fs.js +342 -0
- package/lib/utils/fs.test.js +267 -0
- package/lib/utils/index.js +19 -0
- package/{cli-utils.js → lib/utils/load-config.js} +2 -6
- package/lib/utils/logs.js +94 -0
- package/lib/utils/md/filters.js +20 -0
- package/lib/utils/md/find-code-blocks.js +88 -0
- package/lib/utils/md/find-date.js +32 -0
- package/lib/utils/md/find-frontmatter.js +92 -0
- package/lib/utils/md/find-frontmatter.test.js +17 -0
- package/lib/utils/md/find-html-tags.js +105 -0
- package/lib/utils/md/find-images-md.js +27 -0
- package/lib/utils/md/find-images.js +107 -0
- package/lib/utils/md/find-links.js +220 -0
- package/lib/utils/md/find-unmatched-html-tags.js +32 -0
- package/lib/utils/md/fixtures/2022-01-22-date-in-filename.md +14 -0
- package/lib/utils/md/fixtures/file-with-frontmatter.md +32 -0
- package/lib/utils/md/fixtures/file-with-links.md +153 -0
- package/lib/utils/md/md.test.js +105 -0
- package/lib/utils/md/parse.js +146 -0
- package/lib/utils/md/utils.js +19 -0
- package/lib/utils/regex-timeout.js +84 -0
- package/lib/utils/regex.js +40 -6
- package/lib/utils/remoteRequest.js +55 -0
- package/lib/utils/syntax.js +82 -0
- package/lib/utils/text.js +328 -0
- package/lib/utils/text.test.js +305 -0
- package/lib/utils/toc.js +315 -0
- package/package.json +30 -26
- package/index.js +0 -46
- package/lib/processFile.js +0 -154
- package/lib/updateContents.js +0 -125
- package/lib/utils/_md.test.js +0 -63
- package/lib/utils/new-parser.js +0 -412
- package/lib/utils/new-parser.test.js +0 -324
- package/lib/utils/weird-parse.js +0 -230
- package/lib/utils/weird-parse.test.js +0 -217
package/lib/index.js
CHANGED
|
@@ -1,219 +1,388 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
|
-
const
|
|
3
|
-
const
|
|
2
|
+
const { glob, globWithGit } = require('smart-glob')
|
|
3
|
+
const codeTransform = require('./transforms/code')
|
|
4
|
+
const fileTransform = require('./transforms/file')
|
|
5
|
+
const tocTransform = require('./transforms/toc')
|
|
6
|
+
const sectionTocTransform = require('./transforms/sectionToc')
|
|
7
|
+
const wordCountTransform = require('./transforms/wordCount')
|
|
8
|
+
const remoteTransform = require('./transforms/remote')
|
|
9
|
+
const { getSyntaxInfo } = require('./utils/syntax')
|
|
10
|
+
const { onlyUnique, getCodeLocation, pluralize } = require('./utils')
|
|
11
|
+
const { writeFile, resolveOutputPath, resolveFlatPath } = require('./utils/fs')
|
|
12
|
+
const { processFile } = require('./process-file')
|
|
13
|
+
const { processContents } = require('./process-contents')
|
|
14
|
+
const { parseMarkdown } = require('./utils/md/parse')
|
|
15
|
+
const { deepLog, success, error, info } = require('./utils/logs')
|
|
16
|
+
const { OPEN_WORD, CLOSE_WORD, DEFAULT_GLOB_PATTERN } = require('./defaults')
|
|
17
|
+
// const { getBlockRegex } = require('./block-parser')
|
|
18
|
+
// const diff = require('../misc/old-test/utils/diff')
|
|
4
19
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
const LINE = '────────────────────────────────'
|
|
21
|
+
|
|
22
|
+
const defaultTransforms = {
|
|
23
|
+
CODE: codeTransform,
|
|
24
|
+
FILE: fileTransform,
|
|
25
|
+
TOC: tocTransform,
|
|
26
|
+
sectionToc: sectionTocTransform,
|
|
27
|
+
wordCount: wordCountTransform,
|
|
28
|
+
remote: remoteTransform
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Allowed file syntaxes
|
|
33
|
+
* @typedef {'md' | 'js' | 'yml' | 'yaml'} SyntaxType
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Configuration for markdown magic
|
|
38
|
+
*
|
|
39
|
+
* Below is the main config for markdown magic
|
|
40
|
+
*
|
|
41
|
+
* @typedef {object} MarkdownMagicOptions
|
|
42
|
+
* @property {Array} [transforms = defaultTransforms] - Custom commands to transform block contents, see transforms & custom transforms sections below.
|
|
43
|
+
* @property {string} [outputDir] - Change output path of new content. Default behavior is replacing the original file
|
|
44
|
+
* @property {SyntaxType} [syntax = 'md'] - Syntax to parse
|
|
45
|
+
* @property {boolean} [outputFlatten] - Flatten files that are output
|
|
46
|
+
* @property {function} [handleOutputPath] - Custom function for altering output paths
|
|
47
|
+
* @property {boolean} [useGitGlob] - Use git glob for LARGE file directories
|
|
48
|
+
* @property {boolean} [dryRun = false] - See planned execution of matched blocks
|
|
49
|
+
* @property {boolean} [debug = false] - See debug details
|
|
50
|
+
* @property {boolean} [failOnMissingTransforms = false] - Fail if transform functions are missing. Default skip blocks.
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Markdown Magic
|
|
55
|
+
* @param {string|MarkdownMagicOptions} globOrOpts - Files to process or config. Uses [globby patterns](https://github.com/sindresorhus/multimatch/blob/master/test.js)
|
|
56
|
+
* @param {MarkdownMagicOptions} options - Markdown magic config
|
|
57
|
+
* @returns
|
|
58
|
+
* @example
|
|
59
|
+
markdownMagic(filePath, config)
|
|
60
|
+
*/
|
|
61
|
+
async function markdownMagic(globOrOpts, options = {}) {
|
|
62
|
+
let opts = options || {}
|
|
63
|
+
let globPat
|
|
64
|
+
if (typeof globOrOpts === 'string' || Array.isArray(globOrOpts)) {
|
|
65
|
+
opts = options
|
|
66
|
+
globPat = globOrOpts
|
|
67
|
+
} else if (typeof globOrOpts === 'object') {
|
|
68
|
+
opts = globOrOpts
|
|
69
|
+
}
|
|
70
|
+
const {
|
|
71
|
+
transforms,
|
|
72
|
+
// open,
|
|
73
|
+
outputDir,
|
|
74
|
+
outputFlatten = false,
|
|
75
|
+
handleOutputPath,
|
|
76
|
+
useGitGlob = false,
|
|
77
|
+
failOnMissingTransforms = false,
|
|
78
|
+
dryRun = false,
|
|
79
|
+
debug = true,
|
|
80
|
+
syntax = 'md',
|
|
81
|
+
} = opts
|
|
82
|
+
|
|
83
|
+
let open = OPEN_WORD
|
|
84
|
+
if (opts.open) {
|
|
85
|
+
open = opts.open
|
|
86
|
+
} else if (opts.matchWord) {
|
|
87
|
+
open = `${opts.matchWord}:start`
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let close = CLOSE_WORD
|
|
91
|
+
if (opts.close) {
|
|
92
|
+
close = opts.close
|
|
93
|
+
} else if (opts.matchWord) {
|
|
94
|
+
close = `${opts.matchWord}:end`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// console.log('outputDir', outputDir)
|
|
98
|
+
// console.log('outputFlatten', outputFlatten)
|
|
99
|
+
// return
|
|
17
100
|
|
|
18
|
-
const
|
|
19
|
-
|
|
101
|
+
const cwd = opts.cwd || process.cwd()
|
|
102
|
+
// console.log('cwd', cwd)
|
|
103
|
+
const globPattern = globPat || globOrOpts.glob || globOrOpts.file || globOrOpts.files
|
|
104
|
+
// console.log('globPattern', globPattern)
|
|
105
|
+
|
|
106
|
+
const useTransforms = Object.assign({}, defaultTransforms, transforms)
|
|
107
|
+
let globs = []
|
|
108
|
+
if (!globPattern) {
|
|
109
|
+
globs = [ DEFAULT_GLOB_PATTERN ]
|
|
110
|
+
} else if (Array.isArray(globPattern)) {
|
|
111
|
+
globs = globPattern
|
|
112
|
+
} else if (typeof globPattern === 'string') {
|
|
113
|
+
globs = [ globPattern ]
|
|
114
|
+
}
|
|
115
|
+
opts.glob = globs
|
|
116
|
+
// console.log('globs', globs)
|
|
117
|
+
// return
|
|
118
|
+
|
|
119
|
+
info(`Running Markdown Magic:`)
|
|
120
|
+
logCommentBlockSyntax({
|
|
121
|
+
syntax: syntax,
|
|
20
122
|
open,
|
|
21
|
-
close
|
|
123
|
+
close
|
|
22
124
|
})
|
|
23
125
|
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
console.log(
|
|
126
|
+
if (dryRun || debug) {
|
|
127
|
+
info(`Glob patterns:`)
|
|
128
|
+
console.log(globs)
|
|
129
|
+
console.log()
|
|
130
|
+
/*
|
|
131
|
+
process.exit(1)
|
|
132
|
+
/** */
|
|
27
133
|
}
|
|
28
134
|
|
|
29
|
-
const
|
|
30
|
-
// console.log('transformsToRun', transformsToRun)
|
|
31
|
-
|
|
32
|
-
// if (!transformsToRun.length) {
|
|
33
|
-
// process.exit(1)
|
|
34
|
-
// }
|
|
35
|
-
|
|
36
|
-
let missingTransforms = []
|
|
37
|
-
const updatedContents = await transformsToRun.reduce(async (updatedContent, ogmatch) => {
|
|
38
|
-
const md = await updatedContent
|
|
39
|
-
/* Apply Before middleware to all transforms */
|
|
40
|
-
const match = await applyMiddleware(ogmatch, md, beforeMiddelwares)
|
|
41
|
-
const { block, raw, transform, args } = match
|
|
42
|
-
const { openTag, closeTag, content, contentStart, contentEnd, start, end } = block
|
|
43
|
-
|
|
44
|
-
/* Run transform plugins */
|
|
45
|
-
let tempContent = content
|
|
46
|
-
if (transforms[transform]) {
|
|
47
|
-
tempContent = await transforms[transform](match, md)
|
|
48
|
-
}
|
|
135
|
+
const globFn = (useGitGlob) ? globWithGit : glob
|
|
49
136
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (!transforms[transform]) {
|
|
65
|
-
missingTransforms.push(afterContent)
|
|
66
|
-
console.log(`Missing "${transform}" transform`)
|
|
67
|
-
}
|
|
137
|
+
const pathsPromise = globs.map((str) => {
|
|
138
|
+
// console.log('str', str)
|
|
139
|
+
// Glob pattern examples https://github.com/terkelg/globrex/blob/master/test/index.js
|
|
140
|
+
// return globWithGit(str, {
|
|
141
|
+
// const g = str.replace(/^(?:\.\.\/)+/, "")
|
|
142
|
+
// console.log('g', g)
|
|
143
|
+
return globFn(str, {
|
|
144
|
+
absolute: true,
|
|
145
|
+
alwaysReturnUnixPaths: true,
|
|
146
|
+
ignoreGlobs: ['**/node_modules/**'],
|
|
147
|
+
})
|
|
148
|
+
})
|
|
68
149
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// console.log('fix', fix)
|
|
77
|
-
const preserveIndent = (true || args.preserveIndent) ? block.indentation.length + block.contentIndent : block.indentation.length
|
|
78
|
-
const indent = indentString(fix, preserveIndent)
|
|
79
|
-
const newCont = `${openTag}${indent}${closeTag}`
|
|
80
|
-
/* Replace original contents */
|
|
81
|
-
const newContents = md.replace(raw.block, newCont)
|
|
82
|
-
return Promise.resolve(newContents)
|
|
83
|
-
}, Promise.resolve(originalContents))
|
|
84
|
-
|
|
85
|
-
if (DEBUG) {
|
|
86
|
-
console.log('Output Markdown')
|
|
87
|
-
console.log(updatedContents)
|
|
150
|
+
let files = []
|
|
151
|
+
try {
|
|
152
|
+
files = (await Promise.all(pathsPromise)).flat().filter(onlyUnique)
|
|
153
|
+
opts.files = files
|
|
154
|
+
} catch (e) {
|
|
155
|
+
console.log(e.message)
|
|
156
|
+
throw new Error(e)
|
|
88
157
|
}
|
|
158
|
+
// console.log('files', files)
|
|
159
|
+
// return
|
|
160
|
+
// console.log('globs', globs)
|
|
161
|
+
// const filex = await globby(globs)
|
|
162
|
+
// console.log('filex', filex)
|
|
89
163
|
|
|
90
164
|
/*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
matchOne = missingTransforms[missingTransforms.length - 1]
|
|
95
|
-
// console.log('matchOne', matchOne)
|
|
96
|
-
const { block, transform, args } = matchOne
|
|
97
|
-
const { openTag, closeTag, content, contentStart, contentEnd, start, end} = block
|
|
98
|
-
|
|
99
|
-
// console.log('contentStart', contentStart)
|
|
100
|
-
// console.log('contentEnd', contentEnd)
|
|
101
|
-
// console.log('original text between', `"${getTextBetween(md, contentStart, contentEnd)}"`)
|
|
102
|
-
// console.log('original block between', `"${getTextBetween(md, start, end)}"`)
|
|
103
|
-
}
|
|
165
|
+
const relativeFilePaths = files.map((file) => file.replace(cwd, '').replace(/^\//, ''))
|
|
166
|
+
console.log('relativeFilePaths', relativeFilePaths)
|
|
167
|
+
process.exit(1)
|
|
104
168
|
/** */
|
|
105
169
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
170
|
+
if (dryRun || debug) {
|
|
171
|
+
info(`${files.length} Files found:`)
|
|
172
|
+
console.log(files)
|
|
173
|
+
/*
|
|
174
|
+
process.exit(1)
|
|
175
|
+
/** */
|
|
112
176
|
}
|
|
113
|
-
}
|
|
114
177
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
178
|
+
const processedFiles = files.map((file) => {
|
|
179
|
+
// console.log('file', file)
|
|
180
|
+
let newPath = path.resolve(cwd, file)
|
|
181
|
+
/* Allow for different output directory */
|
|
182
|
+
if (outputDir) {
|
|
183
|
+
newPath = (outputFlatten) ? resolveFlatPath(cwd, outputDir, file) : resolveOutputPath(cwd, outputDir, file)
|
|
184
|
+
}
|
|
185
|
+
/* Allow for custom handling of individual files */
|
|
186
|
+
if (handleOutputPath) {
|
|
187
|
+
newPath = handleOutputPath(newPath)
|
|
188
|
+
}
|
|
189
|
+
// const cleanerDirPath = path.dirname(file)
|
|
190
|
+
// const baseDir = cleanerDirPath.replace(cwd, '')
|
|
191
|
+
// const cleanerDir = baseDir
|
|
192
|
+
// const resolvedDir = path.join(cleanerDir, outputDir)
|
|
193
|
+
// const cleanFinalPath = path.resolve(resolvedDir, path.basename(file))
|
|
194
|
+
/*
|
|
195
|
+
console.log('cleanerDir', cleanerDir)
|
|
196
|
+
console.log('resolvedDir', resolvedDir)
|
|
197
|
+
console.log('cleanFinalPath', cleanFinalPath)
|
|
198
|
+
/** */
|
|
199
|
+
// console.log('newPath', newPath)
|
|
200
|
+
return processFile({
|
|
201
|
+
...opts,
|
|
202
|
+
open,
|
|
203
|
+
close,
|
|
204
|
+
srcPath: file,
|
|
205
|
+
outputPath: newPath,
|
|
206
|
+
transforms: useTransforms
|
|
207
|
+
})
|
|
208
|
+
})
|
|
209
|
+
// process.exit(1)
|
|
210
|
+
const plan = (await Promise.all(processedFiles)).filter((file) => {
|
|
211
|
+
/* Filter out files without transforms */
|
|
212
|
+
return file.transforms.length
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
if (dryRun || debug) {
|
|
216
|
+
/* Generate output paths */
|
|
217
|
+
const outputPaths = plan.map((item) => item.outputPath)
|
|
218
|
+
info(`Output files:`)
|
|
219
|
+
console.log(outputPaths)
|
|
220
|
+
/*
|
|
221
|
+
process.exit(1)
|
|
222
|
+
/** */
|
|
223
|
+
}
|
|
224
|
+
/*
|
|
225
|
+
console.log('plan')
|
|
226
|
+
deepLog(plan)
|
|
227
|
+
process.exit(1)
|
|
228
|
+
/** */
|
|
229
|
+
|
|
230
|
+
const missing = plan.filter((item) => {
|
|
231
|
+
return item.missingTransforms.length
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
let errors = []
|
|
235
|
+
if (missing.length) {
|
|
236
|
+
errors = missing.map((item, i) => {
|
|
237
|
+
const errorMessage = `Missing ${item.missingTransforms.length} transforms in ${item.srcPath}`
|
|
238
|
+
const issues = item.missingTransforms.map((trn) => {
|
|
239
|
+
// console.log('trn', trn)
|
|
240
|
+
// const rowData = getRowAndColumnFromCharPos(item.updatedContents, trn.open.start)
|
|
241
|
+
const location = `${item.srcPath}:${trn.block.lines[0]}:0`
|
|
242
|
+
const message = `Transform "${trn.transform}" at line ${trn.block.lines[0]} does not exist. → ${location}`
|
|
243
|
+
return {
|
|
244
|
+
message,
|
|
245
|
+
location
|
|
127
246
|
}
|
|
247
|
+
})
|
|
248
|
+
return {
|
|
249
|
+
errorMessage,
|
|
250
|
+
errors: issues
|
|
128
251
|
}
|
|
129
252
|
})
|
|
130
|
-
}
|
|
131
|
-
}
|
|
253
|
+
}
|
|
132
254
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
255
|
+
/* If transform errors and should throw, exit early */
|
|
256
|
+
if (errors.length && failOnMissingTransforms) {
|
|
257
|
+
throw new Error(logErrors(errors))
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/* Log out execution plan */
|
|
261
|
+
let planTotal = 0
|
|
262
|
+
let missingTotal = 0
|
|
263
|
+
const planOutput = plan.map((item, i) => {
|
|
264
|
+
const transformsToRun = item.transforms.filter((item) => {
|
|
265
|
+
if (item.context.isMissing) {
|
|
266
|
+
// console.log('item', item)
|
|
267
|
+
missingTotal = missingTotal + 1
|
|
268
|
+
}
|
|
269
|
+
return !item.context.isMissing
|
|
270
|
+
})
|
|
271
|
+
if (!transformsToRun.length) {
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
const count = `${i + 1}.`
|
|
275
|
+
let planMsg = `${count} Found ${transformsToRun.length} transforms in ${item.srcPath}`
|
|
276
|
+
planTotal = planTotal + transformsToRun.length
|
|
277
|
+
// console.log(`Found ${transformsToRun.length} transforms in ${item.srcPath}`)
|
|
278
|
+
transformsToRun.forEach((trn) => {
|
|
279
|
+
const line = trn.block.lines[0]
|
|
280
|
+
const location = getCodeLocation(item.srcPath, line)
|
|
281
|
+
const planData = ` - "${trn.transform}" at line ${line} → ${location}`
|
|
282
|
+
planMsg += `\n${planData}`
|
|
283
|
+
// console.log(` - "${trn.transform}" at line ${trn.block.lines[0]}`)
|
|
284
|
+
})
|
|
285
|
+
const newLine = plan.length !== i + 1 ? '\n' : ''
|
|
286
|
+
return `${planMsg}${newLine}`
|
|
287
|
+
}).filter(Boolean)
|
|
141
288
|
|
|
142
|
-
|
|
143
|
-
|
|
289
|
+
if (files.length) {
|
|
290
|
+
console.log(LINE)
|
|
291
|
+
info(`Markdown Magic updates`, '')
|
|
292
|
+
const total = planTotal + missingTotal
|
|
293
|
+
console.log(`Parsed files: ${files.length}`)
|
|
294
|
+
console.log(`Block Open: ${open}`)
|
|
295
|
+
console.log(`Block Close: ${close}`)
|
|
296
|
+
console.log(`Files w/ transforms: ${plan.length} / ${files.length}`)
|
|
297
|
+
console.log(`Total transforms: ${total}`)
|
|
298
|
+
console.log(`Valid transforms: ${planTotal} / ${total}`)
|
|
299
|
+
console.log(`Invalid transforms: ${missingTotal} / ${total}`)
|
|
300
|
+
console.log('Syntax:')
|
|
301
|
+
logCommentBlockSyntax({
|
|
302
|
+
syntax: syntax,
|
|
303
|
+
open,
|
|
304
|
+
close
|
|
305
|
+
})
|
|
306
|
+
console.log(LINE)
|
|
307
|
+
console.log(planOutput.join('\n'))
|
|
308
|
+
}
|
|
144
309
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
310
|
+
/* Execute updates based on plan */
|
|
311
|
+
if (!dryRun) {
|
|
312
|
+
const changed = plan.filter(({ isChanged }) => isChanged)
|
|
313
|
+
if (changed.length) {
|
|
314
|
+
console.log(LINE)
|
|
315
|
+
console.log()
|
|
316
|
+
const execute = changed.map(({ srcPath, outputPath, updatedContents, originalContents }, i) => {
|
|
317
|
+
// console.log(`${i + 1}. newPath`, newPath)
|
|
318
|
+
console.log(`- Update file ${outputPath}`)
|
|
319
|
+
return writeFile(outputPath, updatedContents)
|
|
320
|
+
})
|
|
321
|
+
|
|
322
|
+
await Promise.all(execute)
|
|
323
|
+
} else {
|
|
324
|
+
console.log(LINE)
|
|
325
|
+
console.log('No changes. Skipping file writes')
|
|
151
326
|
}
|
|
152
|
-
const [ match, leadingText, leadingSpace, comment, insideComment, trailingText, trailingNewLine ] = matches
|
|
153
|
-
/*
|
|
154
|
-
console.log('match', match)
|
|
155
|
-
console.log('leadingText', leadingText)
|
|
156
|
-
console.log('leadingSpace', leadingSpace)
|
|
157
|
-
console.log('comment', comment)
|
|
158
|
-
console.log('insideComment', insideComment)
|
|
159
|
-
console.log('trailingText', trailingText)
|
|
160
|
-
console.log('trailingNewLine', trailingNewLine)
|
|
161
|
-
/** */
|
|
162
|
-
const newLineCount = (trailingNewLine || '').length
|
|
163
|
-
const trailing = (!trailingText && newLineCount > 1) ? `${trailingNewLine || ''}` : ''
|
|
164
|
-
const leading = (leadingSpace) ? leadingSpace.slice(1) : ''
|
|
165
|
-
remove.push(`${leading}${comment}${trailing}`)
|
|
166
327
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
328
|
+
/*
|
|
329
|
+
TODO:
|
|
330
|
+
- Output to new file
|
|
331
|
+
- Clean up default transforms
|
|
332
|
+
- Expose md utils
|
|
333
|
+
*/
|
|
334
|
+
if (errors.length) {
|
|
335
|
+
logErrors(errors)
|
|
336
|
+
}
|
|
171
337
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const removeOpen = content.replace(openPattern, '')
|
|
181
|
-
// TODO this probably needs to be a loop for larger blocks
|
|
182
|
-
closePattern.lastIndex = 0; // reset regex
|
|
183
|
-
const hasClose = closePattern.exec(content)
|
|
184
|
-
// console.log('closePattern', closePattern)
|
|
185
|
-
// console.log('has', content)
|
|
186
|
-
// console.log('hasClose', hasClose)
|
|
187
|
-
if (!hasClose) {
|
|
188
|
-
return removeOpen
|
|
338
|
+
console.log(LINE)
|
|
339
|
+
success(`Markdown Magic Done`)
|
|
340
|
+
console.log(`${LINE}\n`)
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
errors,
|
|
344
|
+
changes: plan,
|
|
345
|
+
data: plan
|
|
189
346
|
}
|
|
190
|
-
const closeTag = `${hasClose[2]}${hasClose[3] || ''}`
|
|
191
|
-
// console.log('closeTag', closeTag)
|
|
192
|
-
return removeOpen
|
|
193
|
-
.replaceAll(closeTag, '')
|
|
194
|
-
/* Trailing new line */
|
|
195
|
-
.replace(/\n$/, '')
|
|
196
347
|
}
|
|
197
|
-
|
|
198
|
-
function
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
348
|
+
|
|
349
|
+
function logErrors(allErrors) {
|
|
350
|
+
const word = pluralize(allErrors, 'error', 'errors')
|
|
351
|
+
const title = `Markdown Magic ${word}: ${allErrors.length}`
|
|
352
|
+
console.log('\n──────────────────────────────')
|
|
353
|
+
error(title)
|
|
354
|
+
console.log('──────────────────────────────\n')
|
|
355
|
+
let msg = title
|
|
356
|
+
allErrors.forEach(({ errorMessage, errors }, i) => {
|
|
357
|
+
const finalMessage = `${i + 1}. ${errorMessage}`
|
|
358
|
+
msg += `\n${finalMessage}`
|
|
359
|
+
error(finalMessage, ``)
|
|
360
|
+
errors.forEach(({ message }, n) => {
|
|
361
|
+
const newLineX = errors.length !== n + 1 ? '' : '\n'
|
|
362
|
+
const lineMessage = ` - ${message}`
|
|
363
|
+
msg += `\n${lineMessage}`
|
|
364
|
+
console.log(`${lineMessage}${newLineX}`)
|
|
365
|
+
})
|
|
204
366
|
})
|
|
367
|
+
return msg
|
|
205
368
|
}
|
|
206
369
|
|
|
207
|
-
function
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
370
|
+
function logCommentBlockSyntax({
|
|
371
|
+
syntax,
|
|
372
|
+
open,
|
|
373
|
+
close
|
|
374
|
+
}) {
|
|
375
|
+
const syntaxDetails = getSyntaxInfo(syntax)
|
|
376
|
+
console.log(`
|
|
377
|
+
${syntaxDetails.tags[0]} ${open} transformName ${syntaxDetails.tags[1]}
|
|
378
|
+
generated content here
|
|
379
|
+
${syntaxDetails.tags[0]} ${close} ${syntaxDetails.tags[1]}
|
|
380
|
+
`)
|
|
215
381
|
}
|
|
216
382
|
|
|
217
383
|
module.exports = {
|
|
218
|
-
|
|
384
|
+
markdownMagic,
|
|
385
|
+
parseMarkdown,
|
|
386
|
+
processContents,
|
|
387
|
+
processFile
|
|
219
388
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const { test } = require('uvu')
|
|
2
|
+
const assert = require('uvu/assert')
|
|
3
|
+
const { markdownMagic, processContents, processFile } = require('./')
|
|
4
|
+
|
|
5
|
+
test('Main API', () => {
|
|
6
|
+
assert.equal(typeof markdownMagic, 'function')
|
|
7
|
+
assert.equal(typeof processContents, 'function')
|
|
8
|
+
assert.equal(typeof processFile, 'function')
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
test.run()
|