* Parse a code file, looking for identifiers of the form: * `docs:start:${identifier}` and `docs:end:{identifier}`. * Extract that section of code. * * It's complicated if code snippet identifiers overlap (i.e. the 'start' of one code snippet is in the * middle of another code snippet). The ext
(filePath, identifier)
| 89 | * @returns the code snippet, and start and end line numbers which can later be used for creating a link to github source code. |
| 90 | */ |
| 91 | function extractCodeSnippet(filePath, identifier) { |
| 92 | let fileContent = fs.readFileSync(filePath, "utf-8"); |
| 93 | let linesToRemove = []; |
| 94 | |
| 95 | const startRegex = /(?:\/\/|#)\s+docs:start:([a-zA-Z0-9-._:]+)/g; // `g` will iterate through the regex.exec loop |
| 96 | const endRegex = /(?:\/\/|#)\s+docs:end:([a-zA-Z0-9-._:]+)/g; |
| 97 | |
| 98 | /** |
| 99 | * Search for one of the regex statements in the code file. If it's found, return the line as a string and the line number. |
| 100 | */ |
| 101 | const lookForMatch = (regex) => { |
| 102 | let match; |
| 103 | let matchFound = false; |
| 104 | let matchedLineNum = null; |
| 105 | let actualMatch = null; |
| 106 | let lines = fileContent.split("\n"); |
| 107 | while ((match = regex.exec(fileContent))) { |
| 108 | if (match !== null) { |
| 109 | const identifiers = match[1].split(":"); |
| 110 | let tempMatch = identifiers.includes(identifier) ? match : null; |
| 111 | |
| 112 | if (tempMatch === null) { |
| 113 | // If it's not a match, we'll make a note that we should remove the matched text, because it's from some other identifier and should not appear in the snippet for this identifier. |
| 114 | for (let i = 0; i < lines.length; i++) { |
| 115 | let line = lines[i]; |
| 116 | if (line.trim() == match[0].trim()) { |
| 117 | linesToRemove.push(i + 1); // lines are indexed from 1 |
| 118 | } |
| 119 | } |
| 120 | } else { |
| 121 | if (matchFound === true) { |
| 122 | throw new Error( |
| 123 | `Duplicate for regex ${regex} and identifier ${identifier}` |
| 124 | ); |
| 125 | } |
| 126 | matchFound = true; |
| 127 | matchedLineNum = getLineNumberFromIndex(fileContent, tempMatch.index); |
| 128 | actualMatch = tempMatch; |
| 129 | } |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | return [actualMatch, matchedLineNum]; |
| 134 | }; |
| 135 | |
| 136 | let [startMatch, startLineNum] = lookForMatch(startRegex); |
| 137 | let [endMatch, endLineNum] = lookForMatch(endRegex); |
| 138 | |
| 139 | // Double-check that the extracted line actually contains the required start and end identifier. |
| 140 | if (startMatch !== null) { |
| 141 | const startIdentifiers = startMatch[1].split(":"); |
| 142 | startMatch = startIdentifiers.includes(identifier) ? startMatch : null; |
| 143 | } |
| 144 | if (endMatch !== null) { |
| 145 | const endIdentifiers = endMatch[1].split(":"); |
| 146 | endMatch = endIdentifiers.includes(identifier) ? endMatch : null; |
| 147 | } |
| 148 |
no test coverage detected