UNPKG

csproj2ts

Version:

Library to parse TypeScript config info from a Visual Studio Project file

382 lines (381 loc) 24.3 kB
"use strict"; var fs = require("fs"); var xml2js = require("xml2js"); var _ = require("lodash"); var path = require("path"); var es6_promise_1 = require("es6-promise"); var semver = require("semver"); var csproj2ts; (function (csproj2ts) { csproj2ts.DEFAULT_TYPESCRIPT_VERSION = "2.5.3"; var cboolean = function (value) { return (typeof value === 'string') ? (value.toLowerCase() === 'true') : value; }; var getSettingOrDefault = function (item, abbreviatedSettingName, defaultValue) { if (item["TypeScript" + abbreviatedSettingName]) { return item["TypeScript" + abbreviatedSettingName][0]; } return defaultValue; }; csproj2ts.fixVersion = function (version) { var testVersion = version + ""; if (!testVersion) { return csproj2ts.DEFAULT_TYPESCRIPT_VERSION; } if (testVersion.indexOf("-") > -1) { var versionInfo = testVersion.split("-"); testVersion = versionInfo[0]; } if (semver.valid(testVersion)) { return testVersion; } testVersion += ".0"; if (semver.valid(testVersion)) { return testVersion; } testVersion += ".0"; if (semver.valid(testVersion)) { return testVersion; } return csproj2ts.DEFAULT_TYPESCRIPT_VERSION; }; var getTSSetting = function (project, abbreviatedSettingName, projectConfiguration, projectPlatform, defaultValue) { var typeOfGrouping = "PropertyGroup"; var result = defaultValue; if (project[typeOfGrouping]) { var items = toArray(project[typeOfGrouping]); _.map(items, function (item) { if (item["$"] && item["$"]["Condition"]) { var condition = item["$"]["Condition"]; condition = condition.replace(/ /g, ""); if (condition === "'$(Configuration)'=='" + projectConfiguration + "'" || condition === "'$(Configuration)|$(Platform)'=='" + projectConfiguration + "|" + projectPlatform + "'") { result = getSettingOrDefault(item, abbreviatedSettingName, result); } } else { result = getSettingOrDefault(item, abbreviatedSettingName, result); } }); } return result; }; csproj2ts.xml2jsReadXMLFile = function (fileName) { return new es6_promise_1.Promise(function (resolve, reject) { var parser = new xml2js.Parser(); parser.addListener('end', function (parsedXMLFileResult) { resolve(parsedXMLFileResult); }); fs.readFile(fileName, function (err, data) { if (err && err.errno !== 0) { reject(err); } else { parser.parseString(data); } }); }); }; csproj2ts.getTypeScriptSettings = function (projectInfo) { if (!projectInfo.MSBuildExtensionsPath32) { projectInfo.MSBuildExtensionsPath32 = path.join(csproj2ts.programFiles(), "/MSBuild/"); } return new es6_promise_1.Promise(function (resolve, reject) { csproj2ts.xml2jsReadXMLFile(projectInfo.ProjectFileName).then(function (parsedVSProject) { if (!parsedVSProject || !parsedVSProject.Project) { reject(new Error("No result from parsing the project.")); } else { var project = parsedVSProject.Project; var projectDefaultConfig = getDefaultConfiguration(project); var projectDefaultPlatform = getDefaultPlatform(project); var projectActiveConfig = projectInfo.ActiveConfiguration || projectDefaultConfig; var projectActivePlat = projectInfo.ActivePlatform || projectDefaultPlatform; var result = { VSProjectDetails: { DefaultProjectConfiguration: projectDefaultConfig, DefaultProjectPlatform: projectDefaultPlatform, DefaultVisualStudioVersion: getDefaultVisualStudioVersion(project), TypeScriptDefaultPropsFilePath: getTypeScriptDefaultPropsFilePath(project), ActiveConfiguration: projectInfo.ActiveConfiguration, ActivePlatform: projectInfo.ActivePlatform, MSBuildExtensionsPath32: projectInfo.MSBuildExtensionsPath32, ProjectFileName: projectInfo.ProjectFileName, VisualStudioVersion: projectInfo.VisualStudioVersion, TypeScriptVersion: csproj2ts.fixVersion(projectInfo.TypeScriptVersion) }, files: getTypeScriptFilesToCompile(project), AdditionalFlags: getTSSetting(project, "AdditionalFlags", projectActiveConfig, projectActivePlat, undefined), AllowJS: cboolean(getTSSetting(project, "AllowJS", projectActiveConfig, projectActivePlat, undefined)), AllowSyntheticDefaultImports: cboolean(getTSSetting(project, "AllowSyntheticDefaultImports", projectActiveConfig, projectActivePlat, undefined)), AllowUnreachableCode: cboolean(getTSSetting(project, "AllowUnreachableCode", projectActiveConfig, projectActivePlat, undefined)), AllowUnusedLabels: cboolean(getTSSetting(project, "AllowUnusedLabels", projectActiveConfig, projectActivePlat, undefined)), AlwaysStrict: cboolean(getTSSetting(project, "AlwaysStrict", projectActiveConfig, projectActivePlat, undefined)), BaseUrl: getTSSetting(project, "BaseUrl", projectActiveConfig, projectActivePlat, undefined), Charset: getTSSetting(project, "Charset", projectActiveConfig, projectActivePlat, undefined), CheckJs: cboolean(getTSSetting(project, "CheckJs", projectActiveConfig, projectActivePlat, undefined)), CodePage: getTSSetting(project, "CodePage", projectActiveConfig, projectActivePlat, undefined), CompileBlocked: getTSSetting(project, "CompileBlocked", projectActiveConfig, projectActivePlat, false), CompileOnSaveEnabled: cboolean(getTSSetting(project, "CompileOnSaveEnabled", projectActiveConfig, projectActivePlat, undefined)), DeclarationDir: getTSSetting(project, "DeclarationDir", projectActiveConfig, projectActivePlat, undefined), DownlevelIteration: cboolean(getTSSetting(project, "DownlevelIteration", projectActiveConfig, projectActivePlat, undefined)), EmitBOM: cboolean(getTSSetting(project, "EmitBOM", projectActiveConfig, projectActivePlat, undefined)), EmitDecoratorMetadata: cboolean(getTSSetting(project, "EmitDecoratorMetadata", projectActiveConfig, projectActivePlat, undefined)), ESModuleInterop: cboolean(getTSSetting(project, "ESModuleInterop", projectActiveConfig, projectActivePlat, undefined)), ExperimentalAsyncFunctions: cboolean(getTSSetting(project, "ExperimentalAsyncFunctions", projectActiveConfig, projectActivePlat, undefined)), ExperimentalDecorators: cboolean(getTSSetting(project, "ExperimentalDecorators", projectActiveConfig, projectActivePlat, undefined)), ForceConsistentCasingInFileNames: cboolean(getTSSetting(project, "ForceConsistentCasingInFileNames", projectActiveConfig, projectActivePlat, undefined)), GeneratesDeclarations: cboolean(getTSSetting(project, "GeneratesDeclarations", projectActiveConfig, projectActivePlat, undefined)), ImportHelpers: cboolean(getTSSetting(project, "ImportHelpers", projectActiveConfig, projectActivePlat, undefined)), InlineSourceMap: cboolean(getTSSetting(project, "InlineSourceMap", projectActiveConfig, projectActivePlat, undefined)), InlineSources: cboolean(getTSSetting(project, "InlineSources", projectActiveConfig, projectActivePlat, undefined)), IsolatedModules: cboolean(getTSSetting(project, "IsolatedModules", projectActiveConfig, projectActivePlat, undefined)), JSXEmit: getTSSetting(project, "JSXEmit", projectActiveConfig, projectActivePlat, undefined), JSXFactory: getTSSetting(project, "JSXFactory", projectActiveConfig, projectActivePlat, undefined), Lib: getTSSetting(project, "Lib", projectActiveConfig, projectActivePlat, undefined), MapRoot: getTSSetting(project, "MapRoot", projectActiveConfig, projectActivePlat, undefined), ModuleKind: getTSSetting(project, "ModuleKind", projectActiveConfig, projectActivePlat, undefined), ModuleResolution: getTSSetting(project, "ModuleResolution", projectActiveConfig, projectActivePlat, undefined), NewLine: getTSSetting(project, "NewLine", projectActiveConfig, projectActivePlat, undefined), NoEmitHelpers: cboolean(getTSSetting(project, "NoEmitHelpers", projectActiveConfig, projectActivePlat, undefined)), NoEmitOnError: cboolean(getTSSetting(project, "NoEmitOnError", projectActiveConfig, projectActivePlat, undefined)), NoFallthroughCasesInSwitch: cboolean(getTSSetting(project, "NoFallthroughCasesInSwitch", projectActiveConfig, projectActivePlat, undefined)), NoImplicitAny: cboolean(getTSSetting(project, "NoImplicitAny", projectActiveConfig, projectActivePlat, undefined)), NoImplicitThis: cboolean(getTSSetting(project, "NoImplicitThis", projectActiveConfig, projectActivePlat, undefined)), NoImplicitReturns: cboolean(getTSSetting(project, "NoImplicitReturns", projectActiveConfig, projectActivePlat, undefined)), NoImplicitUseStrict: cboolean(getTSSetting(project, "NoImplicitUseStrict", projectActiveConfig, projectActivePlat, undefined)), NoLib: cboolean(getTSSetting(project, "NoLib", projectActiveConfig, projectActivePlat, undefined)), NoResolve: cboolean(getTSSetting(project, "NoResolve", projectActiveConfig, projectActivePlat, undefined)), NoStrictGenericChecks: cboolean(getTSSetting(project, "NoStrictGenericChecks", projectActiveConfig, projectActivePlat, undefined)), NoUnusedLocals: cboolean(getTSSetting(project, "NoUnusedLocals", projectActiveConfig, projectActivePlat, undefined)), NoUnusedParameters: cboolean(getTSSetting(project, "NoUnusedParameters", projectActiveConfig, projectActivePlat, undefined)), OutDir: getTSSetting(project, "OutDir", projectActiveConfig, projectActivePlat, undefined), OutFile: getTSSetting(project, "OutFile", projectActiveConfig, projectActivePlat, undefined), PreferredUILang: getTSSetting(project, "PreferredUILang", projectActiveConfig, projectActivePlat, undefined), PreserveConstEnums: cboolean(getTSSetting(project, "PreserveConstEnums", projectActivePlat, projectActiveConfig, undefined)), PreserveSymlinks: cboolean(getTSSetting(project, "PreserveSymlinks", projectActiveConfig, projectActivePlat, undefined)), ReactNamespace: getTSSetting(project, "ReactNamespace", projectActiveConfig, projectActivePlat, undefined), RemoveComments: cboolean(getTSSetting(project, "RemoveComments", projectActiveConfig, projectActivePlat, undefined)), RootDir: getTSSetting(project, "RootDir", projectActiveConfig, projectActivePlat, undefined), SkipDefaultLibCheck: cboolean(getTSSetting(project, "SkipDefaultLibCheck", projectActiveConfig, projectActivePlat, undefined)), SkipLibCheck: cboolean(getTSSetting(project, "SkipLibCheck", projectActiveConfig, projectActivePlat, undefined)), SourceMap: cboolean(getTSSetting(project, "SourceMap", projectActiveConfig, projectActivePlat, undefined)), SourceRoot: getTSSetting(project, "SourceRoot", projectActiveConfig, projectActivePlat, undefined), Strict: cboolean(getTSSetting(project, "Strict", projectActiveConfig, projectActivePlat, undefined)), StrictFunctionTypes: cboolean(getTSSetting(project, "StrictFunctionTypes", projectActiveConfig, projectActivePlat, undefined)), StrictNullChecks: cboolean(getTSSetting(project, "StrictNullChecks", projectActiveConfig, projectActivePlat, undefined)), StrictPropertyInitialization: cboolean(getTSSetting(project, "StrictPropertyInitialization", projectActiveConfig, projectActivePlat, undefined)), SuppressImplicitAnyIndexErrors: cboolean(getTSSetting(project, "SuppressImplicitAnyIndexErrors", projectActiveConfig, projectActivePlat, undefined)), SuppressExcessPropertyErrors: cboolean(getTSSetting(project, "SuppressExcessPropertyErrors", projectActiveConfig, projectActivePlat, undefined)), Target: getTSSetting(project, "Target", projectActiveConfig, projectActivePlat, undefined) }; ["OutDir", "OutFile", "SourceRoot", "RootDir", "MapRoot"].forEach(function (item) { if (result[item]) { result[item] = result[item].replace(/\\/g, "/"); } }); csproj2ts.getTypeScriptDefaultsFromPropsFileOrDefaults(result) .then(function (typeScriptDefaults) { result.VSProjectDetails.TypeScriptDefaultConfiguration = typeScriptDefaults; finishUp(typeScriptDefaults); }).catch(function (error) { var fallbackDefaults = VSTypeScriptDefaults(result.VSProjectDetails.TypeScriptVersion); result.VSProjectDetails.TypeScriptDefaultConfiguration = fallbackDefaults; finishUp(fallbackDefaults); }); var finishUp = function (defaults) { _.forOwn(result, function (value, key) { if (_.isNull(value) || _.isUndefined(value)) { result[key] = defaults[key]; } }); resolve(result); }; } }, function (error) { reject(error); }); }); }; csproj2ts.normalizePath = function (path, settings) { if (path.indexOf("$(VisualStudioVersion)") > -1) { path = path.replace(/\$\(VisualStudioVersion\)/g, settings.VSProjectDetails.VisualStudioVersion || settings.VSProjectDetails.DefaultVisualStudioVersion); } if (path.indexOf("$(MSBuildExtensionsPath32)") > -1) { path = path.replace(/\$\(MSBuildExtensionsPath32\)/g, settings.VSProjectDetails.MSBuildExtensionsPath32); } return path; }; var toArray = function (itemOrArray) { if (_.isArray(itemOrArray)) { return itemOrArray; } else { return [itemOrArray]; } }; var getImports = function (project) { var result = []; if (project.Import) { var importItems = toArray(project.Import); _.map(importItems, function (item) { if (item["$"]) { result.push(item["$"]); } }); } return result; }; var getVSConfigDefault = function (project, typeOfGrouping, nodeName, defaultCondition) { var result = ""; if (project[typeOfGrouping]) { var items = toArray(project[typeOfGrouping]); _.map(items, function (item) { if (item[nodeName] && _.isArray(item[nodeName]) && item[nodeName].length > 0) { var subitem = item[nodeName][0]["$"]; if (subitem.Condition) { var condition = subitem.Condition.replace(/ /g, ''); if (defaultCondition.indexOf(condition) > -1 || !defaultCondition) { result = item[nodeName][0]["_"] + ""; } } } }); } return result; }; var getDefaultVisualStudioVersion = function (project) { return getVSConfigDefault(project, "PropertyGroup", "VisualStudioVersion", "'$(VisualStudioVersion)'==''"); }; var getDefaultConfiguration = function (project) { return getVSConfigDefault(project, "PropertyGroup", "Configuration", "'$(Configuration)'==''"); }; var getDefaultPlatform = function (project) { return getVSConfigDefault(project, "PropertyGroup", "Platform", "'$(Platform)'==''"); }; var getTypeScriptFilesToCompile = function (project) { var typeOfGrouping = "ItemGroup"; var result = []; var osPath; if (project[typeOfGrouping]) { var items = toArray(project[typeOfGrouping]); _.map(items, function (item) { if (item["TypeScriptCompile"]) { _.map(toArray(item["TypeScriptCompile"]), function (compileItem) { if (compileItem["$"] && compileItem["$"]["Include"]) { osPath = compileItem["$"]["Include"].replace(/\\/g, "/"); result.push(osPath); } }); } }); } return result; }; var getTypeScriptDefaultPropsFilePath = function (project) { var typeOfGrouping = "Import"; var result = ""; if (project[typeOfGrouping]) { var items = toArray(project[typeOfGrouping]); _.map(items, function (item) { if (item["$"] && item["$"]["Project"]) { var projectValue = item["$"]["Project"]; if (projectValue.indexOf("Microsoft.TypeScript.Default.props") > -1) { result = projectValue; } } }); } return result; }; function getFirstValueOrDefault(item, defaultValue) { if (item && _.isArray(item) && item.length > 0 && !_.isNull(item[0]) && !_.isUndefined(item[0])) { if (typeof defaultValue === "boolean") { return cboolean(item[0]); } return item[0]; } return defaultValue; } var highestVisualStudioVersionToTestFor = function () { var currentYear = new Date().getFullYear(); return currentYear - 1995; }; var minimumVisualStudioVersion = 10; var findPropsFileName = function (settings) { return new es6_promise_1.Promise(function (resolve, reject) { var propsFileName = csproj2ts.normalizePath(settings.VSProjectDetails.TypeScriptDefaultPropsFilePath, settings); if (fs.existsSync(propsFileName)) { resolve(propsFileName); return; } var alternateSettings = _.cloneDeep(settings); for (var i = highestVisualStudioVersionToTestFor(); i >= minimumVisualStudioVersion; i -= 1) { alternateSettings.VSProjectDetails.VisualStudioVersion = i.toString() + ".0"; propsFileName = csproj2ts.normalizePath(settings.VSProjectDetails.TypeScriptDefaultPropsFilePath, alternateSettings); if (fs.existsSync(propsFileName)) { resolve(propsFileName); return; } } reject(new Error("Could not find a valid props file.")); }); }; csproj2ts.getTypeScriptDefaultsFromPropsFileOrDefaults = function (settings) { return new es6_promise_1.Promise(function (resolve, reject) { findPropsFileName(settings).then(function (propsFileName) { csproj2ts.xml2jsReadXMLFile(propsFileName).then(function (parsedPropertiesFile) { if (!parsedPropertiesFile || !parsedPropertiesFile.Project || !parsedPropertiesFile.Project.PropertyGroup) { reject(new Error("No result from parsing the project.")); } else { var pg = toArray(parsedPropertiesFile.Project.PropertyGroup)[0]; var result = {}; var def = VSTypeScriptDefaults(settings.VSProjectDetails.TypeScriptVersion); result.Target = getFirstValueOrDefault(pg.TypeScriptTarget, def.Target); result.CompileOnSaveEnabled = getFirstValueOrDefault(pg.TypeScriptCompileOnSaveEnabled, def.CompileOnSaveEnabled); result.NoImplicitAny = getFirstValueOrDefault(pg.TypeScriptNoImplicitAny, def.NoImplicitAny); result.ModuleKind = getFirstValueOrDefault(pg.TypeScriptModuleKind, def.ModuleKind); result.RemoveComments = getFirstValueOrDefault(pg.TypeScriptRemoveComments, def.RemoveComments); result.OutFile = getFirstValueOrDefault(pg.TypeScriptOutFile, def.OutFile); result.OutDir = getFirstValueOrDefault(pg.TypeScriptOutDir, def.OutDir); result.GeneratesDeclarations = getFirstValueOrDefault(pg.TypeScriptGeneratesDeclarations, def.GeneratesDeclarations); result.SourceMap = getFirstValueOrDefault(pg.TypeScriptSourceMap, def.SourceMap); result.MapRoot = getFirstValueOrDefault(pg.TypeScript, def.MapRoot); result.SourceRoot = getFirstValueOrDefault(pg.TypeScriptSourceRoot, def.SourceRoot); result.NoEmitOnError = getFirstValueOrDefault(pg.TypeScript, def.NoEmitOnError); resolve(result); } }, function (error) { reject(error); }); }, function (error) { reject(error); }); }); }; var VSTypeScriptDefaults = function (version) { if (!version) { version = csproj2ts.DEFAULT_TYPESCRIPT_VERSION; } var target = semver.lt(version, "1.5.0") ? "ES3" : "ES5"; var noEmitOnError = semver.gte(version, "1.4.0"); var dev = { Target: target, CompileOnSaveEnabled: false, NoImplicitAny: false, ModuleKind: "", RemoveComments: false, OutFile: "", OutDir: "", GeneratesDeclarations: false, SourceMap: false, MapRoot: "", SourceRoot: "", NoEmitOnError: noEmitOnError }; return dev; }; csproj2ts.programFiles = function () { return process.env["ProgramFiles(x86)"] || process.env["ProgramFiles"] || ""; }; })(csproj2ts || (csproj2ts = {})); module.exports = csproj2ts;