markdown-magic 2.6.1 → 3.0.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.
- package/README.md +6 -10
- package/cli.js +5 -82
- package/lib/block-parser-js.test.js +179 -0
- package/lib/block-parser.js +389 -0
- package/lib/{utils/new-parser.test.js → block-parser.test.js} +168 -50
- package/lib/cli.js +234 -0
- package/lib/cli.test.js +409 -0
- package/lib/defaults.js +12 -0
- package/lib/index.js +319 -184
- package/lib/index.test.js +11 -0
- package/lib/options-parser.js +498 -0
- package/lib/options-parser.test.js +1237 -0
- package/lib/process-contents.js +330 -0
- package/lib/process-file.js +34 -0
- package/lib/transforms/code.js +67 -22
- package/lib/transforms/file.js +13 -10
- package/lib/transforms/remote.js +9 -6
- package/lib/transforms/toc.js +136 -64
- package/lib/transforms/wordCount.js +5 -0
- package/lib/utils/fs.js +340 -0
- package/lib/utils/fs.test.js +268 -0
- package/lib/utils/html-to-json/compat.js +42 -0
- package/lib/utils/html-to-json/format.js +64 -0
- package/lib/utils/html-to-json/index.js +37 -0
- package/lib/utils/html-to-json/lexer.js +345 -0
- package/lib/utils/html-to-json/parser.js +146 -0
- package/lib/utils/html-to-json/stringify.js +37 -0
- package/lib/utils/html-to-json/tags.js +171 -0
- package/lib/utils/index.js +19 -0
- package/{cli-utils.js → lib/utils/load-config.js} +2 -6
- package/lib/utils/logs.js +89 -0
- package/lib/utils/md/filters.js +20 -0
- package/lib/utils/md/find-code-blocks.js +80 -0
- package/lib/utils/md/find-date.js +32 -0
- package/lib/utils/md/find-frontmatter.js +94 -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.js +102 -0
- package/lib/utils/md/find-links.js +202 -0
- package/lib/utils/md/find-unmatched-html-tags.js +33 -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 +143 -0
- package/lib/utils/md/md.test.js +37 -0
- package/lib/utils/md/parse.js +122 -0
- package/lib/utils/md/utils.js +19 -0
- package/lib/utils/regex-timeout.js +83 -0
- package/lib/utils/regex.js +38 -5
- package/lib/utils/remoteRequest.js +54 -0
- package/lib/utils/syntax.js +79 -0
- package/lib/utils/text.js +260 -0
- package/lib/utils/text.test.js +311 -0
- package/package.json +25 -25
- package/index.js +0 -46
- package/lib/processFile.js +0 -154
- package/lib/transforms/index.js +0 -114
- 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/weird-parse.js +0 -230
- package/lib/utils/weird-parse.test.js +0 -217
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// https://stackoverflow.com/questions/38859506/cancel-regex-match-if-timeout
|
|
2
|
+
const util = require('util')
|
|
3
|
+
const vm = require('vm')
|
|
4
|
+
const { getBlockRegex } = require('../block-parser')
|
|
5
|
+
const { getSyntaxInfo } = require('./syntax')
|
|
6
|
+
|
|
7
|
+
const goodString = `
|
|
8
|
+
# Test Fixture
|
|
9
|
+
|
|
10
|
+
This is normal text in markdown. <!-- doc-start (wordCount) -->x<!-- doc-end -->
|
|
11
|
+
Keep it.
|
|
12
|
+
|
|
13
|
+
<!-- doc-start (wordCount) -->
|
|
14
|
+
THIS CONTENT GETS AUTO GENERATED. Don't directly edit it
|
|
15
|
+
<!-- doc-end -->
|
|
16
|
+
|
|
17
|
+
This is normal text in markdown. Keep it.
|
|
18
|
+
`
|
|
19
|
+
|
|
20
|
+
const badString = `
|
|
21
|
+
# Test Fixture
|
|
22
|
+
|
|
23
|
+
This is normal text in markdown. <!-- doc-start (wordCount) -->x<!-- oc-end -->
|
|
24
|
+
Keep it.
|
|
25
|
+
|
|
26
|
+
<!-- doc-start (wordCount) -->
|
|
27
|
+
THIS CONTENT GETS AUTO GENERATED. Don't directly edit it
|
|
28
|
+
<!-- xoc-end -->
|
|
29
|
+
|
|
30
|
+
This is normal text in markdown. Keep it.
|
|
31
|
+
`
|
|
32
|
+
|
|
33
|
+
// var pattern = /([ \t]*)(?:<!-{2,}(?:.*|\r?|\n?|\s*)docs-start\s*([(\[\{]*[A-Za-z0-9_$-]*[)\]\}]*)\s*)((?:.*?|.*?\r?\n?)*?)<!-{2,}(?:.*|\r?|\n?|\s*)docs-end(?:.|\r?\n)*?-{2,}>/gim
|
|
34
|
+
|
|
35
|
+
function safeRegex(str) {
|
|
36
|
+
const syntaxInfo = getSyntaxInfo('md')
|
|
37
|
+
if (!syntaxInfo.pattern) {
|
|
38
|
+
throw new Error(`Unknown syntax "${syntax}"`)
|
|
39
|
+
}
|
|
40
|
+
const [ openComment, closeComment ] = syntaxInfo.pattern
|
|
41
|
+
const pattern = getBlockRegex({
|
|
42
|
+
openComment,
|
|
43
|
+
closeComment,
|
|
44
|
+
openText: 'doc-start',
|
|
45
|
+
closeText: 'doc-end'
|
|
46
|
+
})
|
|
47
|
+
console.log('Pattern', pattern)
|
|
48
|
+
const sandbox = {
|
|
49
|
+
// regex: /([ \t]*)(?:<!-{2,}(?:.*|\r?|\n?|\s*)docs-start\s*([(\[\{]*[A-Za-z0-9_$-]*[)\]\}]*)\s*)((?:.*?|.*?\r?\n?)*?)<!-{2,}(?:.*|\r?|\n?|\s*)docs-end(?:.|\r?\n)*?-{2,}>/gim,
|
|
50
|
+
regexToUse: pattern,
|
|
51
|
+
string: str,
|
|
52
|
+
//string: badStringTwo,
|
|
53
|
+
//string: string,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const context = vm.createContext(sandbox)
|
|
57
|
+
console.log('Sandbox initialized: ' + vm.isContext(sandbox))
|
|
58
|
+
// var script = new vm.Script('result = regex.exec(string)');
|
|
59
|
+
const script = new vm.Script(`
|
|
60
|
+
blocks = []
|
|
61
|
+
rawMatches = string.match(regexToUse)
|
|
62
|
+
while ((list = regexToUse.exec(string)) !== null) {
|
|
63
|
+
const [ block, spaces, __type, params ] = list
|
|
64
|
+
blocks.push({
|
|
65
|
+
__type,
|
|
66
|
+
block
|
|
67
|
+
})
|
|
68
|
+
if (list.index === regexToUse.lastIndex) regexToUse.lastIndex++
|
|
69
|
+
}
|
|
70
|
+
`);
|
|
71
|
+
try {
|
|
72
|
+
// One could argue if a RegExp hasn't processed in a given time.
|
|
73
|
+
// then, its likely it will take exponential time.
|
|
74
|
+
script.runInContext(context, { timeout: 1000 }); // milliseconds
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.log('ReDos occurred', e); // Take some remedial action here...
|
|
77
|
+
}
|
|
78
|
+
console.log('result:')
|
|
79
|
+
console.log(util.inspect(sandbox)); // Check the results
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// safeRegex(goodString)
|
|
83
|
+
safeRegex(badString)
|
package/lib/utils/regex.js
CHANGED
|
@@ -1,19 +1,34 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
2
|
+
// REGEX to look for regex
|
|
3
|
+
// https://github.com/kgryte/regex-regex/blob/master/lib/index.js
|
|
4
|
+
const REGEX_REGEX = /^\/((?:\\\/|[^\/])+)\/([imgy]*)$/
|
|
5
|
+
|
|
6
|
+
function escapeRegexString(string) {
|
|
7
|
+
if (typeof string !== 'string') {
|
|
8
|
+
throw new TypeError('Expected a string')
|
|
9
|
+
}
|
|
10
|
+
// Escape characters with special meaning either inside or outside character sets.
|
|
11
|
+
// Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
|
|
12
|
+
return string
|
|
13
|
+
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
|
|
14
|
+
.replace(/-/g, '\\x2d');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function matchCommentBlock(word) {
|
|
3
18
|
//return new RegExp(`(?:\\<\\!--(?:.|\\r?\\n)*?${matchWord}:START(?:.|\\r?\\n)*?\\()(.*)\\)(?:.|\\r?\\n)*?<!--(?:.|\\r?\\n)*?${matchWord}:END(?:.|\\r?\\n)*?--\\>`, 'g')
|
|
4
19
|
return new RegExp(`(.*)(?:\\<\\!--(?:.*|\r?|\n?|\s*)${word}:START(?:.|\\r?\\n)*?\\()(.*)\\)(?:.|\\r?\\n)*?<!--(?:.*|\r?|\n?|\s*)${word}:END(?:.|\\r?\\n)*?--\\>`, 'g')
|
|
5
20
|
}
|
|
6
21
|
|
|
7
|
-
|
|
22
|
+
function matchOpeningCommentTag(word) {
|
|
8
23
|
// return new RegExp(`(\\<\\!--(?:.|\\r?\\n)*?${matchWord}:START)((?:.|\\r?\\n)*?--\\>)`, 'g')
|
|
9
24
|
return new RegExp(`(\\<\\!--(?:.*|\r?|\n?|\s*)${word}:START)((?:.|\\r?\\n)*?--\\>)`, 'g')
|
|
10
25
|
}
|
|
11
26
|
|
|
12
|
-
|
|
27
|
+
function matchClosingCommentTag(word) {
|
|
13
28
|
return new RegExp(`--\\>(?:.|\\r?\\n)*?((?:\\<\\!--(?:.*|\\r?\\n)(?:.*|\\r?\\n))*?${word}:END)((?:.|\\r?\\n)*?--\\>)`, 'g')
|
|
14
29
|
}
|
|
15
30
|
|
|
16
|
-
|
|
31
|
+
const removeLeadingAndTrailingLineBreaks = /^(?:[\t ]*(?:\r?\n|\r))+|\s+$/g
|
|
17
32
|
|
|
18
33
|
const jsRegex = /\/\* Step([\s\S]*?)\*\//g
|
|
19
34
|
const ymlRegex = / *?# Step([\s\S]*?) #\n*?/g
|
|
@@ -56,6 +71,15 @@ function getSteps() {
|
|
|
56
71
|
})
|
|
57
72
|
}
|
|
58
73
|
|
|
74
|
+
/*
|
|
75
|
+
Alt attribute regex https://regex101.com/r/Ughcb7/1
|
|
76
|
+
const attrNameRegex = "[a-z0-9_]+";
|
|
77
|
+
const attrValueRegex = '(\\\\"|[^"])*';
|
|
78
|
+
const attrRegex = `(${attrNameRegex})\\s*=\\s*"(${attrValueRegex})"`;
|
|
79
|
+
const keyValue = new RegExp(attrRegex, "gi");
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
|
|
59
83
|
// Regex to remove all comment blocks
|
|
60
84
|
const REMOVE_COMMENTS_REGEX = / *?\<\!-- ([\s\S]*?) ?--\>\n\n*?/g
|
|
61
85
|
// content.replace(removeComments, '')
|
|
@@ -73,4 +97,13 @@ const TABEL_ROW_REGEX = /^\s*\|.*?\|\s*$/
|
|
|
73
97
|
* @param {string} text The text to validate.
|
|
74
98
|
* @returns {boolean}
|
|
75
99
|
*/
|
|
76
|
-
const isTableRow = (text) => text.match(TABEL_ROW_REGEX);
|
|
100
|
+
const isTableRow = (text) => text.match(TABEL_ROW_REGEX);
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
REGEX_REGEX,
|
|
104
|
+
escapeRegexString,
|
|
105
|
+
matchCommentBlock,
|
|
106
|
+
matchOpeningCommentTag,
|
|
107
|
+
matchClosingCommentTag,
|
|
108
|
+
removeLeadingAndTrailingLineBreaks,
|
|
109
|
+
}
|
|
@@ -11,3 +11,57 @@ module.exports = function remoteRequest(url) {
|
|
|
11
11
|
}
|
|
12
12
|
return body
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
TODO add file caching?
|
|
17
|
+
*/
|
|
18
|
+
// const path = require('path')
|
|
19
|
+
// const cacheManager = require('cache-manager')
|
|
20
|
+
// const fsStoreHash = require('cache-manager-fs-hash')
|
|
21
|
+
// const CACHE_KEY = 'foo'
|
|
22
|
+
// const STORAGE_PATH = (process.env.IS_OFFLINE) ? path.join(__dirname, '../tmp') : '/tmp'
|
|
23
|
+
// const SECONDS = 60
|
|
24
|
+
// const MINUTES = 60
|
|
25
|
+
// const ONE_HOUR = SECONDS * MINUTES
|
|
26
|
+
// const mbOfStorage = 512
|
|
27
|
+
// /* initialize caching on disk */
|
|
28
|
+
// const diskCache = cacheManager.caching({
|
|
29
|
+
// store: fsStoreHash,
|
|
30
|
+
// options: {
|
|
31
|
+
// /* TTL in seconds */
|
|
32
|
+
// ttl: ONE_HOUR,
|
|
33
|
+
// /* max size in bytes on disk */
|
|
34
|
+
// // maxsize: mbOfStorage * 1000 * 1000,
|
|
35
|
+
// path: STORAGE_PATH,
|
|
36
|
+
// }
|
|
37
|
+
// })
|
|
38
|
+
|
|
39
|
+
// async function usage() {
|
|
40
|
+
// const hasCache = await diskCache.get(CACHE_KEY)
|
|
41
|
+
// if (hasCache && hasCache.length) {
|
|
42
|
+
// /* If cache NOT empty return it */
|
|
43
|
+
// // console.log('Using cached value', hasCache)
|
|
44
|
+
// return hasCache
|
|
45
|
+
// }
|
|
46
|
+
// // else do fetch
|
|
47
|
+
// const data = await getStuff()
|
|
48
|
+
// // Then save cache
|
|
49
|
+
// console.log('Saving value')
|
|
50
|
+
// await diskCache.set(CACHE_KEY, data)
|
|
51
|
+
// }
|
|
52
|
+
|
|
53
|
+
// function getCacheSize(filePath) {
|
|
54
|
+
// return new Promise((resolve, reject) => {
|
|
55
|
+
// fs.stat(filePath, (err, stats) => {
|
|
56
|
+
// if (err) {
|
|
57
|
+
// return resolve({ sizeInBytes: 0, sizeInMB: 0 })
|
|
58
|
+
// }
|
|
59
|
+
// const byteSize = stats.size
|
|
60
|
+
// const megaByteSize = byteSize / (1024 * 1024)
|
|
61
|
+
// return resolve({
|
|
62
|
+
// sizeInBytes: byteSize,
|
|
63
|
+
// sizeInMB: megaByteSize
|
|
64
|
+
// })
|
|
65
|
+
// })
|
|
66
|
+
// })
|
|
67
|
+
// }
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const html = {
|
|
2
|
+
tags: [
|
|
3
|
+
'<!--',
|
|
4
|
+
'-->'
|
|
5
|
+
],
|
|
6
|
+
pattern: [
|
|
7
|
+
'<!-{2,}',
|
|
8
|
+
'-{2,}>' // '-->'
|
|
9
|
+
],
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Kramdown https://github.com/HHS/nih-oite-website/blob/480244abfd0f0d741b27d6232273dd03073e06ad/app/javascript/kramdown/parser.js#L12-L48
|
|
13
|
+
|
|
14
|
+
// JS https://regex101.com/r/XKHU18/5
|
|
15
|
+
const js = {
|
|
16
|
+
tags: ['/*', '*/'],
|
|
17
|
+
pattern: [
|
|
18
|
+
'\/\\*+',
|
|
19
|
+
// Old ^ '\/\\*{1,}[\n\\*]*', // '\/\\*+', '\/\*[\*\n\s\t]+', //
|
|
20
|
+
'\\*+/'
|
|
21
|
+
],
|
|
22
|
+
/* Match single line JS comment */
|
|
23
|
+
singleLineTag: '//',
|
|
24
|
+
singleLinePattern: '//+',
|
|
25
|
+
singleLine: '\/\/.*$'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const jsx = {
|
|
29
|
+
tags: [
|
|
30
|
+
'{/*',
|
|
31
|
+
'*/}'
|
|
32
|
+
],
|
|
33
|
+
pattern: [
|
|
34
|
+
'\{\/\\*+',
|
|
35
|
+
'\\*+/\}'
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const yaml = {
|
|
40
|
+
tags: ['##', '##'],
|
|
41
|
+
pattern: [
|
|
42
|
+
'##+',
|
|
43
|
+
'##+'
|
|
44
|
+
],
|
|
45
|
+
singleLineTag: '#',
|
|
46
|
+
singleLinePattern: '#+',
|
|
47
|
+
singleLine: '#.*$',
|
|
48
|
+
content: '[ \\t\\S]*?',
|
|
49
|
+
converter: (str) => {
|
|
50
|
+
return str.split('\n').map((line) => {
|
|
51
|
+
return line[0] === '#' ? line : `#${line}`
|
|
52
|
+
}).join()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const syntaxMap = {
|
|
57
|
+
// <!-- x -->
|
|
58
|
+
md: html,
|
|
59
|
+
markdown: html,
|
|
60
|
+
// <!-- x -->
|
|
61
|
+
html: html,
|
|
62
|
+
// /* x */
|
|
63
|
+
js: js,
|
|
64
|
+
// {/* x */}
|
|
65
|
+
jsx: jsx,
|
|
66
|
+
mdx: jsx,
|
|
67
|
+
// ## x ##
|
|
68
|
+
yaml: yaml,
|
|
69
|
+
yml: yaml
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function getSyntaxInfo(syntax = '') {
|
|
73
|
+
return syntaxMap[syntax.toLowerCase()] || {}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
getSyntaxInfo,
|
|
78
|
+
syntaxMap
|
|
79
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
const { syntaxMap } = require('./syntax')
|
|
2
|
+
|
|
3
|
+
function getLines(str = '') {
|
|
4
|
+
return str.split(/\r\n|\r|\n/)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function getLineCount(str = '') {
|
|
8
|
+
return getLines(str).length
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function getRowAndColumnFromCharPos(input, indexToFind) {
|
|
12
|
+
const preChunk = input.substr(0, indexToFind);
|
|
13
|
+
const row = preChunk.split('\n').length - 1
|
|
14
|
+
const lastIndexOfNewLine = input.lastIndexOf('\n', indexToFind);
|
|
15
|
+
const col = lastIndexOfNewLine > 0 ? indexToFind - lastIndexOfNewLine - 1 : indexToFind;
|
|
16
|
+
return { row, col }
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function getWordCount(str = '') {
|
|
20
|
+
return str.trim().split(/\s+/).length
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getFirstCharacter(str) {
|
|
24
|
+
return str.charAt(0)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getLastCharacter(str) {
|
|
28
|
+
return str.substr(-1)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getLeadingSpaces(text) {
|
|
32
|
+
const matches = text.match(/^\s*/)
|
|
33
|
+
return (matches && matches[0]) ? matches[0] : ''
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getTextBetweenChars(text, start, end) {
|
|
37
|
+
return text.slice(start, end)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function replaceTextBetweenChars(str = '', start, end, newStr) {
|
|
41
|
+
return str.substring(0, start) + newStr + str.substring(end)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getTextBetweenLines(content, startLine, endLine) {
|
|
45
|
+
const startDefined = typeof startLine !== 'undefined'
|
|
46
|
+
const endDefined = typeof endLine !== 'undefined'
|
|
47
|
+
if (!startDefined && !endDefined) return
|
|
48
|
+
|
|
49
|
+
const lines = getLines(content)
|
|
50
|
+
if (startDefined && !endDefined) {
|
|
51
|
+
return lines.slice(startLine - 1, startLine).join('')
|
|
52
|
+
}
|
|
53
|
+
if ((startLine) && (endLine) && parseInt(startLine, 10) <= parseInt(endLine, 10)) {
|
|
54
|
+
return lines.slice(startLine - 1, endLine).join('\n')
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isUpperCase(str) {
|
|
59
|
+
return str === str.toUpperCase()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// https://github.com/jamiebuilds/min-indent/blob/master/index.js
|
|
63
|
+
function findMinIndent(string) {
|
|
64
|
+
const match = string.match(/^[ \t]*(?=\S)/gm)
|
|
65
|
+
if (!match) return 0
|
|
66
|
+
return match.reduce((r, a) => Math.min(r, a.length), Infinity)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function stripIndent(string, indentation) {
|
|
70
|
+
const indent = typeof indentation !== 'undefined' ? indentation : findMinIndent(string);
|
|
71
|
+
if (indent === 0) {
|
|
72
|
+
return string
|
|
73
|
+
}
|
|
74
|
+
const regex = new RegExp(`^[ \\t]{${indent}}`, 'gm')
|
|
75
|
+
return string.replace(regex, '')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Trim leading & trailing spaces/line breaks in code and keeps the indentation of the first non-empty line
|
|
80
|
+
* @param {string} str
|
|
81
|
+
* @returns string
|
|
82
|
+
*/
|
|
83
|
+
function trimString(str = '') {
|
|
84
|
+
let content = (typeof str === 'number') ? str.toString() : str
|
|
85
|
+
// console.log('content', `"${content}"`)
|
|
86
|
+
return content.replace(/^(?:[\t ]*(?:\r?\n|\r))+|\s+$/g, '')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function indentString(string, count = 1, options = {}) {
|
|
90
|
+
const {
|
|
91
|
+
indent = ' ',
|
|
92
|
+
includeEmptyLines = false
|
|
93
|
+
} = options;
|
|
94
|
+
if (count === 0) return string
|
|
95
|
+
const regex = includeEmptyLines ? /^/gm : /^(?!\s*$)/gm
|
|
96
|
+
return string.replace(regex, indent.repeat(count))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Removes the indentation of multiline strings
|
|
101
|
+
* @link https://github.com/victornpb/tiny-dedent/
|
|
102
|
+
* @param {string} str A template literal string
|
|
103
|
+
* @return {string} A string without the indentation
|
|
104
|
+
*/
|
|
105
|
+
function dedentString(str) {
|
|
106
|
+
str = str.replace(/^[ \t]*\r?\n/, ''); // remove leading blank line
|
|
107
|
+
var indent = /^[ \t]+/m.exec(str); // detected indent
|
|
108
|
+
if (indent) str = str.replace(new RegExp('^' + indent[0], 'gm'), ''); // remove indent
|
|
109
|
+
return str.replace(/(\r?\n)[ \t]+$/, '$1'); // remove trailling blank line
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Strip out comment blocks
|
|
114
|
+
* @param {string} str
|
|
115
|
+
* @param {'md' | 'js'} syntax
|
|
116
|
+
* @returns {string} clean commentless string
|
|
117
|
+
*/
|
|
118
|
+
function stripCommentBlockOld(str, syntax = 'md') {
|
|
119
|
+
const [ openPattern, closePattern ] = syntaxMap[syntax].pattern
|
|
120
|
+
const pattern = new RegExp(`^([ \\S]*)${openPattern}(\\s?[\\s\\S]*?)?${closePattern}\n?`, 'gim')
|
|
121
|
+
// console.log('pattern', pattern)
|
|
122
|
+
let newString = str
|
|
123
|
+
let matches
|
|
124
|
+
while ((matches = pattern.exec(str)) !== null) {
|
|
125
|
+
if (matches.index === pattern.lastIndex) {
|
|
126
|
+
pattern.lastIndex++ // avoid infinite loops with zero-width matches
|
|
127
|
+
}
|
|
128
|
+
const [ _match, leadingText ] = matches
|
|
129
|
+
/*
|
|
130
|
+
console.log('_match', _match)
|
|
131
|
+
console.log('leadingText', `"${leadingText}"`)
|
|
132
|
+
console.log('───────────────────────')
|
|
133
|
+
/**/
|
|
134
|
+
/* Handle comments that start midway through line after text */
|
|
135
|
+
if (leadingText) {
|
|
136
|
+
/* Trim trailing tabs/spaces */
|
|
137
|
+
const trimmed = leadingText.replace(/([ \t]*)$/, '')
|
|
138
|
+
const replacement = _match.replace(trimmed, '')
|
|
139
|
+
// console.log('replacement', `"${replacement}"`)
|
|
140
|
+
newString = newString.replace(replacement, `\n`)
|
|
141
|
+
// console.log('new str', newString)
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// const pattern = new RegExp(`([ \\t]*)${openPattern}\\s?([\\s\\S]*?)?${closePattern}\n?`, 'gi')
|
|
146
|
+
return newString.replace(pattern, '')
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Strip out comment blocks
|
|
151
|
+
* @param {string} str
|
|
152
|
+
* @param {'md' | 'js'} syntax
|
|
153
|
+
* @returns {string} clean commentless string
|
|
154
|
+
*/
|
|
155
|
+
function stripComments(str, { syntax = 'md' }) {
|
|
156
|
+
const syntaxData = syntaxMap[syntax]
|
|
157
|
+
const [ openPattern, closePattern ] = syntaxData.pattern
|
|
158
|
+
const OR = (syntaxData.singleLine) ? `|\\s?[ \\t]*${syntaxData.singleLine}` : ''
|
|
159
|
+
const CONTENT = syntaxData.content || '[\\s\\S]*?'
|
|
160
|
+
const pattern = new RegExp(`\\s?[ \\t]*${openPattern}(${CONTENT})?${closePattern}${OR}`, 'gim')
|
|
161
|
+
console.log('pattern', pattern)
|
|
162
|
+
return str.replace(pattern, '')
|
|
163
|
+
// https://regex101.com/r/XKHU18/5
|
|
164
|
+
return str.replace(/\s?[ \t]*\/\*[\s\S]*?\*\/|\s?[ \t]*\/\/.*$|\/\*{1,}[\n\*]*(\s?[\s\S]*?)?\*+\//gm, '')
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// @TODO export as util to import into CODE
|
|
168
|
+
function stripAllComments(block) {
|
|
169
|
+
// ([^\s]*)?([ \t]*)?(\/\*{1,}[\n\*]*(\s?[\s\S]*?)?\*\/)([^\s<]*)?(\n{1,2})?
|
|
170
|
+
// https://regex101.com/r/WSioZ7/1
|
|
171
|
+
const pattern = new RegExp(`([^\\s]*)?([ \\t]*)?(<!-{2,}(\\s?[\\s\\S]*?)?-{2,}>)([^\\s<]*)?(\n{1,2})?`, 'gi')
|
|
172
|
+
// ALT https://regex101.com/r/hxppia/1
|
|
173
|
+
// Alt HTML comments https://regex101.com/r/EJyioz/1
|
|
174
|
+
|
|
175
|
+
// console.log('closeTagRegex', closeTagRegex)
|
|
176
|
+
let matches
|
|
177
|
+
let remove = []
|
|
178
|
+
while ((matches = pattern.exec(block)) !== null) {
|
|
179
|
+
if (matches.index === pattern.lastIndex) {
|
|
180
|
+
pattern.lastIndex++ // avoid infinite loops with zero-width matches
|
|
181
|
+
}
|
|
182
|
+
const [ match, leadingText, leadingSpace, comment, insideComment, trailingText, trailingNewLine ] = matches
|
|
183
|
+
/*
|
|
184
|
+
console.log('match', match)
|
|
185
|
+
console.log('leadingText', leadingText)
|
|
186
|
+
console.log('leadingSpace', leadingSpace)
|
|
187
|
+
console.log('comment', comment)
|
|
188
|
+
console.log('insideComment', insideComment)
|
|
189
|
+
console.log('trailingText', trailingText)
|
|
190
|
+
console.log('trailingNewLine', trailingNewLine)
|
|
191
|
+
/** */
|
|
192
|
+
const newLineCount = (trailingNewLine || '').length
|
|
193
|
+
const trailing = (!trailingText && newLineCount > 1) ? `${trailingNewLine || ''}` : ''
|
|
194
|
+
const leading = (leadingSpace) ? leadingSpace.slice(1) : ''
|
|
195
|
+
remove.push(`${leading}${comment}${trailing}`)
|
|
196
|
+
}
|
|
197
|
+
return remove.reduce((acc, curr) => {
|
|
198
|
+
return acc.replaceAll(curr, '')
|
|
199
|
+
}, block)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function convertCommentSyntax(str, { from, to }) {
|
|
203
|
+
const syntaxData = syntaxMap[from]
|
|
204
|
+
const [ openPattern, closePattern ] = syntaxData.pattern
|
|
205
|
+
const [ openTag, closeTag ] = syntaxMap[to].tags
|
|
206
|
+
// const match = ` *?\\${openPattern}([\\s\\S]*?)?${closePattern}\\n\\n*?`
|
|
207
|
+
const UseLeadingLine = ''// || '|\\s?[ \\t]*'
|
|
208
|
+
const OR = (syntaxData.singleLine) ? `|${UseLeadingLine}${syntaxData.singleLine}` : ''
|
|
209
|
+
const CONTENT = syntaxData.content || '[\\s\\S]*?'
|
|
210
|
+
const match = `${UseLeadingLine}${openPattern}(${CONTENT})?${closePattern}${OR}`
|
|
211
|
+
// const match = `${openPattern}(.*|\\r?|\\n?|\\s*)*${closePattern}`
|
|
212
|
+
const regexToUse = new RegExp(match, 'gm')
|
|
213
|
+
// console.log('regexToUse', regexToUse)
|
|
214
|
+
const found = str.match(regexToUse)
|
|
215
|
+
// console.log('found', found)
|
|
216
|
+
if (!found) {
|
|
217
|
+
return str
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const pattern = syntaxData.singleLinePattern ? new RegExp(syntaxData.singleLinePattern) : new RegExp(openPattern)
|
|
221
|
+
// console.log('pattern', pattern)
|
|
222
|
+
for (let index = 0; index < found.length; index++) {
|
|
223
|
+
const comment = found[index]
|
|
224
|
+
const cleanComment = comment.replace(pattern, '')
|
|
225
|
+
/*
|
|
226
|
+
console.log('comment', comment)
|
|
227
|
+
console.log('cleanComment', cleanComment)
|
|
228
|
+
/** */
|
|
229
|
+
str = str.replace(comment, `${openTag}${cleanComment} ${closeTag}`)
|
|
230
|
+
}
|
|
231
|
+
return str
|
|
232
|
+
|
|
233
|
+
const newComment = found[0].replace(regexToUse, `${openTag}$1${closeTag}`)
|
|
234
|
+
const converter = syntaxMap[to].converter
|
|
235
|
+
const newText = (converter) ? converter(newComment) : newComment
|
|
236
|
+
return str.replace(regexToUse, newText)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.exports = {
|
|
240
|
+
getLines,
|
|
241
|
+
getLineCount,
|
|
242
|
+
getWordCount,
|
|
243
|
+
getLeadingSpaces,
|
|
244
|
+
getFirstCharacter,
|
|
245
|
+
getLastCharacter,
|
|
246
|
+
getRowAndColumnFromCharPos,
|
|
247
|
+
getTextBetweenChars,
|
|
248
|
+
getTextBetweenLines,
|
|
249
|
+
replaceTextBetweenChars,
|
|
250
|
+
stripIndent,
|
|
251
|
+
indentString,
|
|
252
|
+
dedentString,
|
|
253
|
+
stripComments,
|
|
254
|
+
convertCommentSyntax,
|
|
255
|
+
// stripCommentBlockJS,
|
|
256
|
+
trimString,
|
|
257
|
+
// future https://github.com/junfengliang/autowrap
|
|
258
|
+
findMinIndent,
|
|
259
|
+
isUpperCase
|
|
260
|
+
}
|