Skip to content

Commit 4119fdd

Browse files
committed
Merge pull request #875 from abrobston/sourcemap-wrap
Account for wrap config in sourcemap generation
2 parents cfe00a9 + 983d82a commit 4119fdd

File tree

10 files changed

+301
-77
lines changed

10 files changed

+301
-77
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ build/tests/lib/sourcemap/www-built
9393
build/tests/lib/sourcemap/onejs/www/js/built.js
9494
build/tests/lib/sourcemap/onejs/www/js/built.js.map
9595
build/tests/lib/sourcemap/twojs/www-built
96+
build/tests/lib/sourcemapWrap/built
9697
build/tests/lib/stubModules/create/foobar-built.js
9798
build/tests/lib/stubModules/main-built.js
9899
build/tests/lib/stubModules/perModule/built

build/jslib/build.js

Lines changed: 145 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ define(function (require) {
103103
return dirName;
104104
}
105105

106+
function endsWithNewLine(text) {
107+
if (text.charAt(text.length - 1) !== "\n") {
108+
text += "\n";
109+
}
110+
return text;
111+
}
112+
106113
//Method used by plugin writeFile calls, defined up here to avoid
107114
//jslint warning about "making a function in a loop".
108115
function makeWriteFile(namespace, layer) {
@@ -119,6 +126,75 @@ define(function (require) {
119126
return writeFile;
120127
}
121128

129+
/**
130+
* Appends singleContents to fileContents and returns the result. If a sourceMapGenerator
131+
* is provided, adds singleContents to the source map.
132+
*
133+
* @param {string} fileContents - The file contents to which to append singleContents
134+
* @param {string} singleContents - The additional contents to append to fileContents
135+
* @param {string} path - An absolute path of a file whose name to use in the source map.
136+
* The file need not actually exist if the code in singleContents is generated.
137+
* @param {{out: ?string, baseUrl: ?string}} config - The build configuration object.
138+
* @param {?{_buildPath: ?string}} module - An object with module information.
139+
* @param {?SourceMapGenerator} sourceMapGenerator - An instance of Mozilla's SourceMapGenerator,
140+
* or null if no source map is being generated.
141+
* @returns {string} fileContents with singleContents appended
142+
*/
143+
function appendToFileContents(fileContents, singleContents, path, config, module, sourceMapGenerator) {
144+
var refPath, sourceMapPath, resourcePath, pluginId, sourceMapLineNumber, lineCount, parts, i;
145+
if (sourceMapGenerator) {
146+
if (config.out) {
147+
refPath = config.baseUrl;
148+
} else if (module && module._buildPath) {
149+
refPath = module._buildPath;
150+
} else {
151+
refPath = "";
152+
}
153+
parts = path.split('!');
154+
if (parts.length === 1) {
155+
//Not a plugin resource, fix the path
156+
sourceMapPath = build.makeRelativeFilePath(refPath, path);
157+
} else {
158+
//Plugin resource. If it looks like just a plugin
159+
//followed by a module ID, pull off the plugin
160+
//and put it at the end of the name, otherwise
161+
//just leave it alone.
162+
pluginId = parts.shift();
163+
resourcePath = parts.join('!');
164+
if (resourceIsModuleIdRegExp.test(resourcePath)) {
165+
sourceMapPath = build.makeRelativeFilePath(refPath, require.toUrl(resourcePath)) +
166+
'!' + pluginId;
167+
} else {
168+
sourceMapPath = path;
169+
}
170+
}
171+
172+
sourceMapLineNumber = fileContents.split('\n').length - 1;
173+
lineCount = singleContents.split('\n').length;
174+
for (i = 1; i <= lineCount; i += 1) {
175+
sourceMapGenerator.addMapping({
176+
generated: {
177+
line: sourceMapLineNumber + i,
178+
column: 0
179+
},
180+
original: {
181+
line: i,
182+
column: 0
183+
},
184+
source: sourceMapPath
185+
});
186+
}
187+
188+
//Store the content of the original in the source
189+
//map since other transforms later like minification
190+
//can mess up translating back to the original
191+
//source.
192+
sourceMapGenerator.setSourceContent(sourceMapPath, singleContents);
193+
}
194+
fileContents += singleContents;
195+
return fileContents;
196+
}
197+
122198
/**
123199
* Main API entry point into the build. The args argument can either be
124200
* an array of arguments (like the onese passed on a command-line),
@@ -989,22 +1065,37 @@ define(function (require) {
9891065
* Converts a wrap.startFile or endFile to be start/end as a string.
9901066
* the startFile/endFile values can be arrays.
9911067
*/
992-
function flattenWrapFile(wrap, keyName, absFilePath) {
993-
var keyFileName = keyName + 'File';
1068+
function flattenWrapFile(config, keyName, absFilePath) {
1069+
var wrap = config.wrap,
1070+
keyFileName = keyName + 'File',
1071+
keyMapName = '__' + keyName + 'Map';
9941072

9951073
if (typeof wrap[keyName] !== 'string' && wrap[keyFileName]) {
9961074
wrap[keyName] = '';
9971075
if (typeof wrap[keyFileName] === 'string') {
9981076
wrap[keyFileName] = [wrap[keyFileName]];
9991077
}
1078+
wrap[keyMapName] = [];
10001079
wrap[keyFileName].forEach(function (fileName) {
1001-
wrap[keyName] += (wrap[keyName] ? '\n' : '') +
1002-
file.readFile(build.makeAbsPath(fileName, absFilePath));
1080+
var absPath = build.makeAbsPath(fileName, absFilePath),
1081+
fileText = endsWithNewLine(file.readFile(absPath));
1082+
wrap[keyMapName].push(function (fileContents, cfg, sourceMapGenerator) {
1083+
return appendToFileContents(fileContents, fileText, absPath, cfg, null, sourceMapGenerator);
1084+
});
1085+
wrap[keyName] += fileText;
10031086
});
10041087
} else if (wrap[keyName] === null || wrap[keyName] === undefined) {
10051088
//Allow missing one, just set to empty string.
10061089
wrap[keyName] = '';
1007-
} else if (typeof wrap[keyName] !== 'string') {
1090+
} else if (typeof wrap[keyName] === 'string') {
1091+
wrap[keyName] = endsWithNewLine(wrap[keyName]);
1092+
wrap[keyMapName] = [
1093+
function (fileContents, cfg, sourceMapGenerator) {
1094+
var absPath = build.makeAbsPath("config-wrap-" + keyName + "-default.js", absFilePath);
1095+
return appendToFileContents(fileContents, wrap[keyName], absPath, cfg, null, sourceMapGenerator);
1096+
}
1097+
];
1098+
} else {
10081099
throw new Error('wrap.' + keyName + ' or wrap.' + keyFileName + ' malformed');
10091100
}
10101101
}
@@ -1016,12 +1107,27 @@ define(function (require) {
10161107
if (config.wrap === true) {
10171108
//Use default values.
10181109
config.wrap = {
1019-
start: '(function () {',
1020-
end: '}());'
1110+
start: '(function () {\n',
1111+
end: '}());',
1112+
__startMap: [
1113+
function (fileContents, cfg, sourceMapGenerator) {
1114+
return appendToFileContents(fileContents, "(function () {\n",
1115+
build.makeAbsPath("config-wrap-start-default.js",
1116+
absFilePath), cfg, null,
1117+
sourceMapGenerator);
1118+
}
1119+
],
1120+
__endMap: [
1121+
function (fileContents, cfg, sourceMapGenerator) {
1122+
return appendToFileContents(fileContents, "}());",
1123+
build.makeAbsPath("config-wrap-end-default.js", absFilePath),
1124+
cfg, null, sourceMapGenerator);
1125+
}
1126+
]
10211127
};
10221128
} else {
1023-
flattenWrapFile(config.wrap, 'start', absFilePath);
1024-
flattenWrapFile(config.wrap, 'end', absFilePath);
1129+
flattenWrapFile(config, 'start', absFilePath);
1130+
flattenWrapFile(config, 'end', absFilePath);
10251131
}
10261132
}
10271133
} catch (wrapError) {
@@ -1781,11 +1887,16 @@ define(function (require) {
17811887
});
17821888

17831889
//Write the built module to disk, and build up the build output.
1784-
fileContents = config.wrap ? config.wrap.start : "";
1890+
fileContents = "";
1891+
if (config.wrap && config.wrap.__startMap) {
1892+
config.wrap.__startMap.forEach(function (wrapFunction) {
1893+
fileContents = wrapFunction(fileContents, config, sourceMapGenerator);
1894+
});
1895+
}
1896+
17851897
return prim.serial(layer.buildFilePaths.map(function (path) {
17861898
return function () {
1787-
var lineCount,
1788-
singleContents = '';
1899+
var singleContents = '';
17891900

17901901
moduleName = layer.buildFileToModule[path];
17911902

@@ -1882,9 +1993,7 @@ define(function (require) {
18821993
});
18831994
}
18841995
}).then(function () {
1885-
var refPath, pluginId, resourcePath, shimDeps,
1886-
sourceMapPath, sourceMapLineNumber,
1887-
shortPath = path.replace(config.dir, "");
1996+
var shimDeps, shortPath = path.replace(config.dir, "");
18881997

18891998
module.onCompleteData.included.push(shortPath);
18901999
buildFileContents += shortPath + "\n";
@@ -1931,66 +2040,24 @@ define(function (require) {
19312040
//for concatenation would cause an error otherwise.
19322041
singleContents += '\n';
19332042

1934-
//Add to the source map
1935-
if (sourceMapGenerator) {
1936-
refPath = config.out ? config.baseUrl : module._buildPath;
1937-
parts = path.split('!');
1938-
if (parts.length === 1) {
1939-
//Not a plugin resource, fix the path
1940-
sourceMapPath = build.makeRelativeFilePath(refPath, path);
1941-
} else {
1942-
//Plugin resource. If it looks like just a plugin
1943-
//followed by a module ID, pull off the plugin
1944-
//and put it at the end of the name, otherwise
1945-
//just leave it alone.
1946-
pluginId = parts.shift();
1947-
resourcePath = parts.join('!');
1948-
if (resourceIsModuleIdRegExp.test(resourcePath)) {
1949-
sourceMapPath = build.makeRelativeFilePath(refPath, require.toUrl(resourcePath)) +
1950-
'!' + pluginId;
1951-
} else {
1952-
sourceMapPath = path;
1953-
}
1954-
}
1955-
1956-
sourceMapLineNumber = fileContents.split('\n').length - 1;
1957-
lineCount = singleContents.split('\n').length;
1958-
for (var i = 1; i <= lineCount; i += 1) {
1959-
sourceMapGenerator.addMapping({
1960-
generated: {
1961-
line: sourceMapLineNumber + i,
1962-
column: 0
1963-
},
1964-
original: {
1965-
line: i,
1966-
column: 0
1967-
},
1968-
source: sourceMapPath
1969-
});
1970-
}
1971-
1972-
//Store the content of the original in the source
1973-
//map since other transforms later like minification
1974-
//can mess up translating back to the original
1975-
//source.
1976-
sourceMapGenerator.setSourceContent(sourceMapPath, singleContents);
1977-
}
1978-
1979-
//Add the file to the final contents
1980-
fileContents += singleContents;
2043+
//Add to the source map and to the final contents
2044+
fileContents = appendToFileContents(fileContents, singleContents, path, config, module,
2045+
sourceMapGenerator);
19812046
});
19822047
};
19832048
})).then(function () {
19842049
if (onLayerEnds.length) {
1985-
onLayerEnds.forEach(function (builder) {
2050+
onLayerEnds.forEach(function (builder, index) {
19862051
var path;
19872052
if (typeof module.out === 'string') {
19882053
path = module.out;
19892054
} else if (typeof module._buildPath === 'string') {
19902055
path = module._buildPath;
19912056
}
19922057
builder.onLayerEnd(function (input) {
1993-
fileContents += "\n" + addSemiColon(input, config);
2058+
fileContents =
2059+
appendToFileContents(fileContents, "\n" + addSemiColon(input, config),
2060+
'onLayerEnd' + index + '.js', config, module, sourceMapGenerator);
19942061
}, {
19952062
name: module.name,
19962063
path: path
@@ -2003,21 +2070,30 @@ define(function (require) {
20032070
//a module definition for it in case the
20042071
//built file is used with enforceDefine
20052072
//(#432)
2006-
fileContents += '\n' + namespaceWithDot + 'define("' + module.name + '", function(){});\n';
2073+
fileContents =
2074+
appendToFileContents(fileContents, '\n' + namespaceWithDot + 'define("' + module.name +
2075+
'", function(){});\n', 'module-create.js', config, module,
2076+
sourceMapGenerator);
20072077
}
20082078

20092079
//Add a require at the end to kick start module execution, if that
20102080
//was desired. Usually this is only specified when using small shim
20112081
//loaders like almond.
20122082
if (module.insertRequire) {
2013-
fileContents += '\n' + namespaceWithDot + 'require(["' + module.insertRequire.join('", "') + '"]);\n';
2083+
fileContents =
2084+
appendToFileContents(fileContents, '\n' + namespaceWithDot + 'require(["' + module.insertRequire.join('", "') +
2085+
'"]);\n', 'module-insertRequire.js', config, module,
2086+
sourceMapGenerator);
20142087
}
20152088
});
20162089
}).then(function () {
2090+
if (config.wrap && config.wrap.__endMap) {
2091+
config.wrap.__endMap.forEach(function (wrapFunction) {
2092+
fileContents = wrapFunction(fileContents, config, sourceMapGenerator);
2093+
});
2094+
}
20172095
return {
2018-
text: config.wrap ?
2019-
fileContents + config.wrap.end :
2020-
fileContents,
2096+
text: fileContents,
20212097
buildText: buildFileContents,
20222098
sourceMap: sourceMapGenerator ?
20232099
JSON.stringify(sourceMapGenerator.toJSON(), null, ' ') :

0 commit comments

Comments
 (0)