source: frontend/node_modules/v8-to-istanbul/lib/source.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 2 weeks ago

Fix frontend appearance

  • Property mode set to 100644
File size: 7.7 KB
RevLine 
[9af201e]1const CovLine = require('./line')
2const { sliceRange } = require('./range')
3const { GREATEST_LOWER_BOUND, LEAST_UPPER_BOUND } = require('source-map').SourceMapConsumer
4
5module.exports = class CovSource {
6 constructor (sourceRaw, wrapperLength) {
7 sourceRaw = sourceRaw ? sourceRaw.trimEnd() : ''
8 this.lines = []
9 this.eof = sourceRaw.length
10 this.shebangLength = getShebangLength(sourceRaw)
11 this.wrapperLength = wrapperLength - this.shebangLength
12 this._buildLines(sourceRaw)
13 }
14
15 _buildLines (source) {
16 let position = 0
17 let ignoreCount = 0
18 let ignoreAll = false
19 for (const [i, lineStr] of source.split(/(?<=\r?\n)/u).entries()) {
20 const line = new CovLine(i + 1, position, lineStr)
21 if (ignoreCount > 0) {
22 line.ignore = true
23 ignoreCount--
24 } else if (ignoreAll) {
25 line.ignore = true
26 }
27 this.lines.push(line)
28 position += lineStr.length
29
30 const ignoreToken = this._parseIgnore(lineStr)
31 if (!ignoreToken) continue
32
33 line.ignore = true
34 if (ignoreToken.count !== undefined) {
35 ignoreCount = ignoreToken.count
36 }
37 if (ignoreToken.start || ignoreToken.stop) {
38 ignoreAll = ignoreToken.start
39 ignoreCount = 0
40 }
41 }
42 }
43
44 /**
45 * Parses for comments:
46 * c8 ignore next
47 * c8 ignore next 3
48 * c8 ignore start
49 * c8 ignore stop
50 * @param {string} lineStr
51 * @return {{count?: number, start?: boolean, stop?: boolean}|undefined}
52 */
53 _parseIgnore (lineStr) {
54 const testIgnoreNextLines = lineStr.match(/^\W*\/\* c8 ignore next (?<count>[0-9]+) *\*\/\W*$/)
55 if (testIgnoreNextLines) {
56 return { count: Number(testIgnoreNextLines.groups.count) }
57 }
58
59 // Check if comment is on its own line.
60 if (lineStr.match(/^\W*\/\* c8 ignore next *\*\/\W*$/)) {
61 return { count: 1 }
62 }
63
64 if (lineStr.match(/\/\* c8 ignore next \*\//)) {
65 // Won't ignore successive lines, but the current line will be ignored.
66 return { count: 0 }
67 }
68
69 const testIgnoreStartStop = lineStr.match(/\/\* c8 ignore (?<mode>start|stop) *\*\//)
70 if (testIgnoreStartStop) {
71 if (testIgnoreStartStop.groups.mode === 'start') return { start: true }
72 if (testIgnoreStartStop.groups.mode === 'stop') return { stop: true }
73 }
74 }
75
76 // given a start column and end column in absolute offsets within
77 // a source file (0 - EOF), returns the relative line column positions.
78 offsetToOriginalRelative (sourceMap, startCol, endCol) {
79 const lines = sliceRange(this.lines, startCol, endCol, true)
80 if (!lines.length) return {}
81
82 const start = originalPositionTryBoth(
83 sourceMap,
84 lines[0].line,
85 Math.max(0, startCol - lines[0].startCol)
86 )
87 if (!(start && start.source)) {
88 return {}
89 }
90
91 let end = originalEndPositionFor(
92 sourceMap,
93 lines[lines.length - 1].line,
94 endCol - lines[lines.length - 1].startCol
95 )
96 if (!(end && end.source)) {
97 return {}
98 }
99
100 if (start.source !== end.source) {
101 return {}
102 }
103
104 if (start.line === end.line && start.column === end.column) {
105 end = sourceMap.originalPositionFor({
106 line: lines[lines.length - 1].line,
107 column: endCol - lines[lines.length - 1].startCol,
108 bias: LEAST_UPPER_BOUND
109 })
110 end.column -= 1
111 }
112
113 return {
114 source: start.source,
115 startLine: start.line,
116 relStartCol: start.column,
117 endLine: end.line,
118 relEndCol: end.column
119 }
120 }
121
122 relativeToOffset (line, relCol) {
123 line = Math.max(line, 1)
124 if (this.lines[line - 1] === undefined) return this.eof
125 return Math.min(this.lines[line - 1].startCol + relCol, this.lines[line - 1].endCol)
126 }
127}
128
129// this implementation is pulled over from istanbul-lib-sourcemap:
130// https://github.com/istanbuljs/istanbuljs/blob/master/packages/istanbul-lib-source-maps/lib/get-mapping.js
131//
132/**
133 * AST ranges are inclusive for start positions and exclusive for end positions.
134 * Source maps are also logically ranges over text, though interacting with
135 * them is generally achieved by working with explicit positions.
136 *
137 * When finding the _end_ location of an AST item, the range behavior is
138 * important because what we're asking for is the _end_ of whatever range
139 * corresponds to the end location we seek.
140 *
141 * This boils down to the following steps, conceptually, though the source-map
142 * library doesn't expose primitives to do this nicely:
143 *
144 * 1. Find the range on the generated file that ends at, or exclusively
145 * contains the end position of the AST node.
146 * 2. Find the range on the original file that corresponds to
147 * that generated range.
148 * 3. Find the _end_ location of that original range.
149 */
150function originalEndPositionFor (sourceMap, line, column) {
151 // Given the generated location, find the original location of the mapping
152 // that corresponds to a range on the generated file that overlaps the
153 // generated file end location. Note however that this position on its
154 // own is not useful because it is the position of the _start_ of the range
155 // on the original file, and we want the _end_ of the range.
156 const beforeEndMapping = originalPositionTryBoth(
157 sourceMap,
158 line,
159 Math.max(column - 1, 1)
160 )
161
162 if (beforeEndMapping.source === null) {
163 return null
164 }
165
166 // Convert that original position back to a generated one, with a bump
167 // to the right, and a rightward bias. Since 'generatedPositionFor' searches
168 // for mappings in the original-order sorted list, this will find the
169 // mapping that corresponds to the one immediately after the
170 // beforeEndMapping mapping.
171 const afterEndMapping = sourceMap.generatedPositionFor({
172 source: beforeEndMapping.source,
173 line: beforeEndMapping.line,
174 column: beforeEndMapping.column + 1,
175 bias: LEAST_UPPER_BOUND
176 })
177 if (
178 // If this is null, it means that we've hit the end of the file,
179 // so we can use Infinity as the end column.
180 afterEndMapping.line === null ||
181 // If these don't match, it means that the call to
182 // 'generatedPositionFor' didn't find any other original mappings on
183 // the line we gave, so consider the binding to extend to infinity.
184 sourceMap.originalPositionFor(afterEndMapping).line !==
185 beforeEndMapping.line
186 ) {
187 return {
188 source: beforeEndMapping.source,
189 line: beforeEndMapping.line,
190 column: Infinity
191 }
192 }
193
194 // Convert the end mapping into the real original position.
195 return sourceMap.originalPositionFor(afterEndMapping)
196}
197
198function originalPositionTryBoth (sourceMap, line, column) {
199 let original = sourceMap.originalPositionFor({
200 line,
201 column,
202 bias: GREATEST_LOWER_BOUND
203 })
204 if (original.line === null) {
205 original = sourceMap.originalPositionFor({
206 line,
207 column,
208 bias: LEAST_UPPER_BOUND
209 })
210 }
211 // The source maps generated by https://github.com/istanbuljs/istanbuljs
212 // (using @babel/core 7.7.5) have behavior, such that a mapping
213 // mid-way through a line maps to an earlier line than a mapping
214 // at position 0. Using the line at positon 0 seems to provide better reports:
215 //
216 // if (true) {
217 // cov_y5divc6zu().b[1][0]++;
218 // cov_y5divc6zu().s[3]++;
219 // console.info('reachable');
220 // } else { ... }
221 // ^ ^
222 // l5 l3
223 const min = sourceMap.originalPositionFor({
224 line,
225 column: 0,
226 bias: GREATEST_LOWER_BOUND
227 })
228 if (min.line > original.line) {
229 original = min
230 }
231 return original
232}
233
234// Not required since Node 12, see: https://github.com/nodejs/node/pull/27375
235const isPreNode12 = /^v1[0-1]\./u.test(process.version)
236function getShebangLength (source) {
237 if (isPreNode12 && source.indexOf('#!') === 0) {
238 const match = source.match(/(?<shebang>#!.*)/)
239 if (match) {
240 return match.groups.shebang.length
241 }
242 } else {
243 return 0
244 }
245}
Note: See TracBrowser for help on using the repository browser.