BuildTools/djsbuildfile.js (138 lines of code) (raw):

/// <reference path="djscommon.js" /> // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. var markerFormats = {}; markerFormats[".js"] = "// MARKER"; markerFormats[".html"] = "<!-- MARKER -->"; markerFormats[".htm"] = markerFormats[".html"]; function MakeMarker(ext, marker) { /// <summary>Builds the appropriate marker string based on the file extension.</summary> /// <param name="ext" type="String">Extension of the file for which the marker string is going to be generated.</param> /// <param name="marker" type="String">Text to be contained in the marker.</param> /// <returns type="String">Specific marker string.</returns> var format = markerFormats[ext.toLowerCase()]; if (format) { return format.replace("MARKER", marker); } return null; } function BuildFromProject(path, outBasePath) { // Read the csproj. WScript.Echo("Reading project " + path); var xml = new ActiveXObject("Msxml2.DOMDocument.6.0"); xml.load(path); xml.setProperty("SelectionNamespaces", "xmlns:msb='http://schemas.microsoft.com/developer/msbuild/2003'"); xml.setProperty("SelectionLanguage", "XPath"); var files = xml.selectNodes("//msb:ItemGroup/*[not(self::msb:Reference)]/@Include"); var fileIncludes = {}; var i, len, filePath; // Get file dependencies. for (i = 0, len = files.length; i < len; i++) { filePath = PathCombine(PathGetDirectory(path), files[i].value); if (FileExists(filePath)) { var includes = GetFileIncludes(filePath); var j, includeLen; for (j = 0, includeLen = includes.length; j < includeLen; j++) { fileIncludes[includes[j]] = {}; } } else if (!FolderExists(filePath)) { throw { message: "path doesn't exist " + filePath }; } } // Build the files that are not in the dependency list. for (i = 0, len = files.length; i < len; i++) { filePath = PathCombine(PathGetDirectory(path), files[i].value); var outputPath = PathCombine(outBasePath, files[i].value); if (!fileIncludes[filePath] && !FolderExists(filePath)) { BuildFile(filePath, outputPath); } } } function GetFileIncludes(path) { var content = ReadAllTextFile(path); var lines = StringSplit(content, "\r\n"); var result = []; var i, len; for (i = 0, len = lines.length; i < len; i++) { var line = lines[i]; var includeIndex = line.indexOf("// INCLUDE:"); if (includeIndex !== -1) { var anotherPath = line.substr(includeIndex + 11); anotherPath = anotherPath.replace(/^\s+|\s+$/g, ""); if (!FileExists(anotherPath)) { anotherPath = PathGetDirectory(path) + "\\" + anotherPath; } result.push(GetFileIncludes(anotherPath)); result.push(anotherPath); } } return result; } // TODO: provide support for composing relative paths. function BuildFromSln(path, outBasePath) { WScript.Echo("Reading solution " + path); var outPath = PathCombine(outBasePath, PathGetFileName(path)); var regEx = /(Project\("[^"]+"\)\s*=\s*)"([^"]+)"\s*,\s*"([^"]+)"/; var content = ReadAllTextFile(path); var lines = StringSplit(content, "\r\n"); var i, len; for (i = 0, len = lines.length; i < len; i++) { var matches = regEx.exec(lines[i]); if (matches) { var projectPath = PathCombine(PathGetDirectory(path), matches[3]); BuildFromProject(projectPath, outPath); } } } function BuildFile(path, outPath) { /// <summary>Builds a JavaScript file. </summary> /// <param name="path" type="String">Path to the file whose content is going to be built.</param> /// <param name="outPath" type="String">Path of the built file.</param> if (!FileExists(path)) { throw { message: "File does not exist: " + inName }; } CreateFolderIfMissing(PathGetDirectory(outPath)); switch (PathGetExtension(path).toLowerCase()) { case ".js": case ".htm": case ".html": WScript.Echo("building file: " + path); var built = BuildFileForContent(path, false); SaveTextToFile(built, outPath); break; default: WScript.Echo("copying file: " + path); CopyFile(path, outPath, true); break; } } function BuildFileForContent(path, contentOnly) { var ext = PathGetExtension(path); var includeCallback = function (line, inContent) { var includeIndex = line.indexOf(MakeMarker(ext, "INCLUDE: ")); if (includeIndex !== -1) { var anotherPath = line.substr(includeIndex + 11); anotherPath = anotherPath.replace(/^\s+|\s+$/g, ""); if (!FileExists(anotherPath)) { anotherPath = PathGetDirectory(path) + "\\" + anotherPath; } return BuildFileForContent(anotherPath, true); } else { return (inContent) ? line : null; } }; return ExtractContentsBetweenMarkers(path, contentOnly, /*isExclusion*/ false, MakeMarker(ext, "CONTENT START"), MakeMarker(ext, "CONTENT END"), includeCallback); } function RemoveInternals(inName, outName) { var ext = PathGetExtension(inName); var includeCallback = function (line, inContent) { return (line.indexOf("djsassert") === -1) ? line : null; }; var content = ExtractContentsBetweenMarkers(inName, true, /*isExclusion*/ true, MakeMarker(ext, "DATAJS INTERNAL START"), MakeMarker(ext, "DATAJS INTERNAL END"), includeCallback); SaveTextToFile(content, outName); } RunAndQuit(function () { var args = WScript.Arguments; var inName = WScript.Arguments.Unnamed(0); if (!inName) { throw { message: "no input specified" }; } var outName = WScript.Arguments.Named("out"); if (!outName) { throw { message: "no output specified" }; } if (CheckScriptFlag("build-solution")) { BuildFromSln(inName, outName); } if (CheckScriptFlag("remove-internals")) { RemoveInternals(inName, outName); } });