markdown-magic 3.6.5 → 4.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.
@@ -1,5 +1,6 @@
1
1
  const code = require('./code')
2
2
  const file = require('./file')
3
+ const fileTree = require('./fileTree')
3
4
  const remoteContent = require('./remote')
4
5
  const toc = require('./toc')
5
6
  const sectionToc = require('./sectionToc')
@@ -12,7 +13,7 @@ const transforms = {
12
13
  * Generate table of contents from markdown file
13
14
  *
14
15
  * **Options:**
15
- * - `firsth1` - *boolean* - (optional): Show first h1 of doc in table of contents. Default `false`
16
+ * - `firstH1` - *boolean* - (optional): Show first h1 of doc in table of contents. Default `false`
16
17
  * - `collapse` - *boolean* - (optional): Collapse the table of contents in a detail accordion. Default `false`
17
18
  * - `collapseText` - *string* - (optional): Text the toc accordion summary
18
19
  * - `excludeText` - *string* - (optional): Text to exclude in the table of contents. Default `Table of Contents`
@@ -20,12 +21,12 @@ const transforms = {
20
21
  *
21
22
  * **Example:**
22
23
  * ```md
23
- * <!-- doc-gen TOC -->
24
+ * <!-- docs TOC -->
24
25
  * toc will be generated here
25
- * <!-- end-doc-gen -->
26
+ * <!-- /docs -->
26
27
  * ```
27
28
  *
28
- * Default `matchWord` is `doc-gen`
29
+ * Default `matchWord` is `docs`
29
30
  *
30
31
  * ---
31
32
  * @param {string} content The current content of the comment block
@@ -47,18 +48,18 @@ const transforms = {
47
48
  *
48
49
  * **Example:**
49
50
  * ```md
50
- * <!-- doc-gen CODE src="./relative/path/to/code.js" -->
51
+ * <!-- docs CODE src="./relative/path/to/code.js" -->
51
52
  * This content will be dynamically replaced with code from the file
52
- * <!-- end-doc-gen -->
53
+ * <!-- /docs -->
53
54
  * ```
54
55
  *
55
56
  * ```md
56
- * <!-- doc-gen CODE src="./relative/path/to/code.js" lines=22-44 -->
57
+ * <!-- docs CODE src="./relative/path/to/code.js" lines=22-44 -->
57
58
  * This content will be dynamically replaced with code from the file lines 22 through 44
58
- * <!-- end-doc-gen -->
59
+ * <!-- /docs -->
59
60
  * ```
60
- *
61
- * Default `matchWord` is `doc-gen`
61
+ *
62
+ * Default `matchWord` is `docs`
62
63
  *
63
64
  * ---
64
65
  * @param {string} content The current content of the comment block
@@ -76,12 +77,12 @@ const transforms = {
76
77
  *
77
78
  * **Example:**
78
79
  * ```md
79
- * <!-- doc-gen FILE src=./path/to/file -->
80
+ * <!-- docs FILE src=./path/to/file -->
80
81
  * This content will be dynamically replaced from the local file
81
- * <!-- end-doc-gen -->
82
+ * <!-- /docs -->
82
83
  * ```
83
84
  *
84
- * Default `matchWord` is `doc-gen`
85
+ * Default `matchWord` is `docs`
85
86
  *
86
87
  * ---
87
88
  * @param {string} content The current content of the comment block
@@ -99,12 +100,12 @@ const transforms = {
99
100
  *
100
101
  * **Example:**
101
102
  * ```md
102
- * <!-- doc-gen REMOTE url=http://url-to-raw-md-file.md -->
103
+ * <!-- docs REMOTE url=http://url-to-raw-md-file.md -->
103
104
  * This content will be dynamically replaced from the remote url
104
- * <!-- end-doc-gen -->
105
+ * <!-- /docs -->
105
106
  * ```
106
107
  *
107
- * Default `matchWord` is `doc-gen`
108
+ * Default `matchWord` is `docs`
108
109
  *
109
110
  * ---
110
111
  * @param {string} content The current content of the comment block
@@ -112,6 +113,73 @@ const transforms = {
112
113
  * @return {string} Updated content to place in the content block
113
114
  */
114
115
  REMOTE: remoteContent,
116
+ /**
117
+ * ### > fileTree
118
+ *
119
+ * Generate a file tree table of contents
120
+ *
121
+ * **Options:**
122
+ * - `src` (optional): The directory path to generate the file tree for. Default `.` (current directory)
123
+ * - `maxDepth` (optional): Maximum depth to traverse in the directory tree. Default `3`
124
+ * - `includeFiles` (optional): Whether to include files in the tree or just directories. Default `true`
125
+ * - `exclude` (optional): Array of glob patterns to exclude from the tree. Default `[]`
126
+ * - `showSize` (optional): Whether to show file sizes. Default `false`
127
+ * - `format` (optional): Output format: "tree" or "list". Default `"tree"`
128
+ *
129
+ * **Example:**
130
+ * ```md
131
+ * <!-- docs fileTree src="./src" maxDepth=2 -->
132
+ * file tree will be generated here
133
+ * <!-- /docs -->
134
+ * ```
135
+ *
136
+ * **Example Output (tree format):**
137
+ * ```
138
+ * └── src/
139
+ * ├── transforms/
140
+ * │ ├── code/
141
+ * │ │ ...
142
+ * │ ├── fileTree.js
143
+ * │ ├── index.js
144
+ * │ └── toc.js
145
+ * ├── utils/
146
+ * │ ├── fs.js
147
+ * │ ├── logs.js
148
+ * │ └── text.js
149
+ * └── index.js
150
+ * ```
151
+ *
152
+ * **Example Output (list format):**
153
+ * ```md
154
+ * - **src/**
155
+ * - **transforms/**
156
+ * - **code/**
157
+ * - ...
158
+ * - fileTree.js
159
+ * - index.js
160
+ * - toc.js
161
+ * - **utils/**
162
+ * - fs.js
163
+ * - logs.js
164
+ * - text.js
165
+ * - index.js
166
+ * ```
167
+ *
168
+ * **Example with file sizes:**
169
+ * ```
170
+ * └── src/
171
+ * ├── index.js (15.2 KB)
172
+ * └── package.json (552 B)
173
+ * ```
174
+ *
175
+ * Default `matchWord` is `docs`
176
+ *
177
+ * ---
178
+ * @param {string} content The current content of the comment block
179
+ * @param {object} options The options passed in from the comment declaration
180
+ * @return {string} Updated content to place in the content block
181
+ */
182
+ fileTree: fileTree,
115
183
  /**
116
184
  * ### > install
117
185
  *
@@ -125,12 +193,12 @@ const transforms = {
125
193
  *
126
194
  * **Example:**
127
195
  * ```md
128
- * <!-- doc-gen install -->
196
+ * <!-- docs install -->
129
197
  * Installation instructions will be generated here
130
- * <!-- end-doc-gen -->
198
+ * <!-- /docs -->
131
199
  * ```
132
200
  *
133
- * Default `matchWord` is `doc-gen`
201
+ * Default `matchWord` is `docs`
134
202
  *
135
203
  * ---
136
204
  * @param {string} content The current content of the comment block
@@ -11,12 +11,12 @@ const path = require('path')
11
11
  *
12
12
  * **Example:**
13
13
  * ```md
14
- * <!-- doc-gen INSTALL packageName=my-package -->
14
+ * <!-- docs INSTALL packageName=my-package -->
15
15
  * Installation instructions will be generated here
16
- * <!-- end-doc-gen -->
16
+ * <!-- /docs -->
17
17
  * ```
18
18
  *
19
- * Default `matchWord` is `doc-gen`
19
+ * Default `matchWord` is `docs`
20
20
  *
21
21
  * ---
22
22
  * @param {string} content The current content of the comment block
@@ -5,15 +5,15 @@ const { readFile } = require('../utils/fs')
5
5
  const details = require('../utils/details')
6
6
 
7
7
  module.exports = async function sectionToc(api) {
8
- const { options, currentFileContent, originalFileContent, srcPath, getBlockDetails } = api
8
+ const { options, currentContent, originalContent, srcPath, getBlockDetails } = api
9
9
  const opts = options || {}
10
10
  let { collapseText, collapse } = opts
11
11
  /* Sub table of contents */
12
- const originalBlock = getBlockDetails(originalFileContent)
13
- const closestHeading = findClosestParentHeading(originalFileContent, originalBlock.block.start)
12
+ const originalBlock = getBlockDetails(originalContent)
13
+ const closestHeading = findClosestParentHeading(originalContent, originalBlock.block.start)
14
14
  // console.log('closestHeading', closestHeading)
15
15
 
16
- const subToc = await generateToc(currentFileContent, {
16
+ const subToc = await generateToc(currentContent, {
17
17
  ...opts,
18
18
  normalizeLevels: true,
19
19
  // Set sub table of contents
@@ -11,15 +11,15 @@ const sectionToc = require('./sectionToc')
11
11
  * @property {number} [maxDepth=4] - Maximum depth of headings to include in the table of contents. Default is `4`.
12
12
  * @example
13
13
  ```md
14
- <!-- doc-gen (TOC) -->
14
+ <!-- docs (TOC) -->
15
15
  toc will be generated here
16
- <!-- end-doc-gen -->
17
- ```
16
+ <!-- /docs -->
17
+ ```
18
18
  */
19
19
 
20
20
  module.exports = async function TOC(api) {
21
21
  // console.log("TOC API", api)
22
- const { currentFileContent, srcPath, getBlockDetails } = api
22
+ const { currentContent, srcPath, getBlockDetails } = api
23
23
  /** @type {ToCTransformOptions} */
24
24
  const options = api.options || {}
25
25
  // console.log("TOC OPTIONS", options)
@@ -33,8 +33,8 @@ module.exports = async function TOC(api) {
33
33
  return sectionToc(api)
34
34
  }
35
35
 
36
- opts.firsth1 = (opts.firsth1) ? true : false
37
- let contents = currentFileContent
36
+ opts.firsth1 = (opts.firsth1 || opts.firstH1) ? true : false
37
+ let contents = currentContent
38
38
  // console.log('contents', contents)
39
39
 
40
40
  let collapseText = opts.collapseText
@@ -54,7 +54,7 @@ module.exports = async function TOC(api) {
54
54
  trimLeadingHeading: true,
55
55
  // maxHeaderLevel: 2, // default: 4
56
56
  // title: '**Table of Contents**',
57
- // isNotitle: true,
57
+ // isNoTitle: true,
58
58
  // isFolding: true,
59
59
  // entryPrefix: '*',
60
60
  // processAll: true,
@@ -1,5 +1,6 @@
1
1
  const { getWordCount } = require('../utils/text')
2
2
 
3
- module.exports = function wordCount({ currentFileContent }) {
4
- return getWordCount(currentFileContent)
3
+ module.exports = function wordCount(api) {
4
+ const { currentContent } = api
5
+ return getWordCount(currentContent)
5
6
  }
package/src/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Allowed file syntaxes
3
- * @typedef {'md' | 'js' | 'yml' | 'yaml'} SyntaxType
3
+ * @typedef {'md' | 'js' | 'yml' | 'yaml' | 'toml' | 'sql'} SyntaxType
4
4
  */
5
5
 
6
6
  /** @type {SyntaxType} */
package/src/utils/fs.js CHANGED
@@ -9,10 +9,21 @@ const { readdir, stat, readFile } = fs
9
9
 
10
10
  const IS_HIDDEN_FILE = /(^|[\\\/])\.[^\\\/\.]/g
11
11
 
12
+ /**
13
+ * Check if value is a RegExp
14
+ * @param {any} thing - Value to check
15
+ * @returns {boolean} True if value is RegExp
16
+ */
12
17
  function isRegex(thing) {
13
18
  return (thing instanceof RegExp)
14
19
  }
15
20
 
21
+ /**
22
+ * Write file with directory creation if needed
23
+ * @param {string} filePath - File path to write to
24
+ * @param {string} content - Content to write
25
+ * @returns {Promise<void>}
26
+ */
16
27
  async function writeFile(filePath, content) {
17
28
  try {
18
29
  await fs.writeFile(filePath, content)
@@ -69,6 +80,12 @@ async function escalade(start, callback) {
69
80
 
70
81
  // }
71
82
 
83
+ /**
84
+ * Convert absolute path to relative path
85
+ * @param {string} file - Absolute file path
86
+ * @param {string} cwd - Current working directory
87
+ * @returns {string} Relative path
88
+ */
72
89
  function convertToRelativePath(file, cwd) {
73
90
  return file.replace(cwd, '').replace(/^\//, '')
74
91
  }
@@ -165,6 +182,11 @@ function depth(string) {
165
182
  return path.normalize(string).split(path.sep).length - 1;
166
183
  }
167
184
 
185
+ /**
186
+ * Check if path is local (not remote)
187
+ * @param {string} filePath - File path to check
188
+ * @returns {boolean} True if path is local
189
+ */
168
190
  function isLocalPath(filePath) {
169
191
  if (filePath.startsWith('github.com/') || filePath.startsWith('raw.githubusercontent.com/')) return false
170
192
  return _isLocalPath(filePath)
@@ -26,8 +26,8 @@ test('Finds file from dir', async () => {
26
26
  })
27
27
 
28
28
  test('getGitignoreContents', async () => {
29
- const files = await getGitignoreContents()
30
- /*
29
+ const files = await getGitignoreContents(path.resolve(__dirname, '../../', '.gitignore'))
30
+ //*
31
31
  console.log('files', files)
32
32
  /** */
33
33
  assert.is(Array.isArray(files), true)
@@ -42,6 +42,9 @@ test('getGitignoreContents', async () => {
42
42
  'misc',
43
43
  'misc/**/**.js',
44
44
  "__misc",
45
+ 'large-table.md',
46
+ 'large-table.js',
47
+ 'large-table-data.json',
45
48
  '**/old-test/cool.md',
46
49
  'pids',
47
50
  '*.pid',
@@ -1,12 +1,33 @@
1
1
 
2
+ /**
3
+ * Filter function to get only unique values
4
+ * @param {any} value - Current value
5
+ * @param {number} index - Current index
6
+ * @param {any[]} self - Original array
7
+ * @returns {boolean} True if value is unique
8
+ */
2
9
  function onlyUnique(value, index, self) {
3
10
  return self.indexOf(value) === index
4
11
  }
5
12
 
13
+ /**
14
+ * Get code location string in format path:line:column
15
+ * @param {string} srcPath - Source file path
16
+ * @param {string|number} line - Line number
17
+ * @param {string} [column='0'] - Column number
18
+ * @returns {string} Location string
19
+ */
6
20
  function getCodeLocation(srcPath, line, column = '0') {
7
21
  return `${srcPath}:${line}:${column}`
8
22
  }
9
23
 
24
+ /**
25
+ * Pluralize word based on count
26
+ * @param {any[]|number} thing - Array or number to count
27
+ * @param {string} [single=''] - Singular form
28
+ * @param {string} [plural=''] - Plural form
29
+ * @returns {string} Singular or plural form
30
+ */
10
31
  function pluralize(thing, single = '', plural = '') {
11
32
  const count = Array.isArray(thing) ? thing.length : Number(thing)
12
33
  return count === 1 ? single : plural
@@ -1,7 +1,7 @@
1
1
  // https://stackoverflow.com/questions/38859506/cancel-regex-match-if-timeout
2
2
  const util = require('util')
3
3
  const vm = require('vm')
4
- const { getBlockRegex } = require('../block-parser')
4
+ const { getBlockRegex } = require('comment-block-parser')
5
5
  const { getSyntaxInfo } = require('./syntax')
6
6
 
7
7
  const goodString = `
@@ -53,6 +53,30 @@ const yaml = {
53
53
  }
54
54
  }
55
55
 
56
+ const sql = {
57
+ tags: ['/*', '*/'],
58
+ pattern: [
59
+ '\/\\*+',
60
+ '\\*+/'
61
+ ],
62
+ singleLineTag: '--',
63
+ singleLinePattern: '--',
64
+ singleLine: '--.*$',
65
+ content: '[\\s\\S]*?'
66
+ }
67
+
68
+ const toml = {
69
+ tags: ['#', '#'],
70
+ pattern: [
71
+ '#+',
72
+ '#+'
73
+ ],
74
+ singleLineTag: '#',
75
+ singleLinePattern: '#+',
76
+ singleLine: '#.*$',
77
+ content: '[ \\t\\S]*?'
78
+ }
79
+
56
80
  const syntaxMap = {
57
81
  // <!-- x -->
58
82
  md: html,
@@ -66,8 +90,12 @@ const syntaxMap = {
66
90
  jsx: jsx,
67
91
  mdx: jsx,
68
92
  // ## x ##
93
+ yml: yaml,
69
94
  yaml: yaml,
70
- yml: yaml
95
+ // -- x
96
+ sql: sql,
97
+ // # x
98
+ toml: toml
71
99
  }
72
100
 
73
101
  // Additional comment syntaxes for future
package/src/utils/text.js CHANGED
@@ -1,13 +1,29 @@
1
1
  const { syntaxMap } = require('./syntax')
2
2
 
3
+ /**
4
+ * Split string into lines
5
+ * @param {string} str - Input string
6
+ * @returns {string[]} Array of lines
7
+ */
3
8
  function getLines(str = '') {
4
9
  return str.split(/\r\n|\r|\n/)
5
10
  }
6
11
 
12
+ /**
13
+ * Get line count from string
14
+ * @param {string} str - Input string
15
+ * @returns {number} Number of lines
16
+ */
7
17
  function getLineCount(str = '') {
8
18
  return getLines(str).length
9
19
  }
10
20
 
21
+ /**
22
+ * Get row and column position from character index
23
+ * @param {string} input - Input string
24
+ * @param {number} indexToFind - Character index to find
25
+ * @returns {{row: number, col: number}} Row and column position
26
+ */
11
27
  function getRowAndColumnFromCharPos(input, indexToFind) {
12
28
  const preChunk = input.substr(0, indexToFind);
13
29
  const row = preChunk.split('\n').length - 1
@@ -16,23 +32,50 @@ function getRowAndColumnFromCharPos(input, indexToFind) {
16
32
  return { row, col }
17
33
  };
18
34
 
35
+ /**
36
+ * Get word count from string
37
+ * @param {string} str - Input string
38
+ * @returns {number} Word count
39
+ */
19
40
  function getWordCount(str = '') {
20
41
  return str.trim().split(/\s+/).length
21
42
  }
22
43
 
44
+ /**
45
+ * Get first character from string
46
+ * @param {string} str - Input string
47
+ * @returns {string} First character
48
+ */
23
49
  function getFirstCharacter(str) {
24
50
  return str.charAt(0)
25
51
  }
26
52
 
53
+ /**
54
+ * Get last character from string
55
+ * @param {string} str - Input string
56
+ * @returns {string} Last character
57
+ */
27
58
  function getLastCharacter(str) {
28
59
  return str.substr(-1)
29
60
  }
30
61
 
62
+ /**
63
+ * Get leading spaces from text
64
+ * @param {string} text - Input text
65
+ * @returns {string} Leading spaces
66
+ */
31
67
  function getLeadingSpaces(text) {
32
68
  const matches = text.match(/^\s*/)
33
69
  return (matches && matches[0]) ? matches[0] : ''
34
70
  }
35
71
 
72
+ /**
73
+ * Get text between character positions
74
+ * @param {string} text - Input text
75
+ * @param {number} start - Start position
76
+ * @param {number} end - End position
77
+ * @returns {string} Text between positions
78
+ */
36
79
  function getTextBetweenChars(text, start, end) {
37
80
  return text.slice(start, end)
38
81
  }
@@ -56,6 +99,14 @@ function getTextBetweenWords(s, prefix, suffix) {
56
99
  return s
57
100
  }
58
101
 
102
+ /**
103
+ * Replace text between character positions
104
+ * @param {string} str - Input string
105
+ * @param {number} start - Start position
106
+ * @param {number} end - End position
107
+ * @param {string} newStr - Replacement string
108
+ * @returns {string} Modified string
109
+ */
59
110
  function replaceTextBetweenChars(str = '', start, end, newStr) {
60
111
  return str.substring(0, start) + newStr + str.substring(end)
61
112
  }
@@ -77,22 +128,39 @@ function getTextBetweenLines(content, startLine, endLine) {
77
128
  if (startDefined && !endDefined) {
78
129
  return lines.slice(startLine - 1, startLine).join('')
79
130
  }
80
- if (startLine && endLine && parseInt(startLine, 10) <= parseInt(endLine, 10)) {
131
+ // @ts-ignore
132
+ if (startLine && endLine && Number(startLine) <= Number(endLine)) {
81
133
  return lines.slice(startLine - 1, endLine).join('\n')
82
134
  }
83
135
  }
84
136
 
137
+ /**
138
+ * Check if string is uppercase
139
+ * @param {string} str - Input string
140
+ * @returns {boolean} True if uppercase
141
+ */
85
142
  function isUpperCase(str) {
86
143
  return str === str.toUpperCase()
87
144
  }
88
145
 
89
146
  // https://github.com/jamiebuilds/min-indent/blob/master/index.js
147
+ /**
148
+ * Find minimum indentation in string
149
+ * @param {string} string - Input string
150
+ * @returns {number} Minimum indentation level
151
+ */
90
152
  function findMinIndent(string) {
91
153
  const match = string.match(/^[ \t]*(?=\S)/gm)
92
154
  if (!match) return 0
93
155
  return match.reduce((r, a) => Math.min(r, a.length), Infinity)
94
156
  }
95
157
 
158
+ /**
159
+ * Strip indentation from string
160
+ * @param {string} string - Input string
161
+ * @param {number} [indentation] - Indentation level to strip
162
+ * @returns {string} String with indentation stripped
163
+ */
96
164
  function stripIndent(string, indentation) {
97
165
  const indent = typeof indentation !== 'undefined' ? indentation : findMinIndent(string);
98
166
  if (indent === 0) {
@@ -105,7 +173,7 @@ function stripIndent(string, indentation) {
105
173
  /**
106
174
  * Trim leading & trailing spaces/line breaks in code and keeps the indentation of the first non-empty line
107
175
  * @param {string|number} str
108
- * @returns string
176
+ * @returns {string}
109
177
  */
110
178
  function trimString(str = '') {
111
179
  let content = (typeof str === 'number') ? str.toString() : str
@@ -113,6 +181,15 @@ function stripIndent(string, indentation) {
113
181
  return content.replace(/^(?:[\t ]*(?:\r?\n|\r))+|\s+$/g, '')
114
182
  }
115
183
 
184
+ /**
185
+ * Add indentation to string
186
+ * @param {string} string - Input string
187
+ * @param {number} [count=1] - Number of indentations to add
188
+ * @param {object} [options={}] - Options for indentation
189
+ * @param {string} [options.indent=' '] - Character(s) to use for indentation
190
+ * @param {boolean} [options.includeEmptyLines=false] - Whether to indent empty lines
191
+ * @returns {string} Indented string
192
+ */
116
193
  function indentString(string, count = 1, options = {}) {
117
194
  const {
118
195
  indent = ' ',
@@ -130,8 +207,8 @@ function indentString(string, count = 1, options = {}) {
130
207
  /**
131
208
  * Removes the indentation of multiline strings
132
209
  * @link https://github.com/victornpb/tiny-dedent/
133
- * @param {string} str A template literal string
134
- * @return {string} A string without the indentation
210
+ * @param {string} str - A template literal string
211
+ * @returns {string} A string without the indentation
135
212
  */
136
213
  function dedentString(str) {
137
214
  str = str.replace(/^[ \t]*\r?\n/, ''); // remove leading blank line
@@ -180,7 +257,7 @@ function stripCommentBlockOld(str, syntax = 'md') {
180
257
  /**
181
258
  * Strip out comment blocks
182
259
  * @param {string} str
183
- * @param {typeof import('../types')['syntaxType']} syntax
260
+ * @param {import('../types').SyntaxType} syntax
184
261
  * @returns {string} clean comment-less string
185
262
  */
186
263
  function stripComments(str, syntax = 'md') {
@@ -188,11 +265,18 @@ function stripComments(str, syntax = 'md') {
188
265
  const [ openPattern, closePattern ] = syntaxData.pattern
189
266
  const OR = (syntaxData.singleLine) ? `|\\s?[ \\t]*${syntaxData.singleLine}` : ''
190
267
  const CONTENT = syntaxData.content || '[\\s\\S]*?'
191
- const pattern = new RegExp(`\\s?[ \\t]*${openPattern}(${CONTENT})?${closePattern}${OR}`, 'gim')
192
- // console.log('pattern', pattern)
193
- return str.replace(pattern, '')
194
- // https://regex101.com/r/XKHU18/5
195
- return str.replace(/\s?[ \t]*\/\*[\s\S]*?\*\/|\s?[ \t]*\/\/.*$|\/\*{1,}[\n\*]*(\s?[\s\S]*?)?\*+\//gm, '')
268
+
269
+ // Handle multi-line comments
270
+ const multiLinePattern = new RegExp(`\\s?[ \\t]*${openPattern}${CONTENT}${closePattern}`, 'gim')
271
+ let result = str.replace(multiLinePattern, '')
272
+
273
+ // Handle single-line comments if they exist
274
+ if (syntaxData.singleLine) {
275
+ const singleLinePattern = new RegExp(`\\s?[ \\t]*${syntaxData.singleLine}.*$`, 'gm')
276
+ result = result.replace(singleLinePattern, '')
277
+ }
278
+
279
+ return result
196
280
  }
197
281
 
198
282
 
@@ -291,33 +375,48 @@ function convertCommentSyntax(str, { from, to }) {
291
375
  }
292
376
 
293
377
  /**
294
- * capitalize first letter
295
- * @param {string} str
296
- * @returns
378
+ * Capitalize first letter
379
+ * @param {string} str - Input string
380
+ * @returns {string} String with first letter capitalized
297
381
  */
298
382
  function capitalizeFirstLetter(str) {
299
383
  return capitalize(str.charAt(0)) + str.slice(1)
300
384
  }
301
385
 
302
386
  /**
303
- * capitalize string
304
- * @param {string} str
305
- * @returns
387
+ * Capitalize string
388
+ * @param {string} str - Input string
389
+ * @returns {string} Capitalized string
306
390
  */
307
391
  function capitalize(str = '') {
308
392
  return str.toUpperCase()
309
393
  }
310
394
 
395
+ /**
396
+ * Convert string to camelCase
397
+ * @param {string} str - Input string
398
+ * @returns {string} camelCase string
399
+ */
311
400
  function camelCase(str = '') {
312
401
  return str.replace(/[-_ ](\w)/g, (_, c) => c.toUpperCase())
313
402
  }
314
403
 
404
+ /**
405
+ * Convert string to kebab-case
406
+ * @param {string} str - Input string
407
+ * @returns {string} kebab-case string
408
+ */
315
409
  function kebabCase(str = '') {
316
410
  return str.replace(/\B([A-Z])/g, '-$1').toLowerCase()
317
411
  }
318
412
 
319
413
  const smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|nor|of|on|or|per|the|to|vs?\.?|via)$/i;
320
414
 
415
+ /**
416
+ * Convert string to Title Case
417
+ * @param {string} str - Input string
418
+ * @returns {string} Title Case string
419
+ */
321
420
  function toTitleCase(str = '') {
322
421
  return str.replace(/[A-Za-z0-9\u00C0-\u00FF]+[^\s-]*/g, (match, index, title) => {
323
422
  if (index > 0