UNPKG

6.45 kBJavaScriptView Raw
1var util = require('util');
2var fs = require('fs');
3var FileInstrumenter = require("./file-instrumenter");
4var MarkupFileParser = require("../markup-files-parser");
5var FILE_INSTRUMENTATION_ERROR_MESSAGE = "Failed during instrumentation file ";
6var FILE_WRITING_ERROR_MESSAGE = "Failed while writing instrumented file.";
7var FILE_READING_ERROR_MESSAGE = "Failed reading file contents.";
8
9function MarkupFileInstrumenter() {
10 FileInstrumenter.apply(this, arguments);
11 this.originalFile = "";
12 this.instrumentedFile = "";
13 this.scriptTags = [];
14 this.errorLoggingMessage = "";
15 this.fiileHandler = null;
16}
17
18util.inherits(MarkupFileInstrumenter, FileInstrumenter);
19module.exports = MarkupFileInstrumenter;
20
21/*
22 This class used for instrumenting markup files (i.e: html, ftl).
23 The instrumentation works by combine all the js code in the file, instrument it in one piece, then split it back to original script tags
24*/
25MarkupFileInstrumenter.prototype._instrumentFile = function (inputFile, outputFile, name, preambleHeader, callback) {
26 this.logger.debug("Instrumenting file '" + inputFile + "'.");
27 try {
28 this._extractScripts(inputFile);
29 if(!this._hasJsInFile()) {
30 return this._handleFileWithoutJS(outputFile, name, callback);
31 }
32 this._markScripts();
33 return this._instrumentAndReplace(name, inputFile, outputFile, callback);
34 } catch (err) {
35 return this._handleInstrumentationError(this.errorLoggingMessage, err, name, callback);
36 }
37};
38
39MarkupFileInstrumenter.prototype._extractScripts = function(inputFile) {
40 this.errorLoggingMessage = FILE_READING_ERROR_MESSAGE;
41 var fileContents = fs.readFileSync(inputFile, 'utf8');
42 fileContents = this._onBeforeInstrumentation(fileContents);
43 this.originalFile = fileContents;
44 this.instrumentedFile = fileContents;
45 this.fileParser = getFileParser(fileContents, inputFile, this.logger);
46 this.scriptTags = cloneTagsArray(this.fileParser.scriptTags);
47}
48
49MarkupFileInstrumenter.prototype.instrumentationCallback = function (err, instrumentedContent, outputFile, name, callback) {
50 if (err) {
51 throw err;
52 }
53 this._replaceOldJsByInstrumented(instrumentedContent);
54 this._insertCoverageCodeTag(instrumentedContent);
55 this._insertPreambleTag();
56 this.instrumentedFile = this._onAfterInstrumentation(this.instrumentedFile);
57 return this._saveFileContent(outputFile, name, callback);
58}
59
60MarkupFileInstrumenter.prototype._instrumentAndReplace = function(name, inputFile, outputFile, callback) {
61 var _this = this;
62 var jsCode = this.fileParser.getAllJsInFile();
63 this.errorLoggingMessage = FILE_INSTRUMENTATION_ERROR_MESSAGE + name;
64 this.instrumenter.instrument(jsCode, inputFile, function (err, instrumentedContent) {
65 return _this.instrumentationCallback(err, instrumentedContent, outputFile, name, callback);
66 }, {
67 filename: name,
68 inputSourceMap: null
69 });
70}
71
72MarkupFileInstrumenter.prototype._replaceOldJsByInstrumented = function(instrumentedContent){
73 for (var i = 0; i < this.scriptTags.length; i++) {
74 var currentTag = this.scriptTags[i];
75 var scriptMarker = createScriptMarker(i);
76 var scriptStartIndex = instrumentedContent.indexOf(scriptMarker);
77 scriptStartIndex += scriptMarker.length;
78 var scriptEndIndex = instrumentedContent.lastIndexOf(scriptMarker);
79 var instrumentedScript = instrumentedContent.substring(scriptStartIndex, scriptEndIndex);
80 this.instrumentedFile = this.instrumentedFile.replace(currentTag.content, instrumentedScript);
81 }
82}
83
84MarkupFileInstrumenter.prototype._saveFileContent = function(outputFile, name, callback) {
85 if (this.opts.onFileInstrumented != null) {
86 this.opts.onFileInstrumented(name);
87 }
88 this.errorLoggingMessage = FILE_WRITING_ERROR_MESSAGE;
89 fs.writeFileSync(outputFile, this.instrumentedFile, 'utf8');
90 return callback(null, name);
91}
92
93MarkupFileInstrumenter.prototype._handleFileWithoutJS = function (outputFile, name, callback) {
94 if (this.opts.onFileCopied != null) {
95 this.opts.onFileCopied(name);
96 }
97 return this._saveFileContent(outputFile, name, callback);
98}
99
100MarkupFileInstrumenter.prototype._hasJsInFile = function() {
101 return this.scriptTags.length !== 0 && isJSEmbeddedInFile(this.fileParser);
102}
103
104MarkupFileInstrumenter.prototype._insertCoverageCodeTag = function(instrumentedCode){
105 var firstTagMarker = createScriptMarker(0);
106 var firstTagStart = instrumentedCode.indexOf(firstTagMarker);
107 var istanbulCoverageCode = instrumentedCode.substring(0, firstTagStart);
108 var coverageCodeTag = "<script>\n\t" + istanbulCoverageCode + "\n</script>\n";
109 this.instrumentedFile = this._insertTagAtBeginning(coverageCodeTag);
110}
111
112MarkupFileInstrumenter.prototype._insertPreambleTag = function() {
113 var preambleTag = "<script>\n\t" + this.preambleHeader.join("\n") + "\n</script>\n";
114 this.instrumentedFile = this._insertTagAtBeginning(preambleTag);
115};
116
117MarkupFileInstrumenter.prototype._markScripts = function(){
118 var marked = [];
119 for (var i = 0; i < this.fileParser.scriptTags.length; i++) {
120 var slComment = createScriptMarker(i);
121 var currentTag = this.fileParser.scriptTags[i];
122 currentTag.content = slComment + currentTag.content + slComment;
123 marked.push(currentTag);
124 }
125 this.fileParser.scriptTags = marked;
126}
127
128MarkupFileInstrumenter.prototype._insertTagAtBeginning = function(newTag) {
129 var firstScriptTagIndex = this.instrumentedFile.search(/<script[\s\S]*?>/);
130 return this.instrumentedFile.slice(0, firstScriptTagIndex) + newTag +
131 this.instrumentedFile.slice(firstScriptTagIndex);
132};
133
134function getFileParser(fileContents, inputFile, logger) {
135 var handler = new MarkupFileParser(fileContents, inputFile, logger);
136 handler.extractScriptTags();
137 return handler;
138}
139
140
141// Checks if the js code is inside file or loaded from external js file (ie <script src="..."></script>).
142function isJSEmbeddedInFile(fileParser) {
143 return fileParser.getAllJsInFile() !== "";
144}
145
146
147function createScriptMarker(index) {
148 return "/********** SL tag no " + index + " **********/"
149}
150
151/*
152 Because we add mark comments to tag scripts we want to save the original without any changes so we implement deep copy.
153 */
154function cloneTagsArray(tagsArray){
155 return JSON.parse(JSON.stringify( tagsArray));
156}
157
158