markdown-magic 3.0.0 → 3.0.2

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 (49) hide show
  1. package/README.md +43 -29
  2. package/lib/block-parser-js.test.js +148 -156
  3. package/lib/block-parser.js +255 -262
  4. package/lib/block-parser.test.js +43 -6
  5. package/lib/cli.js +30 -19
  6. package/lib/cli.test.js +73 -73
  7. package/lib/globals.d.ts +66 -0
  8. package/lib/index.js +43 -9
  9. package/lib/process-contents.js +80 -39
  10. package/lib/process-file.js +4 -1
  11. package/lib/transforms/code.js +4 -10
  12. package/lib/transforms/file.js +7 -10
  13. package/lib/transforms/index.js +0 -0
  14. package/lib/transforms/remote.js +2 -3
  15. package/lib/transforms/sectionToc.js +18 -0
  16. package/lib/transforms/toc.js +10 -335
  17. package/lib/types.js +11 -0
  18. package/lib/utils/fs.js +21 -19
  19. package/lib/utils/fs.test.js +4 -5
  20. package/lib/utils/logs.js +7 -2
  21. package/lib/utils/md/filters.js +5 -5
  22. package/lib/utils/md/find-code-blocks.js +16 -8
  23. package/lib/utils/md/find-frontmatter.js +11 -13
  24. package/lib/utils/md/find-frontmatter.test.js +2 -2
  25. package/lib/utils/md/find-html-tags.js +1 -1
  26. package/lib/utils/md/find-images-md.js +27 -0
  27. package/lib/utils/md/find-images.js +39 -34
  28. package/lib/utils/md/find-links.js +72 -54
  29. package/lib/utils/md/find-unmatched-html-tags.js +1 -2
  30. package/lib/utils/md/fixtures/file-with-links.md +10 -0
  31. package/lib/utils/md/md.test.js +72 -4
  32. package/lib/utils/md/parse.js +91 -67
  33. package/lib/utils/regex-timeout.js +2 -1
  34. package/lib/utils/regex.js +3 -2
  35. package/lib/utils/remoteRequest.js +1 -0
  36. package/lib/utils/syntax.js +3 -0
  37. package/lib/utils/text.js +71 -3
  38. package/lib/utils/text.test.js +3 -9
  39. package/lib/utils/toc.js +315 -0
  40. package/package.json +7 -3
  41. package/lib/options-parser.js +0 -498
  42. package/lib/options-parser.test.js +0 -1237
  43. package/lib/utils/html-to-json/compat.js +0 -42
  44. package/lib/utils/html-to-json/format.js +0 -64
  45. package/lib/utils/html-to-json/index.js +0 -37
  46. package/lib/utils/html-to-json/lexer.js +0 -345
  47. package/lib/utils/html-to-json/parser.js +0 -146
  48. package/lib/utils/html-to-json/stringify.js +0 -37
  49. package/lib/utils/html-to-json/tags.js +0 -171
@@ -23,6 +23,13 @@ const { OPEN_WORD, CLOSE_WORD } = require('./defaults')
23
23
  debug = false,
24
24
  } = config
25
25
 
26
+ /*
27
+ console.log('OPEN_WORD', open)
28
+ console.log('CLOSE_WORD', close)
29
+ console.log('syntax', syntax)
30
+ // console.log('text', text)
31
+ /** */
32
+
26
33
  let foundBlocks = {}
27
34
  try {
28
35
  foundBlocks = parseBlocks(text, {
@@ -86,9 +93,9 @@ const { OPEN_WORD, CLOSE_WORD } = require('./defaults')
86
93
  /* Run transform plugins */
87
94
  let tempContent = content.value
88
95
  // console.log('transform', transform)
89
- const currentTransform = getTransform(transform, transforms)
96
+ const currentTransformFn = getTransform(transform, transforms)
90
97
  /* Run each transform */
91
- if (currentTransform) {
98
+ if (currentTransformFn) {
92
99
  // console.log('context', context)
93
100
  let returnedContent
94
101
  /* DISABLED legacy syntax */
@@ -97,11 +104,11 @@ const { OPEN_WORD, CLOSE_WORD } = require('./defaults')
97
104
  console.log(`CALL legacy ${transform}`, srcPath)
98
105
  // backward compat maybe
99
106
  // CODE(content, options, config)
100
- returnedContent = await currentTransform(content.value, options, {
107
+ returnedContent = await currentTransformFn(content.value, options, {
101
108
  originalPath: srcPath
102
109
  })
103
110
  } else {
104
- returnedContent = await currentTransform(transformApi({
111
+ returnedContent = await currentTransformFn(transformApi({
105
112
  srcPath,
106
113
  ...match,
107
114
  regex: regexInfo,
@@ -111,13 +118,15 @@ const { OPEN_WORD, CLOSE_WORD } = require('./defaults')
111
118
  }
112
119
  /** */
113
120
 
114
- returnedContent = await currentTransform(transformApi({
115
- srcPath,
116
- ...match,
117
- regex: regexInfo,
118
- originalContents: text,
119
- currentContents: md,
120
- }, config))
121
+ returnedContent = await currentTransformFn(
122
+ transformApi({
123
+ srcPath,
124
+ ...match,
125
+ regex: regexInfo,
126
+ originalContents: text,
127
+ currentContents: md,
128
+ }, config)
129
+ )
121
130
 
122
131
  /* Run each transform */
123
132
  // console.log('config', config)
@@ -143,7 +152,7 @@ const { OPEN_WORD, CLOSE_WORD } = require('./defaults')
143
152
  console.log('afterContent', afterContent)
144
153
  }
145
154
 
146
- if (!currentTransform) {
155
+ if (!currentTransformFn) {
147
156
  missingTransforms.push(afterContent)
148
157
  // console.log(`Missing "${transform}" transform`)
149
158
  }
@@ -211,48 +220,74 @@ const { OPEN_WORD, CLOSE_WORD } = require('./defaults')
211
220
  function transformApi(stuff, opts) {
212
221
  const { transforms, srcPath, outputPath, ...rest } = opts
213
222
  return {
214
- srcPath: stuff.srcPath,
215
- outputPath: outputPath,
216
223
  transform: stuff.transform,
224
+ content: stuff.content.value,
217
225
  options: stuff.options || {},
218
- blockContent: stuff.content.value,
219
- fileContent: stuff.currentContents,
220
- originalFileContent: stuff.originalContents,
226
+ srcPath: stuff.srcPath,
227
+ outputPath: outputPath,
221
228
  settings: {
222
229
  ...rest,
223
230
  regex: stuff.regex,
224
231
  },
232
+
233
+ // blockContent: stuff.content.value,
234
+ fileContent: stuff.currentContents,
235
+ originalFileContent: stuff.originalContents,
236
+ /* Methods */
225
237
  getOriginalContent: () => stuff.originalContents,
226
238
  getOriginalBlock: () => stuff,
227
- getCurrentBlock: () => {
239
+ getBlockDetails: (content) => {
228
240
  /* Re-parse current file for updated positions */
229
- const updatedBlocks = parseBlocks(stuff.currentContents, {
230
- syntax: opts.syntax,
231
- open: opts.open,
232
- close: opts.close,
233
- })
234
-
235
-
236
- const matchingBlocks = updatedBlocks.blocks.filter((block) => {
237
- return block.open.value === stuff.open.value
241
+ return getDetails({
242
+ contents: content || stuff.currentContents,
243
+ openValue: stuff.open.value,
244
+ srcPath: stuff.srcPath,
245
+ index: stuff.index,
246
+ opts: opts
238
247
  })
248
+ },
249
+ // getOriginalBlockDetails: () => {
250
+ // return getDetails({
251
+ // contents: stuff.originalContents,
252
+ // openValue: stuff.open.value,
253
+ // srcPath: stuff.srcPath,
254
+ // index: stuff.index,
255
+ // opts: opts
256
+ // })
257
+ // },
258
+ }
259
+ }
239
260
 
240
- if (!matchingBlocks.length) {
241
- return {}
242
- }
243
- let foundBlock = matchingBlocks[0]
261
+ function getDetails({
262
+ contents,
263
+ openValue,
264
+ srcPath,
265
+ index,
266
+ opts
267
+ }) {
268
+ /* Re-parse current file for updated positions */
269
+ const blockData = parseBlocks(contents, opts)
270
+
271
+ const matchingBlocks = blockData.blocks.filter((block) => {
272
+ return block.open.value === openValue
273
+ })
244
274
 
245
- if (matchingBlocks.length > 1) {
246
- foundBlock = matchingBlocks.filter((block) => {
247
- return block.index === stuff.index
248
- })[0]
249
- }
275
+ if (!matchingBlocks.length) {
276
+ return {}
277
+ }
250
278
 
251
- const location = getCodeLocation(stuff.srcPath, foundBlock.block.lines[0])
279
+ let foundBlock = matchingBlocks[0]
280
+ if (matchingBlocks.length > 1 && index) {
281
+ foundBlock = matchingBlocks.filter((block) => {
282
+ return block.index === index
283
+ })[0]
284
+ }
252
285
 
253
- return [ foundBlock, location ]
254
- },
286
+ if (srcPath) {
287
+ const location = getCodeLocation(srcPath, foundBlock.block.lines[0])
288
+ foundBlock.sourceLocation = location
255
289
  }
290
+ return foundBlock
256
291
  }
257
292
 
258
293
  /**
@@ -299,6 +334,12 @@ function applyMiddleware(data, md, middlewares) {
299
334
  }, Promise.resolve(data))
300
335
  }
301
336
 
337
+ /**
338
+ * Get Transform function
339
+ * @param {string} name - transform name
340
+ * @param {object} transforms - transform fns
341
+ * @returns {function}
342
+ */
302
343
  function getTransform(name, transforms = {}) {
303
344
  return transforms[name] || transforms[name.toLowerCase()]
304
345
  }
@@ -2,11 +2,14 @@ const path = require('path')
2
2
  const isValidFile = require('is-valid-path')
3
3
  const { readFile } = require('./utils/fs')
4
4
  const { processContents } = require('./process-contents')
5
+ // const { OPEN_WORD, CLOSE_WORD } = require('./defaults')
5
6
 
6
7
  async function processFile(opts = {}) {
7
8
  const { content, syntax } = opts
8
9
  let srcPath = opts.srcPath
9
- if (srcPath && content) throw new Error(`Can't set both "srcPath" & "content"`)
10
+ if (srcPath && content) {
11
+ throw new Error(`Can't set both "srcPath" & "content"`)
12
+ }
10
13
  let fileContents
11
14
  if (content) {
12
15
  const isFile = isValidFile(content)
@@ -11,11 +11,12 @@ const { getLineCount, getTextBetweenLines } = require('../utils/text')
11
11
  // usage https://github.com/linear/linear/blame/93981d3a3db571e2f8efdce9f5271ea678941c43/packages/sdk/README.md#L1
12
12
 
13
13
  module.exports = function CODE(api) {
14
- const { options = {}, blockContent, srcPath } = api
14
+ const { content, options, srcPath } = api
15
15
  // console.log('CODE API', api)
16
+ // process.exit(1)
16
17
  // console.log('options', options)
17
18
  const { src, lines } = options
18
- const originalContent = blockContent
19
+ const originalContent = content
19
20
  let code
20
21
  let syntax = options.syntax
21
22
  if (!src) {
@@ -27,14 +28,7 @@ module.exports = function CODE(api) {
27
28
  const fileDir = (srcPath) ? path.dirname(srcPath) : process.cwd()
28
29
  codeFilePath = path.resolve(fileDir, src)
29
30
  try {
30
- code = fs.readFileSync(codeFilePath, 'utf8', (err, contents) => {
31
- if (err) {
32
- console.log(`FILE NOT FOUND ${codeFilePath}`)
33
- console.log(err)
34
- // throw err
35
- }
36
- return contents
37
- })
31
+ code = fs.readFileSync(codeFilePath, 'utf8')
38
32
  } catch (e) {
39
33
  console.log(`FILE NOT FOUND ${codeFilePath}`)
40
34
  throw e
@@ -3,24 +3,21 @@ const fs = require('fs')
3
3
  const isLocalPath = require('is-local-path')
4
4
 
5
5
  module.exports = function FILE(api) {
6
+ /*
7
+ console.log('FILE API', api)
8
+ console.log(api.getBlockDetails())
9
+ process.exit(1)
10
+ /** */
6
11
  const { options, srcPath } = api
7
- // console.log('FILE API', api)
8
- let fileContents
9
12
  if (!options.src) {
10
13
  return false
11
14
  }
15
+ let fileContents = ''
12
16
  if (isLocalPath(options.src)) {
13
17
  const fileDir = path.dirname(srcPath)
14
18
  const resolvedFilePath = path.resolve(fileDir, options.src)
15
19
  try {
16
- fileContents = fs.readFileSync(resolvedFilePath, 'utf8', (err, contents) => {
17
- if (err) {
18
- console.log(`FILE NOT FOUND ${resolvedFilePath}`)
19
- console.log(err)
20
- // throw err
21
- }
22
- return contents
23
- })
20
+ fileContents = fs.readFileSync(resolvedFilePath, 'utf8')
24
21
  } catch (e) {
25
22
  console.log(`FILE NOT FOUND ${resolvedFilePath}`)
26
23
  throw e
File without changes
@@ -1,14 +1,13 @@
1
- const regexUtils = require('../utils/regex')
2
1
  const remoteRequest = require('../utils/remoteRequest')
3
2
 
4
3
  module.exports = function REMOTE(api) {
5
4
  // console.log('REMOTE api', api)
6
- const { options, blockContent, settings } = api
5
+ const { options, content, settings } = api
7
6
  const { regex } = settings
8
7
  // console.log('MAKE REMOTE REQUEST')
9
8
  const remoteContent = remoteRequest(options.url)
10
9
  if (!remoteContent) {
11
- return blockContent
10
+ return content
12
11
  }
13
12
  if (options.keepComments) {
14
13
  return remoteContent
@@ -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,338 +1,13 @@
1
- const { transform } = require('@technote-space/doctoc')
2
- const { removeLeadingAndTrailingLineBreaks, escapeRegexString } = require('../utils/regex')
3
- const { findMinIndent } = require('../utils/text')
1
+ const { generateToc } = require('../utils/toc')
4
2
 
5
3
  module.exports = async function TOC(api) {
6
4
  // console.log("TOC API", api)
7
- const { options, fileContent, originalFileContent } = api
8
- //const currentBlock = api.getCurrentBlock()
9
- const originalBlock = api.getOriginalBlock()
10
- const { block } = originalBlock
11
- // console.log('originalBlock', originalBlock)
12
- const originalContents = originalFileContent
13
- const opts = options || {}
14
- const isSub = opts.sub
15
- opts.firsth1 = (opts.firsth1) ? true : false
16
- let contents = fileContent
17
- // console.log('contents', contents)
18
-
19
- let debugFileMatch
20
- // console.log('config', config.originalPath)
21
- // debugFileMatch = config.originalPath.match(/packages\/analytics\/README\.md/)
22
-
23
- // https://www.npmjs.com/package/@technote-space/toc-generator
24
- const tocOptions = {
25
- // mode: 'github.com', // github.com | bitbucket.org | gitlab.com | nodejs.org | ghost.org (default: github.com)
26
- isNotitle: true,
27
- //isCustomMode: true,
28
- openingComment: '',
29
- closingComment: '',
30
- maxHeaderLevel: (opts.maxDepth) ? Number(opts.maxDepth) : 4,
31
- // maxHeaderLevel: 2, // default: 4
32
- // title: '**Table of Contents**',
33
- // isNotitle: true,
34
- // isFolding: true,
35
- // entryPrefix: '*',
36
- // processAll: true,
37
- // updateOnly: true,
38
- // openingComment: '<!-- toc -->',
39
- // closingComment: '<!-- tocstop --> ',
40
- // checkOpeningComments: ['<!-- toc '],
41
- // checkClosingComments: ['<!-- tocstop '],
42
- // isCustomMode: false,
43
- // customTemplate: '<p align="center">${ITEMS}</p>',
44
- // itemTemplate: '<a href="${LINK}">${TEXT}</a>',
45
- // separator: '<span>|</span>',
46
- // footer: 'end',
47
- }
48
- const t = await transform(contents, tocOptions)
49
- let outputText = t.wrappedToc || ''
50
-
51
- if (debugFileMatch) {
52
- console.log('before firsth1 removal', outputText)
53
- }
54
-
55
- /* remove first h1 */
56
- if (!opts.firsth1) {
57
- // console.log('outputText', outputText)
58
- const lines = outputText.split('\n')
59
- let firstH1
60
- let firstLine
61
- const countOfH1s = lines.reduce((acc, line, index) => {
62
- if (line !== '' && !firstLine) {
63
- firstLine = index
64
- }
65
- if (line.match(/^-\s+/)) {
66
- if (!firstH1) {
67
- const rawText = line.match(/\[(.*)\]/)[1]
68
- firstH1 = [line, index, firstLine === index, rawText]
69
- }
70
- acc = acc + 1
71
- }
72
- return acc
73
- }, 0)
74
-
75
- const firstHeadingData = (firstH1 && Array.isArray(firstH1)) ? firstH1 : []
76
- const [ lineText, lineIndex, isFirst, matchText ] = firstHeadingData
77
-
78
- let docHasHeading = false
79
- if (matchText) {
80
- // verify its h1
81
- const matchTextEscaped = escapeRegexString(matchText)
82
- // console.log('matchTextEscaped', matchTextEscaped)
83
- // /^#{1}\s+(.*)/
84
- const FIRST_H1_REGEX = new RegExp(`^#\\s*\\[?${matchTextEscaped}\\]?(?:.*)?`, 'gim')
85
- // /^<h1\b[^>]*>([\s\S]*?)<\/h1>/
86
- const FIRST_HTML_H1_REGEX = new RegExp(`^<h1\\b[^>]*>[\\s]*?(${matchTextEscaped})[\\s]*?<\\/h1>`, 'gim')
87
- // /^(.*)\n={3,}/
88
- const FIRST_UNDERSCORE_H1 = new RegExp(`^(${matchTextEscaped})\n={3,}`, 'gim')
89
-
90
- if (contents.match(FIRST_H1_REGEX)) {
91
- docHasHeading = matchText
92
- } else if (contents.match(FIRST_HTML_H1_REGEX)) {
93
- docHasHeading = matchText
94
- } else if (contents.match(FIRST_UNDERSCORE_H1)) {
95
- docHasHeading = matchText
96
- }
97
- }
98
-
99
- if (debugFileMatch) {
100
- console.log('matchText', matchText)
101
- if (docHasHeading) {
102
- console.log('Found heading 1', docHasHeading)
103
- }
104
- }
105
-
106
- if (debugFileMatch) {
107
- console.log('top level toc item count', countOfH1s)
108
- if (docHasHeading) {
109
- console.log('Found heading 1', docHasHeading)
110
- console.log('firstH1', firstH1)
111
- }
112
- }
113
-
114
- let firstItemWithContent
115
- let foundFirstH1
116
-
117
- if (docHasHeading) {
118
- outputText = lines.reduce((acc, line, i) => {
119
- const isLineEmpty = line === ''
120
- if (!isLineEmpty && !firstItemWithContent) {
121
- firstItemWithContent = i
122
- }
123
- if (!foundFirstH1 && (firstItemWithContent === i) && line.match(/^-\s+/)) {
124
- foundFirstH1 = true
125
- return acc
126
- }
127
- // Add back line and remove level
128
- let newLineValue = line
129
- if (lineText) {
130
- // const untilFirstH1 = i < lineIndex
131
- /* @TODO make option? flatten all non first h1 tags */
132
- if (countOfH1s > 0 && !isLineEmpty && newLineValue.match(/^\s+-/)) {
133
- newLineValue = line.substring(2)
134
- }
135
- }
136
-
137
- acc = acc.concat(newLineValue)
138
- return acc
139
- }, []).join('\n')
140
- }
141
-
142
- // console.log('outputText', outputText)
143
- if (debugFileMatch) {
144
- console.log('after firsth1 removal', outputText)
145
- }
146
- }
147
- // console.log(t)
148
- // Fix <h1> with multiple lines
149
- const spaces = outputText.match(/\[\n([\s\S]*?)\]/gm)
150
- if (spaces) {
151
- const fixed = spaces[0]
152
- // all new lines
153
- .replace(/\n/g, '')
154
- // leading spaces
155
- .replace(/\[\s+/, '[')
156
- .trim()
157
- outputText = outputText.replace(spaces[0], fixed)
158
- }
159
- // console.log(outputText)
160
- outputText = outputText
161
- .replace(/(.*)\[Table of Contents\]\(.*\)\n?/i, '')
162
- .replace(/(.*)\[toc\]\(.*\)\n?/i, '')
163
-
164
-
165
- if (opts.excludeText) {
166
-
167
- outputText = excludeTocItem(outputText, opts.excludeText)
168
- // // (\s+)?-(.*)\[Usage\]\(.*\)
169
- // const regex = new RegExp(`\(\\s+\)?-(.*)\\[${opts.excludeText}\\]\\(.*\\)`, 'i')
170
- // // /(\s+)?-(.*)\[Usage\]\(.*\)(\n\s+(.*))+/im
171
- // const nestedRegex = new RegExp(`\(\\s+\)?-(.*)\\[${opts.excludeText}\\]\\(.*\\)\(\\n\\s+\(.*\)\)+`, 'i')
172
-
173
- // const hasNested = nestedRegex.exec(outputText)
174
- // if (hasNested) {
175
- // // Count indentation of spaces
176
- // const numberOfSpaces = hasNested[1].replace(/\n/g, '').length
177
- // const subItems = numberOfSpaces + 1
178
- // // Update regex to only remove sub items
179
- // const nestedRegexSpaces = new RegExp(`\(\\s+\)?-(.*)\\[${opts.excludeText}\\]\\(.*\\)\(\\n\\s{${subItems},}\(.*\)\)+`, 'i')
180
- // // console.log('nestedRegexSpaces', nestedRegexSpaces)
181
- // // If exclude value has nested sections remove them as well.
182
- // outputText = outputText.replace(nestedRegexSpaces, '')
183
- // outputText = outputText.replace(regex, '')
184
- // } else {
185
- // outputText = outputText.replace(regex, '')
186
- // }
187
- }
188
-
189
- /* Sub table of contents */
190
- if (isSub) {
191
- // const start = fileContent.indexOf(open.value)
192
- // const linesBefore = fileContent.substr(0, start).split('\n')
193
- // const closestHeading = linesBefore.reverse().find((line) => {
194
- // return line.match((/^#+/))
195
- // })
196
- const linesBefore = originalContents.substr(0, block.start).split('\n')
197
- const closestHeading = linesBefore.reverse().find((line) => {
198
- return line.match((/^#+/))
199
- })
200
-
201
- if (closestHeading) {
202
- const headingText = closestHeading.replace(/^#*\s*/, '')
203
- // console.log('BEFORE', linesBefore)
204
- // console.log('closest parent heading', closestHeading)
205
- // console.log('headingText', headingText)
206
- // https://regex101.com/r/MB85zm/1
207
-
208
- const findSubToc = new RegExp(`^\(\\s+\)?-(.*)\\[${headingText}\\]\\(.*\\)(\\n\\s.*)+`, 'gm')
209
- // console.log('findSubToc', findSubToc)
210
- const single = singleLinePattern(headingText)
211
- // console.log('single', single)
212
- const subItems = outputText.match(findSubToc)
213
- if (subItems) {
214
- const items = subItems[0].replace(single, '').split('\n')
215
- .filter(Boolean)
216
- // console.log('items', items)
217
- const finalItems = items // .slice(1, items.length)
218
- if (finalItems) {
219
- const indent = findMinIndent(finalItems.join('\n'))
220
- // console.log('min indent', indent)
221
- // console.log('finalItems', finalItems)
222
- outputText = finalItems.map((thing) => thing.substring(indent)).join('\n')
223
- } else {
224
- // console.log('No sub items')
225
- }
226
- }
227
- }
228
- }
229
-
230
- // If collapse wrap in <details>
231
- if (opts.collapse) {
232
- const text = (opts.collapseText) ? opts.collapseText : 'Table of Contents'
233
- return `<details>
234
- <summary>${text}</summary>
235
- ${outputText
236
- // Replace leading double spaces
237
- .replace(/^\n\n/, '\n')
238
- // Replace trailing double spaces
239
- .replace(/\n\n$/, '\n')}
240
- </details>`
241
- }
242
-
243
- return outputText.replace(removeLeadingAndTrailingLineBreaks, '')
244
- }
245
-
246
- const HTML_TAG = /<([a-zA-Z1-6]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)/gim
247
-
248
- function parseHtmlProps(mdContents) {
249
- const htmlTags = mdContents
250
- /* Fix non terminating <tags> */
251
- .replace(/(['"`]<(.*)>['"`])/gm, '_$2_')
252
- .match(HTML_TAG)
253
- //console.log('htmlTags', htmlTags)
254
-
255
- let tags = []
256
- if (htmlTags) {
257
- let propsValues = {}
258
- var regexSingleTag = /<([a-zA-Z1-6]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)/
259
- for (var i = 0; i < htmlTags.length; i++) {
260
- var tagMatches = regexSingleTag.exec(htmlTags[i])
261
- // console.log('tagMatches', tagMatches)
262
- var [ match, tag, props ] = tagMatches
263
- // console.log(`Tag #${i} ${tag}`)
264
- if (props) {
265
- const cleanProps = props
266
- // Remove new lines and tabs
267
- .replace(/\n\t/g, '')
268
- // Remove extra spaces
269
- .replace(/\s\s+/g, ' ')
270
- .trim()
271
-
272
- propsValues = cleanProps.split(" ").reduce((acc, curr) => {
273
- const hasQuotes = curr.match(/=['"]/)
274
- // Check key="value" | key='value' | key={value}
275
- const propWithValue = /([A-Za-z-_$]+)=['{"](.*)['}"]/g.exec(curr)
276
- if (propWithValue) {
277
- return {
278
- ...acc,
279
- [`${propWithValue[1]}`]: (hasQuotes) ? propWithValue[2] : convert(propWithValue[2])
280
- }
281
- }
282
- // Check isLoading boolean props
283
- const booleanProp = curr.match(/([A-Za-z]*)/)
284
- if (booleanProp) {
285
- return {
286
- ...acc,
287
- [`${booleanProp[1]}`]: true
288
- }
289
- }
290
- return acc
291
- }, {})
292
- }
293
-
294
- tags.push({
295
- tag: tag,
296
- props: propsValues,
297
- raw: match
298
- })
299
- }
300
- }
301
- return tags
302
- }
303
-
304
- function singleLinePattern(text) {
305
- /* (\s+)?-(.*)\[Usage\]\(.*\) */
306
- return new RegExp(`\(\\s+\)?-(.*)\\[${text}\\]\\(.*\\)`, 'i')
307
- }
308
-
309
- function excludeTocItem(str, excludeText) {
310
- const matchTextEscaped = escapeRegexString(excludeText)
311
- /* (\s+)?-(.*)\[Usage\]\(.*\) */
312
- const regex = singleLinePattern(matchTextEscaped) // new RegExp(`\(\\s+\)?-(.*)\\[${matchTextEscaped}\\]\\(.*\\)`, 'i')
313
- /* /(\s+)?-(.*)\[Usage\]\(.*\)(\n\s+(.*))+/im */
314
- const nestedRegex = new RegExp(`\(\\s+\)?-(.*)\\[${matchTextEscaped}\\]\\(.*\\)\(\\n\\s+\(.*\)\)+`, 'i')
315
-
316
- const hasNested = nestedRegex.exec(str)
317
- if (hasNested) {
318
- // Count indentation of spaces
319
- const numberOfSpaces = (hasNested[1] || '').replace(/\n/g, '').length
320
- const subItems = numberOfSpaces + 1
321
- // Update regex to only remove sub items
322
- const nestedRegexSpaces = new RegExp(`\(\\s+\)?-(.*)\\[${matchTextEscaped}\\]\\(.*\\)\(\\n\\s{${subItems},}\(.*\)\)+`, 'i')
323
- // console.log('nestedRegexSpaces', nestedRegexSpaces)
324
- // If exclude value has nested sections remove them as well.
325
- str = str.replace(nestedRegexSpaces, '')
326
- str = str.replace(regex, '')
327
- } else {
328
- str = str.replace(regex, '')
329
- }
330
- return str
331
- }
332
-
333
- function removeUndefined(outputText) {
334
- // remove undefined from new line and start of string if first H1 is missing
335
- return outputText.replace(/\nundefined/g, '\n-').replace(/^undefined/g, '-')
336
- }
337
-
338
- // Alt https://github.com/thlorenz/doctoc
5
+ const { options, fileContent, srcPath, getBlockDetails } = api
6
+ const toc = await generateToc({
7
+ options: options || {},
8
+ fileContent,
9
+ srcPath,
10
+ getBlockDetails: getBlockDetails
11
+ })
12
+ return toc
13
+ }
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
+ }