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.
Files changed (58) hide show
  1. package/README.md +47 -37
  2. package/cli.js +5 -82
  3. package/lib/block-parser-js.test.js +171 -0
  4. package/lib/block-parser.js +382 -0
  5. package/lib/block-parser.test.js +479 -0
  6. package/lib/cli.js +245 -0
  7. package/lib/cli.test.js +409 -0
  8. package/lib/defaults.js +12 -0
  9. package/lib/globals.d.ts +66 -0
  10. package/lib/index.js +353 -184
  11. package/lib/index.test.js +11 -0
  12. package/lib/process-contents.js +371 -0
  13. package/lib/process-file.js +37 -0
  14. package/lib/transforms/code.js +67 -28
  15. package/lib/transforms/file.js +17 -17
  16. package/lib/transforms/index.js +0 -114
  17. package/lib/transforms/remote.js +8 -6
  18. package/lib/transforms/sectionToc.js +18 -0
  19. package/lib/transforms/toc.js +12 -265
  20. package/lib/transforms/wordCount.js +5 -0
  21. package/lib/types.js +11 -0
  22. package/lib/utils/fs.js +342 -0
  23. package/lib/utils/fs.test.js +267 -0
  24. package/lib/utils/index.js +19 -0
  25. package/{cli-utils.js → lib/utils/load-config.js} +2 -6
  26. package/lib/utils/logs.js +94 -0
  27. package/lib/utils/md/filters.js +20 -0
  28. package/lib/utils/md/find-code-blocks.js +88 -0
  29. package/lib/utils/md/find-date.js +32 -0
  30. package/lib/utils/md/find-frontmatter.js +92 -0
  31. package/lib/utils/md/find-frontmatter.test.js +17 -0
  32. package/lib/utils/md/find-html-tags.js +105 -0
  33. package/lib/utils/md/find-images-md.js +27 -0
  34. package/lib/utils/md/find-images.js +107 -0
  35. package/lib/utils/md/find-links.js +220 -0
  36. package/lib/utils/md/find-unmatched-html-tags.js +32 -0
  37. package/lib/utils/md/fixtures/2022-01-22-date-in-filename.md +14 -0
  38. package/lib/utils/md/fixtures/file-with-frontmatter.md +32 -0
  39. package/lib/utils/md/fixtures/file-with-links.md +153 -0
  40. package/lib/utils/md/md.test.js +105 -0
  41. package/lib/utils/md/parse.js +146 -0
  42. package/lib/utils/md/utils.js +19 -0
  43. package/lib/utils/regex-timeout.js +84 -0
  44. package/lib/utils/regex.js +40 -6
  45. package/lib/utils/remoteRequest.js +55 -0
  46. package/lib/utils/syntax.js +82 -0
  47. package/lib/utils/text.js +328 -0
  48. package/lib/utils/text.test.js +305 -0
  49. package/lib/utils/toc.js +315 -0
  50. package/package.json +30 -26
  51. package/index.js +0 -46
  52. package/lib/processFile.js +0 -154
  53. package/lib/updateContents.js +0 -125
  54. package/lib/utils/_md.test.js +0 -63
  55. package/lib/utils/new-parser.js +0 -412
  56. package/lib/utils/new-parser.test.js +0 -324
  57. package/lib/utils/weird-parse.js +0 -230
  58. package/lib/utils/weird-parse.test.js +0 -217
@@ -1,15 +1,17 @@
1
- const regexUtils = require('../utils/regex')
2
1
  const remoteRequest = require('../utils/remoteRequest')
3
2
 
4
- module.exports = function REMOTE(content, options, config) {
5
- const remoteContent = remoteRequest(options.url) || content
3
+ module.exports = function REMOTE(api) {
4
+ // console.log('REMOTE api', api)
5
+ const { options, content, settings } = api
6
+ const { regex } = settings
7
+ // console.log('MAKE REMOTE REQUEST')
8
+ const remoteContent = remoteRequest(options.url)
6
9
  if (!remoteContent) {
7
10
  return content
8
11
  }
9
12
  if (options.keepComments) {
10
13
  return remoteContent
11
14
  }
12
- const openTagRegex = regexUtils.matchOpeningCommentTag(config.matchWord)
13
- const closeTagRegex = regexUtils.matchClosingCommentTag(config.matchWord)
14
- return remoteContent.replace(openTagRegex, '').replace(closeTagRegex, '')
15
+ // console.log('REMOTE', remoteContent)
16
+ return remoteContent.replace(regex.open, '').replace(regex.close, '')
15
17
  }
@@ -0,0 +1,18 @@
1
+ const { generateToc } = require('../utils/toc')
2
+
3
+ module.exports = async function sectionToc(api) {
4
+ // console.log("sectionToc", api)
5
+ const { options, fileContent, srcPath, getBlockDetails } = api
6
+ const opts = options || {}
7
+ const subToc = await generateToc({
8
+ options: {
9
+ ...opts,
10
+ // Set sub table of contents
11
+ sub: true
12
+ },
13
+ fileContent,
14
+ srcPath,
15
+ getBlockDetails: getBlockDetails
16
+ })
17
+ return subToc
18
+ }
@@ -1,266 +1,13 @@
1
- const { transform } = require('@technote-space/doctoc')
2
- const { removeLeadingAndTrailingLineBreaks } = require('../utils/regex')
3
-
4
- module.exports = async function TOC(content, options, config) {
5
- const opts = options || {}
6
- opts.firsth1 = (opts.firsth1) ? true : false
7
- let contents = config.outputContent
8
- // console.log('contents', contents)
9
-
10
- let debugFileMatch
11
- // console.log('config', config.originalPath)
12
- // debugFileMatch = config.originalPath.match(/packages\/analytics\/README\.md/)
13
-
14
- // https://www.npmjs.com/package/@technote-space/toc-generator
15
- const t = await transform(contents, {
16
- // mode: 'github.com', // github.com | bitbucket.org | gitlab.com | nodejs.org | ghost.org (default: github.com)
17
- isNotitle: true,
18
- //isCustomMode: true,
19
- openingComment: '',
20
- closingComment: '',
21
- maxHeaderLevel: (opts.maxDepth) ? Number(opts.maxDepth) : 4
22
- // maxHeaderLevel: 2, // default: 4
23
- // title: '**Table of Contents**',
24
- // isNotitle: true,
25
- // isFolding: true,
26
- // entryPrefix: '*',
27
- // processAll: true,
28
- // updateOnly: true,
29
- // openingComment: '<!-- toc -->',
30
- // closingComment: '<!-- tocstop --> ',
31
- // checkOpeningComments: ['<!-- toc '],
32
- // checkClosingComments: ['<!-- tocstop '],
33
- // isCustomMode: false,
34
- // customTemplate: '<p align="center">${ITEMS}</p>',
35
- // itemTemplate: '<a href="${LINK}">${TEXT}</a>',
36
- // separator: '<span>|</span>',
37
- // footer: '',
1
+ const { generateToc } = require('../utils/toc')
2
+
3
+ module.exports = async function TOC(api) {
4
+ // console.log("TOC API", api)
5
+ const { options, fileContent, srcPath, getBlockDetails } = api
6
+ const toc = await generateToc({
7
+ options: options || {},
8
+ fileContent,
9
+ srcPath,
10
+ getBlockDetails: getBlockDetails
38
11
  })
39
- let output = t.wrappedToc || ''
40
-
41
- if (debugFileMatch) {
42
- console.log('before firsth1 removal', output)
43
- }
44
-
45
- /* remove first h1 */
46
- if (!opts.firsth1) {
47
- // console.log('output', output)
48
- const lines = output.split('\n')
49
- let firstH1
50
- let firstLine
51
- const countOfH1s = lines.reduce((acc, line, index) => {
52
- if (line !== '' && !firstLine) {
53
- firstLine = index
54
- }
55
- if (line.match(/^-\s+/)) {
56
- if (!firstH1) {
57
- const rawText = line.match(/\[(.*)\]/)[1]
58
- firstH1 = [line, index, firstLine === index, rawText]
59
- }
60
- acc = acc + 1
61
- }
62
- return acc
63
- }, 0)
64
-
65
- const firstHeadingData = (firstH1 && Array.isArray(firstH1)) ? firstH1 : []
66
- const [ lineText, lineIndex, isFirst, matchText ] = firstHeadingData
67
-
68
- // verify its h1
69
- const matchTextEscaped = escapeStringRegexp(matchText)
70
- // console.log('matchTextEscaped', matchTextEscaped)
71
- // /^#{1}\s+(.*)/
72
- const FIRST_H1_REGEX = new RegExp(`^#\\s*\\[?${matchTextEscaped}\\]?(?:.*)?`, 'gim')
73
- // /^<h1\b[^>]*>([\s\S]*?)<\/h1>/
74
- const FIRST_HTML_H1_REGEX = new RegExp(`^<h1\\b[^>]*>[\\s]*?(${matchTextEscaped})[\\s]*?<\\/h1>`, 'gim')
75
- // /^(.*)\n={3,}/
76
- const FIRST_UNDERSCORE_H1 = new RegExp(`^(${matchTextEscaped})\n={3,}`, 'gim')
77
-
78
- let docHasHeading = false
79
- if (contents.match(FIRST_H1_REGEX)) {
80
- docHasHeading = matchText
81
- } else if (contents.match(FIRST_HTML_H1_REGEX)) {
82
- docHasHeading = matchText
83
- } else if (contents.match(FIRST_UNDERSCORE_H1)) {
84
- docHasHeading = matchText
85
- }
86
-
87
- if (debugFileMatch) {
88
- console.log('matchText', matchText)
89
- if (docHasHeading) {
90
- console.log('Found heading 1', docHasHeading)
91
- }
92
- }
93
-
94
- if (debugFileMatch) {
95
- console.log('top level toc item count', countOfH1s)
96
- if (docHasHeading) {
97
- console.log('Found heading 1', docHasHeading)
98
- console.log('firstH1', firstH1)
99
- }
100
- }
101
-
102
- let firstItemWithContent
103
- let foundFirstH1
104
-
105
- if (docHasHeading) {
106
- output = lines.reduce((acc, line, i) => {
107
- const isLineEmpty = line === ''
108
- if (!isLineEmpty && !firstItemWithContent) {
109
- firstItemWithContent = i
110
- }
111
- if (!foundFirstH1 && (firstItemWithContent === i) && line.match(/^-\s+/)) {
112
- foundFirstH1 = true
113
- return acc
114
- }
115
- // Add back line and remove level
116
- let newLineValue = line
117
- if (lineText) {
118
- // const untilFirstH1 = i < lineIndex
119
- /* @TODO make option? flatten all non first h1 tags */
120
- if (countOfH1s > 0 && !isLineEmpty && newLineValue.match(/^\s+-/)) {
121
- newLineValue = line.substring(2)
122
- }
123
- }
124
-
125
- acc = acc.concat(newLineValue)
126
- return acc
127
- }, []).join('\n')
128
- }
129
-
130
- // console.log('output', output)
131
- if (debugFileMatch) {
132
- console.log('after firsth1 removal', output)
133
- }
134
- }
135
- // console.log(t)
136
- // Fix <h1> with multiple lines
137
- const spaces = output.match(/\[\n([\s\S]*?)\]/gm)
138
- if (spaces) {
139
- const fixed = spaces[0]
140
- // all new lines
141
- .replace(/\n/g, '')
142
- // leading spaces
143
- .replace(/\[\s+/, '[')
144
- .trim()
145
- output = output.replace(spaces[0], fixed)
146
- }
147
- // console.log(output)
148
- output = output
149
- .replace(/(.*)\[Table of Contents\]\(.*\)\n?/i, '')
150
- .replace(/(.*)\[toc\]\(.*\)\n?/i, '')
151
-
152
-
153
- if (opts.excludeText) {
154
- // (\s+)?-(.*)\[Usage\]\(.*\)
155
- const regex = new RegExp(`\(\\s+\)?-(.*)\\[${opts.excludeText}\\]\\(.*\\)`, 'i')
156
- // /(\s+)?-(.*)\[Usage\]\(.*\)(\n\s+(.*))+/im
157
- const nestedRegex = new RegExp(`\(\\s+\)?-(.*)\\[${opts.excludeText}\\]\\(.*\\)\(\\n\\s+\(.*\)\)+`, 'i')
158
-
159
- const hasNested = nestedRegex.exec(output)
160
- if (hasNested) {
161
- // Count indentation of spaces
162
- const numberOfSpaces = hasNested[1].replace(/\n/g, '').length
163
- const subItems = numberOfSpaces + 1
164
- // Update regex to only remove sub items
165
- const nestedRegexSpaces = new RegExp(`\(\\s+\)?-(.*)\\[${opts.excludeText}\\]\\(.*\\)\(\\n\\s{${subItems},}\(.*\)\)+`, 'i')
166
- // console.log('nestedRegexSpaces', nestedRegexSpaces)
167
- // If exclude value has nested sections remove them as well.
168
- output = output.replace(nestedRegexSpaces, '')
169
- output = output.replace(regex, '')
170
- } else {
171
- output = output.replace(regex, '')
172
- }
173
- }
174
-
175
- // If collapse wrap in <details>
176
- if (opts.collapse) {
177
- const text = (opts.collapseText) ? opts.collapseText : 'Table of Contents'
178
- return `<details>
179
- <summary>${text}</summary>
180
- ${output
181
- // Replace leading double spaces
182
- .replace(/^\n\n/, '\n')
183
- // Replace trailing double spaces
184
- .replace(/\n\n$/, '\n')}
185
- </details>`
186
- }
187
-
188
- return output.replace(removeLeadingAndTrailingLineBreaks, '')
189
- }
190
-
191
- const HTML_TAG = /<([a-zA-Z1-6]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)/gim
192
-
193
- function parseHtmlProps(mdContents) {
194
- const htmlTags = mdContents
195
- /* Fix non terminating <tags> */
196
- .replace(/(['"`]<(.*)>['"`])/gm, '_$2_')
197
- .match(HTML_TAG)
198
- //console.log('htmlTags', htmlTags)
199
-
200
- let tags = []
201
- if (htmlTags) {
202
- let propsValues = {}
203
- var regexSingleTag = /<([a-zA-Z1-6]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)/
204
- for (var i = 0; i < htmlTags.length; i++) {
205
- var tagMatches = regexSingleTag.exec(htmlTags[i])
206
- // console.log('tagMatches', tagMatches)
207
- var [ match, tag, props ] = tagMatches
208
- // console.log(`Tag #${i} ${tag}`)
209
- if (props) {
210
- const cleanProps = props
211
- // Remove new lines and tabs
212
- .replace(/\n\t/g, '')
213
- // Remove extra spaces
214
- .replace(/\s\s+/g, ' ')
215
- .trim()
216
-
217
- propsValues = cleanProps.split(" ").reduce((acc, curr) => {
218
- const hasQuotes = curr.match(/=['"]/)
219
- // Check key="value" | key='value' | key={value}
220
- const propWithValue = /([A-Za-z-_$]+)=['{"](.*)['}"]/g.exec(curr)
221
- if (propWithValue) {
222
- return {
223
- ...acc,
224
- [`${propWithValue[1]}`]: (hasQuotes) ? propWithValue[2] : convert(propWithValue[2])
225
- }
226
- }
227
- // Check isLoading boolean props
228
- const booleanProp = curr.match(/([A-Za-z]*)/)
229
- if (booleanProp) {
230
- return {
231
- ...acc,
232
- [`${booleanProp[1]}`]: true
233
- }
234
- }
235
- return acc
236
- }, {})
237
- }
238
-
239
- tags.push({
240
- tag: tag,
241
- props: propsValues,
242
- raw: match
243
- })
244
- }
245
- }
246
- return tags
247
- }
248
-
249
- function escapeStringRegexp(string) {
250
- if (typeof string !== 'string') {
251
- throw new TypeError('Expected a string');
252
- }
253
-
254
- // Escape characters with special meaning either inside or outside character sets.
255
- // 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.
256
- return string
257
- .replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
258
- .replace(/-/g, '\\x2d');
259
- }
260
-
261
- function removeUndefined(output) {
262
- // remove undefined from new line and start of string if first H1 is missing
263
- return output.replace(/\nundefined/g, '\n-').replace(/^undefined/g, '-')
264
- }
265
-
266
- // Alt https://github.com/thlorenz/doctoc
12
+ return toc
13
+ }
@@ -0,0 +1,5 @@
1
+ const { getWordCount } = require('../utils/text')
2
+
3
+ module.exports = function wordCount({ fileContent }) {
4
+ return getWordCount(fileContent)
5
+ }
package/lib/types.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Allowed file syntaxes
3
+ * @typedef {'md' | 'js' | 'yml' | 'yaml'} SyntaxType
4
+ */
5
+
6
+ /** @type {SyntaxType} */
7
+ const syntaxType = 'md'
8
+
9
+ module.exports = {
10
+ syntaxType
11
+ }
@@ -0,0 +1,342 @@
1
+ const fs = require('fs').promises
2
+ const path = require('path')
3
+ const globrex = require('globrex')
4
+ const isGlob = require('is-glob')
5
+ const isLocalPath = require('is-local-path')
6
+ const { REGEX_REGEX, escapeRegexString } = require('./regex')
7
+ const { dirname, resolve, join } = require('path')
8
+ const { readdir, stat, readFile } = fs
9
+
10
+ const IS_HIDDEN_FILE = /(^|[\\\/])\.[^\\\/\.]/g
11
+
12
+ function isRegex(thing) {
13
+ return (thing instanceof RegExp)
14
+ }
15
+
16
+ async function writeFile(filePath, content) {
17
+ try {
18
+ await fs.writeFile(filePath, content)
19
+ } catch(e) {
20
+ const dirName = path.dirname(filePath)
21
+ await fs.mkdir(dirName, { recursive: true })
22
+ await fs.writeFile(filePath, content)
23
+ }
24
+ }
25
+
26
+ async function findUp(start, fileName) {
27
+ const file = await escalade(start, (dir, relativePaths) => {
28
+ // console.log('~> dir:', dir);
29
+ // console.log('~> relativePaths:', relativePaths);
30
+ // console.log('---')
31
+ if (typeof fileName === 'string' && relativePaths.includes(fileName)) {
32
+ // will be resolved into absolute
33
+ return fileName
34
+ }
35
+ if (fileName instanceof RegExp) {
36
+ const found = relativePaths.find((relativePath) => relativePath.match(fileName))
37
+ if (found) return found
38
+ }
39
+ })
40
+ return file
41
+ }
42
+
43
+ // https://github.com/lukeed/escalade
44
+ async function escalade(start, callback) {
45
+ let dir = resolve('.', start)
46
+ let tmp, stats = await stat(dir)
47
+
48
+ if (!stats.isDirectory()) {
49
+ dir = dirname(dir)
50
+ }
51
+
52
+ while (true) {
53
+ tmp = await callback(dir, await readdir(dir))
54
+ if (tmp) return resolve(dir, tmp)
55
+ dir = dirname(tmp = dir)
56
+ if (tmp === dir) break;
57
+ }
58
+ }
59
+
60
+ // https://github.com/lukeed/totalist
61
+ async function totalist(dir, callback, pre='') {
62
+ dir = resolve('.', dir)
63
+ await readdir(dir).then(arr => {
64
+ return Promise.all(arr.map((str) => {
65
+ let abs = join(dir, str)
66
+ return stat(abs).then(stats => {
67
+ return stats.isDirectory() ? totalist(abs, callback, join(pre, str)) : callback(join(pre, str), abs, stats)
68
+ })
69
+ }))
70
+ })
71
+ }
72
+
73
+ function combineRegexes(patterns = []) {
74
+ const string = patterns.map((pat) => {
75
+ if (isRegex(pat)) {
76
+ return pat.source
77
+ } else if (typeof pat === 'string' && REGEX_REGEX.test(pat)) {
78
+ const regexInfo = pat.match(REGEX_REGEX)
79
+ console.log('regexInfo', regexInfo)
80
+ if (regexInfo && regexInfo[1]) {
81
+ // escapeRegexString
82
+ return regexInfo[1]
83
+ }
84
+ } else if (isGlob(pat)) {
85
+ console.log('pat', pat)
86
+ const result = globrex(pat, { globstar: true, extended: true })
87
+ console.log('result', result)
88
+ return result.regex.source
89
+ }
90
+ return pat
91
+ }).join('|')
92
+ console.log('xxxstring', string)
93
+ return new RegExp(string)
94
+ }
95
+
96
+ // alt https://github.com/duniul/clean-modules/blob/33b66bcfb7825e1fa1eb1e296e523ddba374f1ae/src/utils/filesystem.ts#L92
97
+ // Alt https://github.com/AvianFlu/ncp
98
+ async function getFilePaths(dirName, {
99
+ patterns = [],
100
+ ignore = [],
101
+ excludeGitIgnore = false,
102
+ excludeHidden = false
103
+ }) {
104
+ let findPattern
105
+ let ignorePattern
106
+ let filePaths = []
107
+ let gitIgnoreFiles = []
108
+ let gitIgnoreGlobs = []
109
+
110
+ if (patterns && patterns.length) {
111
+ findPattern = combineRegexes(patterns)
112
+ console.log('findPatternfindPatternfindPattern', patterns)
113
+ }
114
+ if (ignore && ignore.length) {
115
+ ignorePattern = combineRegexes(ignore)
116
+ }
117
+
118
+ if (excludeGitIgnore) {
119
+ const gitIgnoreContents = await getGitignoreContents()
120
+ for (let index = 0; index < gitIgnoreContents.length; index++) {
121
+ const ignoreItem = gitIgnoreContents[index]
122
+ // console.log('ignoreItem', ignoreItem)
123
+ if (isGlob(ignoreItem)) {
124
+ gitIgnoreGlobs.push(ignoreItem)
125
+ } else {
126
+ gitIgnoreFiles.push(
127
+ ignoreItem.replace(/^\.\//, '') // normalize relative paths
128
+ )
129
+ }
130
+ }
131
+ }
132
+
133
+ //*
134
+ console.log('findPattern', findPattern)
135
+ console.log('ignorePattern', ignorePattern)
136
+ console.log('gitIgnoreFiles', gitIgnoreFiles)
137
+ console.log('gitIgnoreGlobs', gitIgnoreGlobs)
138
+ // process.exit(1)
139
+ /** */
140
+
141
+ await totalist(dirName, (relativePath, abs, stats) => {
142
+ const absolutePath = `${dirName}/${relativePath}`
143
+ const topLevelDir = relativePath.substring(0, relativePath.indexOf('/'))
144
+ //console.log('absolutePath', absolutePath)
145
+ // console.log('relativePath', relativePath)
146
+ // console.log('topLevelDir', topLevelDir)
147
+
148
+ /* Remove hidden files */
149
+ if (excludeHidden && IS_HIDDEN_FILE.test(relativePath)) {
150
+ return
151
+ }
152
+
153
+ /* Remove files in git ignore */
154
+ if (excludeGitIgnore && gitIgnoreFiles.length) {
155
+ if (gitIgnoreFiles.includes(relativePath)) return
156
+ if (gitIgnoreFiles.includes(path.basename(relativePath))) return
157
+ //* // slow
158
+ if (gitIgnoreFiles.some((ignore) => {
159
+ // console.log('ignore', ignore)
160
+ // return relativePath.indexOf(ignore) > -1
161
+ // return relativePath.split('/')[0] === ignore
162
+ return topLevelDir === ignore || relativePath === ignore
163
+ })) {
164
+ return
165
+ }
166
+ /** */
167
+ }
168
+
169
+ /* Remove files in ignore array */
170
+ if (ignorePattern && ignorePattern.test(relativePath)) {
171
+ // Alt checker https://github.com/axtgr/wildcard-match
172
+ return
173
+ }
174
+
175
+ /* If no patterns supplied add all files */
176
+ if (!findPattern) {
177
+ filePaths.push(absolutePath)
178
+ return
179
+ }
180
+
181
+ /* If pattern match add file! */
182
+ // Alt match https://github.com/micromatch/picomatch
183
+ if (findPattern.test(absolutePath)) {
184
+ // console.log('Match absolutePath', absolutePath)
185
+ filePaths.push(absolutePath)
186
+ return
187
+ }
188
+
189
+ /* If pattern match add file! */
190
+ if (findPattern.test(relativePath)) {
191
+ // console.log('Match relativePath', relativePath)
192
+ filePaths.push(absolutePath)
193
+ return
194
+ }
195
+
196
+ /*
197
+ let ignored = false
198
+ for (let index = 0; index < ignore.length; index++) {
199
+ const pattern = ignore[index]
200
+ if (pattern.test(absolutePath)) {
201
+ ignored = true
202
+ }
203
+ }
204
+ if (!ignored) {
205
+ filePaths.push(absolutePath)
206
+ }
207
+ /** */
208
+ })
209
+
210
+ if (gitIgnoreGlobs && gitIgnoreGlobs.length) {
211
+ console.log('gitIgnoreGlobs', gitIgnoreGlobs)
212
+ let removeFiles = []
213
+ for (let index = 0; index < gitIgnoreGlobs.length; index++) {
214
+ const glob = gitIgnoreGlobs[index]
215
+ const result = globrex(glob) // alt lib https://github.com/axtgr/wildcard-match
216
+ // console.log('result', result)
217
+ for (let n = 0; n < filePaths.length; n++) {
218
+ const file = filePaths[n]
219
+ if (result.regex.test(file)) {
220
+ removeFiles.push(file)
221
+ }
222
+ }
223
+ }
224
+ /* Remove files that match glob pattern */
225
+ if (removeFiles.length) {
226
+ filePaths = filePaths.filter(function(el) {
227
+ return removeFiles.indexOf(el) < 0
228
+ })
229
+ }
230
+ }
231
+
232
+ return filePaths
233
+ }
234
+
235
+ function convertToRelativePath(file, cwd) {
236
+ return file.replace(cwd, '').replace(/^\//, '')
237
+ }
238
+
239
+ async function getGitignoreContents(filePath = '.gitignore') {
240
+ try {
241
+ const gitIgnoreContent = await readFile(filePath, { encoding: 'utf8' })
242
+ return gitIgnoreContent
243
+ .split(/\r?\n/)
244
+ .filter((line) => !/^\s*$/.test(line) && !/^\s*#/.test(line))
245
+ .map((line) => line.trim().replace(/^\/+|\/+$/g, ''))
246
+ } catch (_a) {
247
+ return []
248
+ }
249
+ }
250
+
251
+ // slash at the beginning of a filename
252
+ const leadingPathSeparator = new RegExp(`^${escapeRegexString(path.sep)}`)
253
+ const windowsLeadingPathSeparator = new RegExp('^/')
254
+
255
+ // all slashes in the filename. path.sep is OS agnostic (windows, mac, etc)
256
+ const pathSeparator = new RegExp(escapeRegexString(path.sep), 'g')
257
+ const windowsPathSeparator = new RegExp('/', 'g')
258
+
259
+ // handle MS Windows style double-backslashed filenames
260
+ const windowsDoubleSlashSeparator = new RegExp('\\\\', 'g')
261
+
262
+ // derive `foo.bar.baz` object key from `foo/bar/baz.yml` filename
263
+ function fileNameToKey(filename) {
264
+ // const extension = new RegExp(`${path.extname(filename)}$`)
265
+ const key = filename
266
+ // .replace(extension, '')
267
+ .replace(leadingPathSeparator, '')
268
+ .replace(windowsLeadingPathSeparator, '')
269
+ .replace(pathSeparator, '.')
270
+ .replace(windowsPathSeparator, '.')
271
+ .replace(windowsDoubleSlashSeparator, '.')
272
+
273
+ return key
274
+ }
275
+
276
+ // https://github.com/regexhq/unc-path-regex/blob/master/index.js
277
+ function isUncPath(filepath) {
278
+ return /^[\\\/]{2,}[^\\\/]+[\\\/]+[^\\\/]+/.test(filepath)
279
+ }
280
+ function isRelative(filepath) {
281
+ const isRel = !isUncPath(filepath) && !/^([a-z]:)?[\\\/]/i.test(filepath)
282
+ // console.log(`isRel ${filepath}`, isRel)
283
+ return isRel
284
+ }
285
+ /* Find common parts of 2 paths */
286
+ function resolveCommonParent(mainDir = '', fileDir = '') {
287
+ const parts = mainDir.split('/')
288
+ let acc = ''
289
+ let value = ''
290
+ for (let i = 0; i < parts.length; i++) {
291
+ const element = parts[i];
292
+ acc+= ((i) ? '/' : '') + element
293
+ if (fileDir.startsWith(acc)) {
294
+ value = acc
295
+ }
296
+ }
297
+ return value
298
+ }
299
+
300
+ function resolveOutputPath(cwd, outputDir, file) {
301
+ // console.log('file', file)
302
+ const fileCommon = resolveCommonParent(cwd, file)
303
+ // console.log('fileCommon', fileCommon)
304
+ const remove = resolveCommonParent(outputDir, file)
305
+ const fileName = file.replace(remove, '').replace(fileCommon, '')
306
+ let outputFilePath = path.join(outputDir, fileName)
307
+ if (isRelative(outputDir)) {
308
+ outputFilePath = path.join(cwd, outputDir, fileName)
309
+ }
310
+ // console.log('isRelative(outputDir)', isRelative(outputDir))
311
+ // console.log('outputDir', outputDir)
312
+ // console.log('fileName', fileName)
313
+ // console.log('remove', remove)
314
+ return outputFilePath
315
+ }
316
+
317
+ function resolveFlatPath(cwd, outputDir, file) {
318
+ /* old setup */
319
+ const fileName = path.basename(file)
320
+ let outputFilePath = path.join(outputDir, fileName)
321
+ if (isRelative(outputDir)) {
322
+ outputFilePath = path.join(cwd, outputDir, fileName)
323
+ }
324
+ return outputFilePath
325
+ }
326
+
327
+ function depth(string) {
328
+ return path.normalize(string).split(path.sep).length - 1;
329
+ }
330
+
331
+ module.exports = {
332
+ isLocalPath,
333
+ writeFile,
334
+ readFile,
335
+ findUp,
336
+ getFilePaths,
337
+ resolveOutputPath,
338
+ resolveFlatPath,
339
+ resolveCommonParent,
340
+ getGitignoreContents,
341
+ convertToRelativePath
342
+ }