blob: 903a2149a366a3470631b4cc200b46bac6b03d49 [file] [log] [blame]
/*
Helper for dealing with Windows Store JS app .jsproj files
*/
var xml_helpers = require('./xml-helpers'),
et = require('elementtree'),
fs = require('fs'),
shell = require('shelljs'),
events = require('../events'),
path = require('path');
var WindowsStoreProjectTypeGUID = "{BC8A1FFA-BEE3-4634-8014-F334798102B3}"; // any of the below, subtype
var WinCSharpProjectTypeGUID = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"; // .csproj
var WinVBnetProjectTypeGUID = "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"; // who the ef cares?
var WinCplusplusProjectTypeGUID = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"; // .vcxproj
function jsproj(location) {
events.emit('verbose','creating jsproj from project at : ' + location);
this.location = location;
this.xml = xml_helpers.parseElementtreeSync(location);
return this;
}
jsproj.prototype = {
location:null,
xml:null,
plugins_dir:"Plugins",
write:function() {
fs.writeFileSync(this.location, this.xml.write({indent:4}), 'utf-8');
},
// add/remove the item group for SDKReference
// example :
// <ItemGroup><SDKReference Include="Microsoft.VCLibs, version=12.0" /></ItemGroup>
addSDKRef:function(incText) {
var item_group = new et.Element('ItemGroup');
var elem = new et.Element('SDKReference');
elem.attrib.Include = incText;
item_group.append(elem);
this.xml.getroot().append(item_group);
},
removeSDKRef:function(incText) {
var item_group = this.xml.find('ItemGroup/SDKReference[@Include="' + incText + '"]/..');
if(item_group) { // TODO: error handling
this.xml.getroot().remove(0, item_group);
}
},
addReference:function(relPath,src) {
events.emit('verbose','addReference::' + relPath);
var item = new et.Element('ItemGroup');
var extName = path.extname(relPath);
var elem = new et.Element('Reference');
// add file name
elem.attrib.Include = path.basename(relPath, extName);
// add hint path with full path
var hint_path = new et.Element('HintPath');
hint_path.text = relPath;
elem.append(hint_path);
if(extName == ".winmd") {
var mdFileTag = new et.Element("IsWinMDFile");
mdFileTag.text = "true";
elem.append(mdFileTag);
}
item.append(elem);
this.xml.getroot().append(item);
},
removeReference:function(relPath) {
events.emit('verbose','removeReference::' + relPath);
var extName = path.extname(relPath);
var includeText = path.basename(relPath,extName);
// <ItemGroup>
// <Reference Include="WindowsRuntimeComponent1">
var item_group = this.xml.find('ItemGroup/Reference[@Include="' + includeText + '"]/..');
if(item_group) { // TODO: erro handling
this.xml.getroot().remove(0, item_group);
}
},
addSourceFile:function(relative_path) {
relative_path = relative_path.split('/').join('\\');
// make ItemGroup to hold file.
var item = new et.Element('ItemGroup');
var content = new et.Element('Content');
content.attrib.Include = relative_path;
item.append(content);
this.xml.getroot().append(item);
},
removeSourceFile:function(relative_path) {
// path.normalize(relative_path);// ??
relative_path = relative_path.split('/').join('\\');
// var oneStep = this.xml.findall('ItemGroup/Content[@Include="' + relative_path + '""]/..');
var item_groups = this.xml.findall('ItemGroup');
for (var i = 0, l = item_groups.length; i < l; i++) {
var group = item_groups[i];
var files = group.findall('Content');
for (var j = 0, k = files.length; j < k; j++) {
var file = files[j];
if (file.attrib.Include == relative_path) {
// remove file reference
group.remove(0, file);
// remove ItemGroup if empty
var new_group = group.findall('Content');
if(new_group.length < 1) {
this.xml.getroot().remove(0, group);
}
return true;
}
}
}
return false;
},
// relative path must include the project file, so we can determine .csproj, .jsproj, .vcxproj...
addProjectReference:function(relative_path) {
events.emit('verbose','adding project reference to ' + relative_path);
relative_path = relative_path.split('/').join('\\');
// read the solution path from the base directory
var solutionPath = shell.ls(path.join(path.dirname(this.location),"*.sln"))[0];// TODO:error handling
// note we may not have a solution, in which case just add a project reference, I guess ..
// get the project extension to figure out project type
var projectExt = path.extname(relative_path);
var pluginProjectXML = xml_helpers.parseElementtreeSync(relative_path);
// find the guid + name of the referenced project
var projectGuid = pluginProjectXML.find("PropertyGroup/ProjectGuid").text;
var projName = pluginProjectXML.find("PropertyGroup/ProjectName").text;
var preInsertText = "ProjectSection(ProjectDependencies) = postProject\n\r" +
projectGuid + "=" + projectGuid + "\n\r" +
"EndProjectSection\n\r";
// read in the solution file
var solText = fs.readFileSync(solutionPath,{encoding:"utf8"});
var splitText = solText.split("EndProject");
if(splitText.length != 2) {
throw new Error("too many projects in solution.");
}
var projectTypeGuid = null;
if(projectExt == ".vcxproj") {
projectTypeGuid = WinCplusplusProjectTypeGUID;
}
else if(projectExt == ".csproj") {
projectTypeGuid = WinCSharpProjectTypeGUID;
}
if(!projectTypeGuid) {
throw new Error("unrecognized project type");
}
var postInsertText = 'Project("' + projectTypeGuid + '") = "' +
projName + '", "' + relative_path + '",' +
'"' + projectGuid + '"\n\r EndProject\n\r';
solText = splitText[0] + preInsertText + "EndProject\n\r" + postInsertText + splitText[1];
fs.writeFileSync(solutionPath,solText,{encoding:"utf8"});
// Add the ItemGroup/ProjectReference to the cordova project :
// <ItemGroup><ProjectReference Include="blahblah.csproj"/></ItemGroup>
var item = new et.Element('ItemGroup');
var projRef = new et.Element('ProjectReference');
projRef.attrib.Include = relative_path;
item.append(projRef);
this.xml.getroot().append(item);
},
removeProjectReference:function(relative_path) {
events.emit('verbose','removing project reference to ' + relative_path);
// find the guid + name of the referenced project
var pluginProjectXML = xml_helpers.parseElementtreeSync(relative_path);
var projectGuid = pluginProjectXML.find("PropertyGroup/ProjectGuid").text;
var projName = pluginProjectXML.find("PropertyGroup/ProjectName").text;
// get the project extension to figure out project type
var projectExt = path.extname(relative_path);
// get the project type
var projectTypeGuid = null;
if(projectExt == ".vcxproj") {
projectTypeGuid = WinCplusplusProjectTypeGUID;
}
else if(projectExt == ".csproj") {
projectTypeGuid = WinCSharpProjectTypeGUID;
}
if(!projectTypeGuid) {
throw new Error("unrecognized project type");
}
var preInsertText = "ProjectSection(ProjectDependencies) = postProject\n\r" +
projectGuid + "=" + projectGuid + "\n\r" +
"EndProjectSection\n\r";
var postInsertText = 'Project("' + projectTypeGuid + '") = "' +
projName + '", "' + relative_path + '",' +
'"' + projectGuid + '"\n\r EndProject\n\r';
// find and read in the solution file
var solutionPath = shell.ls(path.join(path.dirname(this.location),"*.sln"))[0]; // TODO:error handling
var solText = fs.readFileSync(solutionPath,{encoding:"utf8"});
var splitText = solText.split(preInsertText);
solText = splitText.join("").split(postInsertText);
solText = solText.join("");
fs.writeFileSync(solutionPath,solText,{encoding:"utf8"});
// select first ItemsGroups with a ChildNode ProjectReference
// ideally select all, and look for @attrib 'Include'= projectFullPath
var projectRefNodesPar = this.xml.find("ItemGroup/ProjectReference[@Include='" + relative_path + "']/..");
if(projectRefNodesPar) {
this.xml.getroot().remove(0, projectRefNodesPar);
}
}
};
module.exports = jsproj;