diff --git a/lib/main.ts b/lib/main.ts index 2a6ce9ba..ed00c553 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -46,9 +46,7 @@ function getTypeScript(typescript: typeof ts) { } } -function getCompilerOptions(settings: compile.Settings, projectPath: string, configFileName: string): ts.CompilerOptions { - let typescript = getTypeScript(settings.typescript); - +function checkAndNormalizeSettings(settings: compile.Settings): void { if (settings.sourceRoot !== undefined) { console.warn('gulp-typescript: sourceRoot isn\'t supported any more. Use sourceRoot option of gulp-sourcemaps instead.') } @@ -64,33 +62,30 @@ function getCompilerOptions(settings: compile.Settings, projectPath: string, con "The non-standard option sortOutput has been removed as of gulp-typescript 3.0.\nYour project will probably compile without this option.\nOtherwise, if you're using gulp-concat, you should remove gulp-concat and use the outFile option instead."); } - // Copy settings and remove several options - const newSettings: compile.Settings = {}; - for (const option of Object.keys(settings)) { - if (option === 'declarationFiles') { - newSettings.declaration = settings.declarationFiles; - continue; - } - if (option === 'noExternalResolve' || - option === 'sortOutput' || - option === 'typescript' || - option === 'sourceMap' || - option === 'inlineSourceMap' || - option === 'sourceRoot' || - option === 'inlineSources') continue; - - newSettings[option] = settings[option]; + if (settings.declarationFiles) { + settings.declaration = settings.declarationFiles; + delete settings.declarationFiles; } - const result = typescript.convertCompilerOptionsFromJson(newSettings, projectPath, configFileName); + delete settings.noExternalResolve; + delete settings.sortOutput; + delete settings.typescript; + delete (settings as any).sourceMap; + delete (settings as any).inlineSourceMap; + delete settings.sourceRoot; + delete (settings as any).inlineSources; +} + +function normalizeCompilerOptions(options: ts.CompilerOptions): void { + options.sourceMap = true; + (options as any).suppressOutputPathCheck = true; +} + +function reportErrors(errors: ts.Diagnostic[], typescript: typeof ts): void { const reporter = _reporter.defaultReporter(); - for (const error of result.errors) { + for (const error of errors) { reporter.error(utils.getError(error, typescript), typescript); } - result.options.sourceMap = true; - (result.options as any).suppressOutputPathCheck = true; - - return result.options; } module compile { @@ -149,36 +144,59 @@ module compile { let tsConfigFileName: string = undefined; let tsConfigContent: TsConfig = undefined; let projectDirectory = process.cwd(); + let typescript; + let compilerOptions: ts.CompilerOptions; + let fileName: string; + settings = { ...settings }; // Shallow copy the settings. if (fileNameOrSettings !== undefined) { if (typeof fileNameOrSettings === 'string') { + fileName = fileNameOrSettings; + } else { + settings = fileNameOrSettings || {}; + } + + typescript = getTypeScript(settings.typescript); + checkAndNormalizeSettings(settings); + + const settingsResult = typescript.convertCompilerOptionsFromJson(settings, projectDirectory); + + if (settingsResult.errors) { + reportErrors(settingsResult.errors, typescript); + } + + compilerOptions = settingsResult.options; + + if (fileName) { tsConfigFileName = path.resolve(process.cwd(), fileNameOrSettings); projectDirectory = path.dirname(tsConfigFileName); - // Load file and strip BOM, since JSON.parse fails to parse if there's a BOM present - let tsConfigText = fs.readFileSync(tsConfigFileName).toString(); - const typescript = getTypeScript(settings && settings.typescript); - const tsConfig = typescript.parseConfigFileTextToJson(tsConfigFileName, tsConfigText); - tsConfigContent = tsConfig.config || {}; + let tsConfig = typescript.readConfigFile(tsConfigFileName, typescript.sys.readFile); if (tsConfig.error) { console.log(tsConfig.error.messageText); } - let newSettings: any = {}; - if (tsConfigContent.compilerOptions) { - for (const key of Object.keys(tsConfigContent.compilerOptions)) { - newSettings[key] = tsConfigContent.compilerOptions[key]; - } - } - if (settings) { - for (const key of Object.keys(settings)) { - newSettings[key] = settings[key]; - } + + let parsed: ts.ParsedCommandLine = tsConfig.config && + typescript.parseJsonConfigFileContent( + tsConfig.config, + typescript.sys, + path.resolve(projectDirectory), + settings, + path.basename(tsConfigFileName)); + + tsConfigContent = { + compilerOptions: parsed.options, + files: parsed.fileNames, + }; + + if (parsed.errors) { + reportErrors(parsed.errors, typescript); } - settings = newSettings; - } else { - settings = fileNameOrSettings; + + compilerOptions = parsed.options; } } - const project = _project.setupProject(projectDirectory, tsConfigContent, getCompilerOptions(settings, projectDirectory, tsConfigFileName), getTypeScript(settings.typescript)); + normalizeCompilerOptions(compilerOptions); + const project = _project.setupProject(projectDirectory, tsConfigContent, compilerOptions, typescript); return project; } diff --git a/release/main.js b/release/main.js index 4af9f922..0d6aad50 100644 --- a/release/main.js +++ b/release/main.js @@ -1,5 +1,12 @@ "use strict"; -var fs = require("fs"); +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; var path = require("path"); var _project = require("./project"); var utils = require("./utils"); @@ -34,8 +41,7 @@ function getTypeScript(typescript) { throw new Error("TypeScript not installed"); } } -function getCompilerOptions(settings, projectPath, configFileName) { - var typescript = getTypeScript(settings.typescript); +function checkAndNormalizeSettings(settings) { if (settings.sourceRoot !== undefined) { console.warn('gulp-typescript: sourceRoot isn\'t supported any more. Use sourceRoot option of gulp-sourcemaps instead.'); } @@ -45,33 +51,28 @@ function getCompilerOptions(settings, projectPath, configFileName) { if (settings.sortOutput !== undefined) { utils.deprecate("sortOutput is deprecated", "your project might work without it", "The non-standard option sortOutput has been removed as of gulp-typescript 3.0.\nYour project will probably compile without this option.\nOtherwise, if you're using gulp-concat, you should remove gulp-concat and use the outFile option instead."); } - // Copy settings and remove several options - var newSettings = {}; - for (var _i = 0, _a = Object.keys(settings); _i < _a.length; _i++) { - var option = _a[_i]; - if (option === 'declarationFiles') { - newSettings.declaration = settings.declarationFiles; - continue; - } - if (option === 'noExternalResolve' || - option === 'sortOutput' || - option === 'typescript' || - option === 'sourceMap' || - option === 'inlineSourceMap' || - option === 'sourceRoot' || - option === 'inlineSources') - continue; - newSettings[option] = settings[option]; + if (settings.declarationFiles) { + settings.declaration = settings.declarationFiles; + delete settings.declarationFiles; } - var result = typescript.convertCompilerOptionsFromJson(newSettings, projectPath, configFileName); + delete settings.noExternalResolve; + delete settings.sortOutput; + delete settings.typescript; + delete settings.sourceMap; + delete settings.inlineSourceMap; + delete settings.sourceRoot; + delete settings.inlineSources; +} +function normalizeCompilerOptions(options) { + options.sourceMap = true; + options.suppressOutputPathCheck = true; +} +function reportErrors(errors, typescript) { var reporter = _reporter.defaultReporter(); - for (var _b = 0, _c = result.errors; _b < _c.length; _b++) { - var error = _c[_b]; + for (var _i = 0, errors_1 = errors; _i < errors_1.length; _i++) { + var error = errors_1[_i]; reporter.error(utils.getError(error, typescript), typescript); } - result.options.sourceMap = true; - result.options.suppressOutputPathCheck = true; - return result.options; } (function (compile) { compile.reporter = _reporter; @@ -79,38 +80,45 @@ function getCompilerOptions(settings, projectPath, configFileName) { var tsConfigFileName = undefined; var tsConfigContent = undefined; var projectDirectory = process.cwd(); + var typescript; + var compilerOptions; + var fileName; + settings = __assign({}, settings); // Shallow copy the settings. if (fileNameOrSettings !== undefined) { if (typeof fileNameOrSettings === 'string') { + fileName = fileNameOrSettings; + } + else { + settings = fileNameOrSettings || {}; + } + typescript = getTypeScript(settings.typescript); + checkAndNormalizeSettings(settings); + var settingsResult = typescript.convertCompilerOptionsFromJson(settings, projectDirectory); + if (settingsResult.errors) { + reportErrors(settingsResult.errors, typescript); + } + compilerOptions = settingsResult.options; + if (fileName) { tsConfigFileName = path.resolve(process.cwd(), fileNameOrSettings); projectDirectory = path.dirname(tsConfigFileName); - // Load file and strip BOM, since JSON.parse fails to parse if there's a BOM present - var tsConfigText = fs.readFileSync(tsConfigFileName).toString(); - var typescript = getTypeScript(settings && settings.typescript); - var tsConfig = typescript.parseConfigFileTextToJson(tsConfigFileName, tsConfigText); - tsConfigContent = tsConfig.config || {}; + var tsConfig = typescript.readConfigFile(tsConfigFileName, typescript.sys.readFile); if (tsConfig.error) { console.log(tsConfig.error.messageText); } - var newSettings = {}; - if (tsConfigContent.compilerOptions) { - for (var _i = 0, _a = Object.keys(tsConfigContent.compilerOptions); _i < _a.length; _i++) { - var key = _a[_i]; - newSettings[key] = tsConfigContent.compilerOptions[key]; - } - } - if (settings) { - for (var _b = 0, _c = Object.keys(settings); _b < _c.length; _b++) { - var key = _c[_b]; - newSettings[key] = settings[key]; - } + var parsed = tsConfig.config && + typescript.parseJsonConfigFileContent(tsConfig.config, typescript.sys, path.resolve(projectDirectory), settings, path.basename(tsConfigFileName)); + tsConfigContent = { + compilerOptions: parsed.options, + files: parsed.fileNames, + }; + if (parsed.errors) { + reportErrors(parsed.errors, typescript); } - settings = newSettings; - } - else { - settings = fileNameOrSettings; + compilerOptions = parsed.options; } } - var project = _project.setupProject(projectDirectory, tsConfigContent, getCompilerOptions(settings, projectDirectory, tsConfigFileName), getTypeScript(settings.typescript)); + normalizeCompilerOptions(compilerOptions); + var project = _project.setupProject(projectDirectory, tsConfigContent, compilerOptions, typescript); return project; } compile.createProject = createProject; diff --git a/test/baselines/tsconfigExtends/2.0/dts/other-3.d.ts b/test/baselines/tsconfigExtends/2.0/dts/other-3.d.ts new file mode 100644 index 00000000..b3a0b19d --- /dev/null +++ b/test/baselines/tsconfigExtends/2.0/dts/other-3.d.ts @@ -0,0 +1,3 @@ +export declare class Hello { + value: string; +} diff --git a/test/baselines/tsconfigExtends/2.0/dts/test-3.d.ts b/test/baselines/tsconfigExtends/2.0/dts/test-3.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/test/baselines/tsconfigExtends/2.0/errors.txt b/test/baselines/tsconfigExtends/2.0/errors.txt new file mode 100644 index 00000000..e51d1660 --- /dev/null +++ b/test/baselines/tsconfigExtends/2.0/errors.txt @@ -0,0 +1,11 @@ + +{ + "transpileErrors": 0, + "optionsErrors": 0, + "syntaxErrors": 0, + "globalErrors": 0, + "semanticErrors": 0, + "declarationErrors": 0, + "emitErrors": 0, + "emitSkipped": false +} \ No newline at end of file diff --git a/test/baselines/tsconfigExtends/2.0/js/other-3.js b/test/baselines/tsconfigExtends/2.0/js/other-3.js new file mode 100644 index 00000000..206eb383 --- /dev/null +++ b/test/baselines/tsconfigExtends/2.0/js/other-3.js @@ -0,0 +1,12 @@ +define(["require", "exports"], function (require, exports) { + "use strict"; + exports.__esModule = true; + var Hello = (function () { + function Hello() { + } + return Hello; + }()); + exports.Hello = Hello; +}); + +//# sourceMappingURL=other-3.js.map diff --git a/test/baselines/tsconfigExtends/2.0/js/other-3.js.map b/test/baselines/tsconfigExtends/2.0/js/other-3.js.map new file mode 100644 index 00000000..3f884110 --- /dev/null +++ b/test/baselines/tsconfigExtends/2.0/js/other-3.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../other-3.ts"],"names":[],"mappings":";;;IAAA;QAAA;QAEA,CAAC;QAAD,YAAC;IAAD,CAFA,AAEC,IAAA;IAFY,sBAAK","file":"other-3.js","sourcesContent":["export class Hello {\n\tvalue: string;\n}"],"sourceRoot":"../../../../basic/"} \ No newline at end of file diff --git a/test/baselines/tsconfigExtends/2.0/js/test-3.js b/test/baselines/tsconfigExtends/2.0/js/test-3.js new file mode 100644 index 00000000..44d147aa --- /dev/null +++ b/test/baselines/tsconfigExtends/2.0/js/test-3.js @@ -0,0 +1,8 @@ +define(["require", "exports", "./other-3"], function (require, exports, other) { + "use strict"; + exports.__esModule = true; + var a = new other.Hello(); + console.log(a.value); +}); + +//# sourceMappingURL=test-3.js.map diff --git a/test/baselines/tsconfigExtends/2.0/js/test-3.js.map b/test/baselines/tsconfigExtends/2.0/js/test-3.js.map new file mode 100644 index 00000000..ee89706f --- /dev/null +++ b/test/baselines/tsconfigExtends/2.0/js/test-3.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../test-3.ts"],"names":[],"mappings":";;;IAEA,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC","file":"test-3.js","sourcesContent":["import other = require('./other-3');\n\nvar a = new other.Hello();\nconsole.log(a.value);"],"sourceRoot":"../../../../basic/"} \ No newline at end of file diff --git a/test/baselines/tsconfigExtends/dev/dts/other-3.d.ts b/test/baselines/tsconfigExtends/dev/dts/other-3.d.ts new file mode 100644 index 00000000..b3a0b19d --- /dev/null +++ b/test/baselines/tsconfigExtends/dev/dts/other-3.d.ts @@ -0,0 +1,3 @@ +export declare class Hello { + value: string; +} diff --git a/test/baselines/tsconfigExtends/dev/dts/test-3.d.ts b/test/baselines/tsconfigExtends/dev/dts/test-3.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/test/baselines/tsconfigExtends/dev/errors.txt b/test/baselines/tsconfigExtends/dev/errors.txt new file mode 100644 index 00000000..e51d1660 --- /dev/null +++ b/test/baselines/tsconfigExtends/dev/errors.txt @@ -0,0 +1,11 @@ + +{ + "transpileErrors": 0, + "optionsErrors": 0, + "syntaxErrors": 0, + "globalErrors": 0, + "semanticErrors": 0, + "declarationErrors": 0, + "emitErrors": 0, + "emitSkipped": false +} \ No newline at end of file diff --git a/test/baselines/tsconfigExtends/dev/js/other-3.js b/test/baselines/tsconfigExtends/dev/js/other-3.js new file mode 100644 index 00000000..206eb383 --- /dev/null +++ b/test/baselines/tsconfigExtends/dev/js/other-3.js @@ -0,0 +1,12 @@ +define(["require", "exports"], function (require, exports) { + "use strict"; + exports.__esModule = true; + var Hello = (function () { + function Hello() { + } + return Hello; + }()); + exports.Hello = Hello; +}); + +//# sourceMappingURL=other-3.js.map diff --git a/test/baselines/tsconfigExtends/dev/js/other-3.js.map b/test/baselines/tsconfigExtends/dev/js/other-3.js.map new file mode 100644 index 00000000..3f884110 --- /dev/null +++ b/test/baselines/tsconfigExtends/dev/js/other-3.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../other-3.ts"],"names":[],"mappings":";;;IAAA;QAAA;QAEA,CAAC;QAAD,YAAC;IAAD,CAFA,AAEC,IAAA;IAFY,sBAAK","file":"other-3.js","sourcesContent":["export class Hello {\n\tvalue: string;\n}"],"sourceRoot":"../../../../basic/"} \ No newline at end of file diff --git a/test/baselines/tsconfigExtends/dev/js/test-3.js b/test/baselines/tsconfigExtends/dev/js/test-3.js new file mode 100644 index 00000000..44d147aa --- /dev/null +++ b/test/baselines/tsconfigExtends/dev/js/test-3.js @@ -0,0 +1,8 @@ +define(["require", "exports", "./other-3"], function (require, exports, other) { + "use strict"; + exports.__esModule = true; + var a = new other.Hello(); + console.log(a.value); +}); + +//# sourceMappingURL=test-3.js.map diff --git a/test/baselines/tsconfigExtends/dev/js/test-3.js.map b/test/baselines/tsconfigExtends/dev/js/test-3.js.map new file mode 100644 index 00000000..ee89706f --- /dev/null +++ b/test/baselines/tsconfigExtends/dev/js/test-3.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../test-3.ts"],"names":[],"mappings":";;;IAEA,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC","file":"test-3.js","sourcesContent":["import other = require('./other-3');\n\nvar a = new other.Hello();\nconsole.log(a.value);"],"sourceRoot":"../../../../basic/"} \ No newline at end of file diff --git a/test/tsconfigExtends/bad.ts b/test/tsconfigExtends/bad.ts new file mode 100644 index 00000000..f9781a75 --- /dev/null +++ b/test/tsconfigExtends/bad.ts @@ -0,0 +1 @@ +blargh. diff --git a/test/tsconfigExtends/gulptask.js b/test/tsconfigExtends/gulptask.js new file mode 100644 index 00000000..f2a5c03a --- /dev/null +++ b/test/tsconfigExtends/gulptask.js @@ -0,0 +1,32 @@ +var gulp = require('gulp'); +var sourcemaps = require('gulp-sourcemaps'); + +// +// The test here loads tsconfig.json which extends tsconfig-base.json +// If the "extends" parameter is not processed, then only other-3.ts +// will be compiled but not test-3.ts because the latter is only +// included among the compiled files by the tsconfig-base.json file. +// +// tsconfig-base.json also changes the module format to "amd" from the +// default which is "commonjs". +// +// Both the module format change and the file inclusion change are +// meaningful changes, because historically the introduction of +// "extends" made it so that updates to TypeScript tools that read +// tsconfig.json could get one or the other change wrong. +// + +module.exports = function(newTS, lib, output, reporter) { + var tsProject = newTS.createProject('test/tsconfigExtends/tsconfig.json', { + typescript: lib, + }); + + var tsResult = tsProject.src() + .pipe(sourcemaps.init()) + .pipe(tsProject(reporter)); + + tsResult.dts.pipe(gulp.dest(output + '/dts')); + return tsResult.js + .pipe(sourcemaps.write('.', { sourceRoot: '../../../../basic/' })) + .pipe(gulp.dest(output + 'js')); +} diff --git a/test/tsconfigExtends/other-3.ts b/test/tsconfigExtends/other-3.ts new file mode 100644 index 00000000..50f5310d --- /dev/null +++ b/test/tsconfigExtends/other-3.ts @@ -0,0 +1,3 @@ +export class Hello { + value: string; +} \ No newline at end of file diff --git a/test/tsconfigExtends/test-3.ts b/test/tsconfigExtends/test-3.ts new file mode 100644 index 00000000..5c291a9c --- /dev/null +++ b/test/tsconfigExtends/test-3.ts @@ -0,0 +1,4 @@ +import other = require('./other-3'); + +var a = new other.Hello(); +console.log(a.value); \ No newline at end of file diff --git a/test/tsconfigExtends/tsconfig-base.json b/test/tsconfigExtends/tsconfig-base.json new file mode 100644 index 00000000..ce51fe4a --- /dev/null +++ b/test/tsconfigExtends/tsconfig-base.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "declaration": true, + "module": "amd", + "outDir": "js", + "declarationDir": "dts", + "types": [] + }, + "include": [ + "test-3.ts" + ] +} diff --git a/test/tsconfigExtends/tsconfig.json b/test/tsconfigExtends/tsconfig.json new file mode 100644 index 00000000..996ae872 --- /dev/null +++ b/test/tsconfigExtends/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "./tsconfig-base", + "files": [ + "other-3.ts" + ] +}