UNPKG

grunt-ts

Version:

Compile and manage your TypeScript project

328 lines 14.9 kB
'use strict'; var es6_promise_1 = require('es6-promise'); var fs = require('fs'); var path = require('path'); var stripBom = require('strip-bom'); var _ = require('lodash'); var utils = require('./utils'); var templateProcessor = null; var globExpander = null; var gruntfileGlobs = null; var absolutePathToTSConfig; function resolveAsync(applyTo, taskOptions, targetOptions, theTemplateProcessor, theGlobExpander) { if (theGlobExpander === void 0) { theGlobExpander = null; } templateProcessor = theTemplateProcessor; globExpander = theGlobExpander; gruntfileGlobs = getGlobs(taskOptions, targetOptions); return new es6_promise_1.Promise(function (resolve, reject) { try { var taskTSConfig = getTSConfigSettings(taskOptions); var targetTSConfig = getTSConfigSettings(targetOptions); var tsconfig = null; if (taskTSConfig) { tsconfig = taskTSConfig; } if (targetTSConfig) { if (!tsconfig) { tsconfig = targetTSConfig; } if ('tsconfig' in targetTSConfig) { tsconfig.tsconfig = templateProcessor(targetTSConfig.tsconfig, {}); } if ('ignoreSettings' in targetTSConfig) { tsconfig.ignoreSettings = targetTSConfig.ignoreSettings; } if ('overwriteFilesGlob' in targetTSConfig) { tsconfig.overwriteFilesGlob = targetTSConfig.overwriteFilesGlob; } if ('updateFiles' in targetTSConfig) { tsconfig.updateFiles = targetTSConfig.updateFiles; } if ('passThrough' in targetTSConfig) { tsconfig.passThrough = targetTSConfig.passThrough; } } applyTo.tsconfig = tsconfig; } catch (ex) { return reject(ex); } if (!applyTo.tsconfig) { return resolve(applyTo); } if (applyTo.tsconfig.passThrough) { if (applyTo.CompilationTasks.length === 0) { applyTo.CompilationTasks.push({ src: [] }); } if (!applyTo.tsconfig.tsconfig) { applyTo.tsconfig.tsconfig = '.'; } } else { var projectFile = applyTo.tsconfig.tsconfig; try { var projectFileTextContent = fs.readFileSync(projectFile, 'utf8'); } catch (ex) { if (ex && ex.code === 'ENOENT') { return reject('Could not find file "' + projectFile + '".'); } else if (ex && ex.errno) { return reject('Error ' + ex.errno + ' reading "' + projectFile + '".'); } else { return reject('Error reading "' + projectFile + '": ' + JSON.stringify(ex)); } return reject(ex); } try { var projectSpec; var content = stripBom(projectFileTextContent); if (content.trim() === '') { projectSpec = {}; } else { projectSpec = JSON.parse(content); } } catch (ex) { return reject('Error parsing "' + projectFile + '". It may not be valid JSON in UTF-8.'); } applyTo = warnOnBadConfiguration(applyTo, projectSpec); applyTo = applyCompilerOptions(applyTo, projectSpec); applyTo = resolve_output_locations(applyTo, projectSpec); } resolve(applyTo); }); } exports.resolveAsync = resolveAsync; function warnOnBadConfiguration(options, projectSpec) { if (projectSpec.compilerOptions) { if (projectSpec.compilerOptions.out && projectSpec.compilerOptions.outFile) { options.warnings.push('Warning: `out` and `outFile` should not be used together in tsconfig.json.'); } if (projectSpec.compilerOptions.out) { options.warnings.push('Warning: Using `out` in tsconfig.json can be unreliable because it will output relative' + ' to the tsc working directory. It is better to use `outFile` which is always relative to tsconfig.json, ' + ' but this requires TypeScript 1.6 or higher.'); } } return options; } function getGlobs(taskOptions, targetOptions) { var globs = null; if (taskOptions && taskOptions.src) { globs = taskOptions.src; } if (targetOptions && targetOptions.src) { globs = targetOptions.src; } return globs; } function resolve_output_locations(options, projectSpec) { if (options.CompilationTasks && options.CompilationTasks.length > 0 && projectSpec && projectSpec.compilerOptions) { options.CompilationTasks.forEach(function (compilationTask) { if (projectSpec.compilerOptions.out) { compilationTask.out = path.normalize(projectSpec.compilerOptions.out).replace(/\\/g, '/'); } if (projectSpec.compilerOptions.outFile) { compilationTask.out = path.normalize(path.join(relativePathFromGruntfileToTSConfig(), projectSpec.compilerOptions.outFile)).replace(/\\/g, '/'); } if (projectSpec.compilerOptions.outDir) { compilationTask.outDir = path.normalize(path.join(relativePathFromGruntfileToTSConfig(), projectSpec.compilerOptions.outDir)).replace(/\\/g, '/'); } }); } return options; } function getTSConfigSettings(raw) { try { if (!raw || !raw.tsconfig) { return null; } if (typeof raw.tsconfig === 'boolean') { return { tsconfig: path.join(path.resolve('.'), 'tsconfig.json') }; } else if (typeof raw.tsconfig === 'string') { var tsconfigName = templateProcessor(raw.tsconfig, {}); var fileInfo = fs.lstatSync(tsconfigName); if (fileInfo.isDirectory()) { tsconfigName = path.join(tsconfigName, 'tsconfig.json'); } return { tsconfig: tsconfigName }; } return raw.tsconfig; } catch (ex) { if (ex.code === 'ENOENT') { throw ex; } var exception = { name: 'Invalid tsconfig setting', message: 'Exception due to invalid tsconfig setting. Details: ' + ex, code: ex.code, errno: ex.errno }; throw exception; } } function applyCompilerOptions(applyTo, projectSpec) { var result = applyTo || {}; var co = projectSpec.compilerOptions; var tsconfig = applyTo.tsconfig; if (!tsconfig.ignoreSettings && co) { var sameNameInTSConfigAndGruntTS = ['declaration', 'emitDecoratorMetadata', 'experimentalAsyncFunctions', 'experimentalDecorators', 'isolatedModules', 'inlineSourceMap', 'inlineSources', 'jsx', 'mapRoot', 'module', 'moduleResolution', 'newLine', 'noEmit', 'noEmitHelpers', 'noEmitOnError', 'noImplicitAny', 'noLib', 'noResolve', 'out', 'outDir', 'preserveConstEnums', 'removeComments', 'rootDir', 'sourceMap', 'sourceRoot', 'suppressImplicitAnyIndexErrors', 'target']; sameNameInTSConfigAndGruntTS.forEach(function (propertyName) { if ((propertyName in co) && !(propertyName in result)) { result[propertyName] = co[propertyName]; } }); // now copy the ones that don't have the same names. // `outFile` was added in TypeScript 1.6 and is the same as out for command-line // purposes except that `outFile` is relative to the tsconfig.json. if (('outFile' in co) && !('out' in result)) { result['out'] = co['outFile']; } } if (!('updateFiles' in tsconfig)) { tsconfig.updateFiles = true; } if (applyTo.CompilationTasks.length === 0) { applyTo.CompilationTasks.push({ src: [] }); } var src = applyTo.CompilationTasks[0].src; absolutePathToTSConfig = path.resolve(tsconfig.tsconfig, '..'); if (tsconfig.overwriteFilesGlob) { if (!gruntfileGlobs) { throw new Error('The tsconfig option overwriteFilesGlob is set to true, but no glob was passed-in.'); } var relPath = relativePathFromGruntfileToTSConfig(); var gruntGlobsRelativeToTSConfig = []; for (var i = 0; i < gruntfileGlobs.length; i += 1) { gruntfileGlobs[i] = gruntfileGlobs[i].replace(/\\/g, '/'); gruntGlobsRelativeToTSConfig.push(path.relative(relPath, gruntfileGlobs[i]).replace(/\\/g, '/')); } if (_.difference(projectSpec.filesGlob, gruntGlobsRelativeToTSConfig).length > 0 || _.difference(gruntGlobsRelativeToTSConfig, projectSpec.filesGlob).length > 0) { projectSpec.filesGlob = gruntGlobsRelativeToTSConfig; if (projectSpec.files) { projectSpec.files = []; } saveTSConfigSync(tsconfig.tsconfig, projectSpec); } } if (tsconfig.updateFiles && projectSpec.filesGlob) { if (projectSpec.files === undefined) { projectSpec.files = []; } updateTSConfigAndFilesFromGlob(projectSpec.files, projectSpec.filesGlob, tsconfig.tsconfig); } if (projectSpec.files) { addUniqueRelativeFilesToSrc(projectSpec.files, src, absolutePathToTSConfig); } else { if (!globExpander.isStub) { var virtualGlob = []; if (projectSpec.exclude && _.isArray(projectSpec.exclude)) { virtualGlob.push(path.resolve(absolutePathToTSConfig, './*.ts')); virtualGlob.push(path.resolve(absolutePathToTSConfig, './*.tsx')); var tsconfigExcludedDirectories = []; projectSpec.exclude.forEach(function (exc) { tsconfigExcludedDirectories.push(path.normalize(path.join(absolutePathToTSConfig, exc))); }); fs.readdirSync(absolutePathToTSConfig).forEach(function (item) { var filePath = path.normalize(path.join(absolutePathToTSConfig, item)); if (fs.statSync(filePath).isDirectory()) { if (tsconfigExcludedDirectories.indexOf(filePath) === -1) { virtualGlob.push(path.resolve(absolutePathToTSConfig, item, './**/*.ts')); virtualGlob.push(path.resolve(absolutePathToTSConfig, item, './**/*.tsx')); } } }); } else { virtualGlob.push(path.resolve(absolutePathToTSConfig, './**/*.ts')); virtualGlob.push(path.resolve(absolutePathToTSConfig, './**/*.tsx')); } var files = globExpander(virtualGlob); // make files relative to the tsconfig.json file for (var i = 0; i < files.length; i += 1) { files[i] = path.relative(absolutePathToTSConfig, files[i]).replace(/\\/g, '/'); } projectSpec.files = files; if (projectSpec.filesGlob) { saveTSConfigSync(tsconfig.tsconfig, projectSpec); } addUniqueRelativeFilesToSrc(files, src, absolutePathToTSConfig); } } return result; } function relativePathFromGruntfileToTSConfig() { if (!absolutePathToTSConfig) { throw 'attempt to get relative path to tsconfig.json before setting absolute path'; } return path.relative('.', absolutePathToTSConfig).replace(/\\/g, '/'); } function updateTSConfigAndFilesFromGlob(filesRelativeToTSConfig, globRelativeToTSConfig, tsconfigFileName) { if (globExpander.isStub) { return; } var absolutePathToTSConfig = path.resolve(tsconfigFileName, '..'); var filesGlobRelativeToGruntfile = []; for (var i = 0; i < globRelativeToTSConfig.length; i += 1) { filesGlobRelativeToGruntfile.push(path.relative(path.resolve('.'), path.join(absolutePathToTSConfig, globRelativeToTSConfig[i]))); } var filesRelativeToGruntfile = globExpander(filesGlobRelativeToGruntfile); { var filesRelativeToTSConfig_temp = []; var relativePathFromGruntfileToTSConfig_1 = path.relative('.', absolutePathToTSConfig).replace(/\\/g, '/'); for (var i = 0; i < filesRelativeToGruntfile.length; i += 1) { filesRelativeToGruntfile[i] = filesRelativeToGruntfile[i].replace(/\\/g, '/'); filesRelativeToTSConfig_temp.push(path.relative(relativePathFromGruntfileToTSConfig_1, filesRelativeToGruntfile[i]).replace(/\\/g, '/')); } filesRelativeToTSConfig.length = 0; filesRelativeToTSConfig.push.apply(filesRelativeToTSConfig, filesRelativeToTSConfig_temp); } var tsconfigJSONContent = utils.readAndParseJSONFromFileSync(tsconfigFileName); var tempTSConfigFiles = tsconfigJSONContent.files || []; if (_.difference(tempTSConfigFiles, filesRelativeToTSConfig).length > 0 || _.difference(filesRelativeToTSConfig, tempTSConfigFiles).length > 0) { try { tsconfigJSONContent.files = filesRelativeToTSConfig; saveTSConfigSync(tsconfigFileName, tsconfigJSONContent); } catch (ex) { var error = new Error('Error updating tsconfig.json: ' + ex); throw error; } } } function saveTSConfigSync(fileName, content) { fs.writeFileSync(fileName, JSON.stringify(content, null, ' ')); } function addUniqueRelativeFilesToSrc(tsconfigFilesArray, compilationTaskSrc, absolutePathToTSConfig) { var gruntfileFolder = path.resolve('.'); _.map(_.uniq(tsconfigFilesArray), function (file) { var absolutePathToFile = path.normalize(path.join(absolutePathToTSConfig, file)); var relativePathToFileFromGruntfile = path.relative(gruntfileFolder, absolutePathToFile).replace(new RegExp('\\' + path.sep, 'g'), '/'); if (compilationTaskSrc.indexOf(absolutePathToFile) === -1 && compilationTaskSrc.indexOf(relativePathToFileFromGruntfile) === -1) { compilationTaskSrc.push(relativePathToFileFromGruntfile); } }); } //# sourceMappingURL=tsconfig.js.map