formio/node_modules/source-map/lib/source-map-generator.js   F
last analyzed

Complexity

Total Complexity 81
Complexity/F 5.4

Size

Lines of Code 409
Function Count 15

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 0
wmc 81
nc 16896
mnd 4
bc 60
fnc 15
dl 0
loc 409
rs 1.5789
bpm 4
cpm 5.4
noi 2
c 0
b 0
f 0

10 Functions

Rating   Name   Duplication   Size   Complexity  
B source-map-generator.js ➔ SourceMapGenerator_applySourceMap 0 75 4
B source-map-generator.js ➔ SourceMapGenerator_setSourceContent 0 22 6
A source-map-generator.js ➔ SourceMapGenerator 0 12 2
A source-map-generator.js ➔ SourceMapGenerator_toString 0 3 1
B source-map-generator.js ➔ SourceMapGenerator_fromSourceMap 0 40 1
D source-map-generator.js ➔ SourceMapGenerator_validateMapping 0 37 23
A source-map-generator.js ➔ SourceMapGenerator_generateSourcesContent 0 14 1
C source-map-generator.js ➔ SourceMapGenerator_serializeMappings 0 64 8
A source-map-generator.js ➔ SourceMapGenerator_toJSON 0 19 4
B source-map-generator.js ➔ SourceMapGenerator_addMapping 0 33 6

How to fix   Complexity   

Complexity

Complex classes like formio/node_modules/source-map/lib/source-map-generator.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* -*- Mode: js; js-indent-level: 2; -*- */
2
/*
3
 * Copyright 2011 Mozilla Foundation and contributors
4
 * Licensed under the New BSD license. See LICENSE or:
5
 * http://opensource.org/licenses/BSD-3-Clause
6
 */
7
8
var base64VLQ = require('./base64-vlq');
9
var util = require('./util');
10
var ArraySet = require('./array-set').ArraySet;
11
var MappingList = require('./mapping-list').MappingList;
12
13
/**
14
 * An instance of the SourceMapGenerator represents a source map which is
15
 * being built incrementally. You may pass an object with the following
16
 * properties:
17
 *
18
 *   - file: The filename of the generated source.
19
 *   - sourceRoot: A root for all relative URLs in this source map.
20
 */
21
function SourceMapGenerator(aArgs) {
22
  if (!aArgs) {
23
    aArgs = {};
24
  }
25
  this._file = util.getArg(aArgs, 'file', null);
26
  this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null);
27
  this._skipValidation = util.getArg(aArgs, 'skipValidation', false);
28
  this._sources = new ArraySet();
29
  this._names = new ArraySet();
30
  this._mappings = new MappingList();
31
  this._sourcesContents = null;
32
}
33
34
SourceMapGenerator.prototype._version = 3;
35
36
/**
37
 * Creates a new SourceMapGenerator based on a SourceMapConsumer
38
 *
39
 * @param aSourceMapConsumer The SourceMap.
40
 */
41
SourceMapGenerator.fromSourceMap =
42
  function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) {
43
    var sourceRoot = aSourceMapConsumer.sourceRoot;
44
    var generator = new SourceMapGenerator({
45
      file: aSourceMapConsumer.file,
46
      sourceRoot: sourceRoot
47
    });
48
    aSourceMapConsumer.eachMapping(function (mapping) {
49
      var newMapping = {
50
        generated: {
51
          line: mapping.generatedLine,
52
          column: mapping.generatedColumn
53
        }
54
      };
55
56
      if (mapping.source != null) {
57
        newMapping.source = mapping.source;
58
        if (sourceRoot != null) {
59
          newMapping.source = util.relative(sourceRoot, newMapping.source);
60
        }
61
62
        newMapping.original = {
63
          line: mapping.originalLine,
64
          column: mapping.originalColumn
65
        };
66
67
        if (mapping.name != null) {
68
          newMapping.name = mapping.name;
69
        }
70
      }
71
72
      generator.addMapping(newMapping);
73
    });
74
    aSourceMapConsumer.sources.forEach(function (sourceFile) {
75
      var content = aSourceMapConsumer.sourceContentFor(sourceFile);
76
      if (content != null) {
77
        generator.setSourceContent(sourceFile, content);
78
      }
79
    });
80
    return generator;
81
  };
82
83
/**
84
 * Add a single mapping from original source line and column to the generated
85
 * source's line and column for this source map being created. The mapping
86
 * object should have the following properties:
87
 *
88
 *   - generated: An object with the generated line and column positions.
89
 *   - original: An object with the original line and column positions.
90
 *   - source: The original source file (relative to the sourceRoot).
91
 *   - name: An optional original token name for this mapping.
92
 */
93
SourceMapGenerator.prototype.addMapping =
94
  function SourceMapGenerator_addMapping(aArgs) {
95
    var generated = util.getArg(aArgs, 'generated');
96
    var original = util.getArg(aArgs, 'original', null);
97
    var source = util.getArg(aArgs, 'source', null);
98
    var name = util.getArg(aArgs, 'name', null);
99
100
    if (!this._skipValidation) {
101
      this._validateMapping(generated, original, source, name);
102
    }
103
104
    if (source != null) {
105
      source = String(source);
106
      if (!this._sources.has(source)) {
107
        this._sources.add(source);
108
      }
109
    }
110
111
    if (name != null) {
112
      name = String(name);
113
      if (!this._names.has(name)) {
114
        this._names.add(name);
115
      }
116
    }
117
118
    this._mappings.add({
119
      generatedLine: generated.line,
120
      generatedColumn: generated.column,
121
      originalLine: original != null && original.line,
122
      originalColumn: original != null && original.column,
123
      source: source,
124
      name: name
125
    });
126
  };
127
128
/**
129
 * Set the source content for a source file.
130
 */
131
SourceMapGenerator.prototype.setSourceContent =
132
  function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) {
133
    var source = aSourceFile;
134
    if (this._sourceRoot != null) {
135
      source = util.relative(this._sourceRoot, source);
136
    }
137
138
    if (aSourceContent != null) {
139
      // Add the source content to the _sourcesContents map.
140
      // Create a new _sourcesContents map if the property is null.
141
      if (!this._sourcesContents) {
142
        this._sourcesContents = Object.create(null);
143
      }
144
      this._sourcesContents[util.toSetString(source)] = aSourceContent;
145
    } else if (this._sourcesContents) {
146
      // Remove the source file from the _sourcesContents map.
147
      // If the _sourcesContents map is empty, set the property to null.
148
      delete this._sourcesContents[util.toSetString(source)];
149
      if (Object.keys(this._sourcesContents).length === 0) {
150
        this._sourcesContents = null;
151
      }
152
    }
153
  };
154
155
/**
156
 * Applies the mappings of a sub-source-map for a specific source file to the
157
 * source map being generated. Each mapping to the supplied source file is
158
 * rewritten using the supplied source map. Note: The resolution for the
159
 * resulting mappings is the minimium of this map and the supplied map.
160
 *
161
 * @param aSourceMapConsumer The source map to be applied.
162
 * @param aSourceFile Optional. The filename of the source file.
163
 *        If omitted, SourceMapConsumer's file property will be used.
164
 * @param aSourceMapPath Optional. The dirname of the path to the source map
165
 *        to be applied. If relative, it is relative to the SourceMapConsumer.
166
 *        This parameter is needed when the two source maps aren't in the same
167
 *        directory, and the source map to be applied contains relative source
168
 *        paths. If so, those relative source paths need to be rewritten
169
 *        relative to the SourceMapGenerator.
170
 */
171
SourceMapGenerator.prototype.applySourceMap =
172
  function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) {
173
    var sourceFile = aSourceFile;
174
    // If aSourceFile is omitted, we will use the file property of the SourceMap
175
    if (aSourceFile == null) {
176
      if (aSourceMapConsumer.file == null) {
177
        throw new Error(
178
          'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' +
179
          'or the source map\'s "file" property. Both were omitted.'
180
        );
181
      }
182
      sourceFile = aSourceMapConsumer.file;
183
    }
184
    var sourceRoot = this._sourceRoot;
185
    // Make "sourceFile" relative if an absolute Url is passed.
186
    if (sourceRoot != null) {
187
      sourceFile = util.relative(sourceRoot, sourceFile);
188
    }
189
    // Applying the SourceMap can add and remove items from the sources and
190
    // the names array.
191
    var newSources = new ArraySet();
192
    var newNames = new ArraySet();
193
194
    // Find mappings for the "sourceFile"
195
    this._mappings.unsortedForEach(function (mapping) {
196
      if (mapping.source === sourceFile && mapping.originalLine != null) {
197
        // Check if it can be mapped by the source map, then update the mapping.
198
        var original = aSourceMapConsumer.originalPositionFor({
199
          line: mapping.originalLine,
200
          column: mapping.originalColumn
201
        });
202
        if (original.source != null) {
203
          // Copy mapping
204
          mapping.source = original.source;
205
          if (aSourceMapPath != null) {
206
            mapping.source = util.join(aSourceMapPath, mapping.source)
207
          }
208
          if (sourceRoot != null) {
209
            mapping.source = util.relative(sourceRoot, mapping.source);
210
          }
211
          mapping.originalLine = original.line;
212
          mapping.originalColumn = original.column;
213
          if (original.name != null) {
214
            mapping.name = original.name;
215
          }
216
        }
217
      }
218
219
      var source = mapping.source;
220
      if (source != null && !newSources.has(source)) {
221
        newSources.add(source);
222
      }
223
224
      var name = mapping.name;
225
      if (name != null && !newNames.has(name)) {
226
        newNames.add(name);
227
      }
228
229
    }, this);
230
    this._sources = newSources;
231
    this._names = newNames;
232
233
    // Copy sourcesContents of applied map.
234
    aSourceMapConsumer.sources.forEach(function (sourceFile) {
235
      var content = aSourceMapConsumer.sourceContentFor(sourceFile);
236
      if (content != null) {
237
        if (aSourceMapPath != null) {
238
          sourceFile = util.join(aSourceMapPath, sourceFile);
239
        }
240
        if (sourceRoot != null) {
241
          sourceFile = util.relative(sourceRoot, sourceFile);
242
        }
243
        this.setSourceContent(sourceFile, content);
244
      }
245
    }, this);
246
  };
247
248
/**
249
 * A mapping can have one of the three levels of data:
250
 *
251
 *   1. Just the generated position.
252
 *   2. The Generated position, original position, and original source.
253
 *   3. Generated and original position, original source, as well as a name
254
 *      token.
255
 *
256
 * To maintain consistency, we validate that any new mapping being added falls
257
 * in to one of these categories.
258
 */
259
SourceMapGenerator.prototype._validateMapping =
260
  function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource,
261
                                              aName) {
262
    // When aOriginal is truthy but has empty values for .line and .column,
263
    // it is most likely a programmer error. In this case we throw a very
264
    // specific error message to try to guide them the right way.
265
    // For example: https://github.com/Polymer/polymer-bundler/pull/519
266
    if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') {
267
        throw new Error(
268
            'original.line and original.column are not numbers -- you probably meant to omit ' +
269
            'the original mapping entirely and only map the generated position. If so, pass ' +
270
            'null for the original mapping instead of an object with empty or null values.'
271
        );
272
    }
273
274
    if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
275
        && aGenerated.line > 0 && aGenerated.column >= 0
276
        && !aOriginal && !aSource && !aName) {
277
      // Case 1.
278
      return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
279
    }
280
    else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated
281
             && aOriginal && 'line' in aOriginal && 'column' in aOriginal
282
             && aGenerated.line > 0 && aGenerated.column >= 0
283
             && aOriginal.line > 0 && aOriginal.column >= 0
284
             && aSource) {
285
      // Cases 2 and 3.
286
      return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
287
    }
288
    else {
289
      throw new Error('Invalid mapping: ' + JSON.stringify({
290
        generated: aGenerated,
291
        source: aSource,
292
        original: aOriginal,
293
        name: aName
294
      }));
295
    }
296
  };
297
298
/**
299
 * Serialize the accumulated mappings in to the stream of base 64 VLQs
300
 * specified by the source map format.
301
 */
302
SourceMapGenerator.prototype._serializeMappings =
303
  function SourceMapGenerator_serializeMappings() {
304
    var previousGeneratedColumn = 0;
305
    var previousGeneratedLine = 1;
306
    var previousOriginalColumn = 0;
307
    var previousOriginalLine = 0;
308
    var previousName = 0;
309
    var previousSource = 0;
310
    var result = '';
311
    var next;
312
    var mapping;
313
    var nameIdx;
314
    var sourceIdx;
315
316
    var mappings = this._mappings.toArray();
317
    for (var i = 0, len = mappings.length; i < len; i++) {
318
      mapping = mappings[i];
319
      next = ''
320
321
      if (mapping.generatedLine !== previousGeneratedLine) {
322
        previousGeneratedColumn = 0;
323
        while (mapping.generatedLine !== previousGeneratedLine) {
324
          next += ';';
325
          previousGeneratedLine++;
326
        }
327
      }
328
      else {
329
        if (i > 0) {
330
          if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) {
331
            continue;
332
          }
333
          next += ',';
334
        }
335
      }
336
337
      next += base64VLQ.encode(mapping.generatedColumn
338
                                 - previousGeneratedColumn);
339
      previousGeneratedColumn = mapping.generatedColumn;
340
341
      if (mapping.source != null) {
342
        sourceIdx = this._sources.indexOf(mapping.source);
343
        next += base64VLQ.encode(sourceIdx - previousSource);
344
        previousSource = sourceIdx;
345
346
        // lines are stored 0-based in SourceMap spec version 3
347
        next += base64VLQ.encode(mapping.originalLine - 1
348
                                   - previousOriginalLine);
349
        previousOriginalLine = mapping.originalLine - 1;
350
351
        next += base64VLQ.encode(mapping.originalColumn
352
                                   - previousOriginalColumn);
353
        previousOriginalColumn = mapping.originalColumn;
354
355
        if (mapping.name != null) {
356
          nameIdx = this._names.indexOf(mapping.name);
357
          next += base64VLQ.encode(nameIdx - previousName);
358
          previousName = nameIdx;
359
        }
360
      }
361
362
      result += next;
363
    }
364
365
    return result;
366
  };
367
368
SourceMapGenerator.prototype._generateSourcesContent =
369
  function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) {
370
    return aSources.map(function (source) {
371
      if (!this._sourcesContents) {
372
        return null;
373
      }
374
      if (aSourceRoot != null) {
375
        source = util.relative(aSourceRoot, source);
376
      }
377
      var key = util.toSetString(source);
378
      return Object.prototype.hasOwnProperty.call(this._sourcesContents, key)
379
        ? this._sourcesContents[key]
380
        : null;
381
    }, this);
382
  };
383
384
/**
385
 * Externalize the source map.
386
 */
387
SourceMapGenerator.prototype.toJSON =
388
  function SourceMapGenerator_toJSON() {
389
    var map = {
390
      version: this._version,
391
      sources: this._sources.toArray(),
392
      names: this._names.toArray(),
393
      mappings: this._serializeMappings()
394
    };
395
    if (this._file != null) {
396
      map.file = this._file;
397
    }
398
    if (this._sourceRoot != null) {
399
      map.sourceRoot = this._sourceRoot;
400
    }
401
    if (this._sourcesContents) {
402
      map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot);
403
    }
404
405
    return map;
406
  };
407
408
/**
409
 * Render the source map being generated to a string.
410
 */
411
SourceMapGenerator.prototype.toString =
412
  function SourceMapGenerator_toString() {
413
    return JSON.stringify(this.toJSON());
414
  };
415
416
exports.SourceMapGenerator = SourceMapGenerator;
417