diff --git a/gulpfile.js b/gulpfile.js index b1789cde..1752a387 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -8,7 +8,6 @@ const isparta = require("isparta"); const sourcemaps = require("gulp-sourcemaps"); const path = require("path"); const preprocess = require("gulp-preprocess"); -const runSequence = require("run-sequence"); const ts = require("gulp-typescript"); const mocha = require("gulp-mocha"); const GulpExtras = require("./tools/gulp-extras"); @@ -18,8 +17,9 @@ const fs = require("fs"); const Q = require("q"); const es = require("event-stream"); const remapIstanbul = require("remap-istanbul/lib/gulpRemapIstanbul"); -const execSync = require("child_process").execSync; const nls = require("vscode-nls-dev"); +const libtslint = require("tslint"); +const tslint = require("gulp-tslint"); const copyright = GulpExtras.checkCopyright; const imports = GulpExtras.checkImports; @@ -32,14 +32,14 @@ const transifexProjectName = "vscode-extensions"; const transifexExtensionName = "vscode-react-native"; const defaultLanguages = [ - { id: "zh-tw", folderName: "cht", transifexId: "zh-hant" }, - { id: "zh-cn", folderName: "chs", transifexId: "zh-hans" }, - { id: "ja", folderName: "jpn" }, - { id: "ko", folderName: "kor" }, - { id: "de", folderName: "deu" }, - { id: "fr", folderName: "fra" }, - { id: "es", folderName: "esn" }, - { id: "ru", folderName: "rus" }, + { id: "zh-tw", folderName: "cht", transifexId: "zh-hant" }, + { id: "zh-cn", folderName: "chs", transifexId: "zh-hans" }, + { id: "ja", folderName: "jpn" }, + { id: "ko", folderName: "kor" }, + { id: "de", folderName: "deu" }, + { id: "fr", folderName: "fra" }, + { id: "es", folderName: "esn" }, + { id: "ru", folderName: "rus" }, { id: "it", folderName: "ita" }, // These language-pack languages are included for VS but excluded from the vscode package @@ -49,29 +49,76 @@ const defaultLanguages = [ { id: "pl", folderName: "plk" } ]; -var srcPath = "src"; -var testPath = "test"; +const srcPath = "src"; +const testPath = "test"; -var sources = [ - srcPath, - testPath, -].map(function (tsFolder) { return tsFolder + "/**/*.ts"; }); +const sources = [srcPath, testPath].map((tsFolder) => tsFolder + "/**/*.ts"); -var knownOptions = { +const knownOptions = { string: "env", default: { env: "production" } }; -var options = minimist(process.argv.slice(2), knownOptions); +const options = minimist(process.argv.slice(2), knownOptions); -var tsProject = ts.createProject("tsconfig.json"); +let lintSources = [srcPath, testPath].map((tsFolder) => tsFolder + "/**/*.ts"); +lintSources = lintSources.concat([ + "!src/typings/**", + "!test/resources/sampleReactNative022Project/**" +]); -gulp.task("check-imports", function () { +function build(failOnError, buildNls) { + const tsProject = ts.createProject("tsconfig.json"); + const isProd = options.env === "production"; + const preprocessorContext = isProd ? { PROD: true } : { DEBUG: true }; + let gotError = false; + log(`Building with preprocessor context: ${JSON.stringify(preprocessorContext)}`); + const tsResult = tsProject.src() + .pipe(preprocess({ context: preprocessorContext })) //To set environment variables in-line + .pipe(sourcemaps.init()) + .pipe(tsProject()); + + return tsResult.js + .pipe(buildNls ? nls.rewriteLocalizeCalls() : es.through()) + .pipe(buildNls ? nls.createAdditionalLanguageFiles(defaultLanguages, "i18n", ".") : es.through()) + .pipe(buildNls ? nls.bundleMetaDataFiles("vsmobile.vscode-react-native", ".") : es.through()) + .pipe(buildNls ? nls.bundleLanguageFiles() : es.through()) + .pipe(sourcemaps.write(".", { includeContent: false, sourceRoot: "." })) + .pipe(gulp.dest((file) => file.cwd)) + .once("error", () => { + gotError = true; + }) + .once("finish", () => { + if (failOnError && gotError) { + process.exit(1); + } + }); +} + +function test() { + // Check if arguments were passed + if (options.pattern) { + log(`\nTesting cases that match pattern: ${options.pattern}`); + } else { + log("\nTesting cases that don't match pattern: extensionContext"); + } + + return gulp.src(["test/**/*.test.js", "!test/extension/**"]) + .pipe(mocha({ + ui: "tdd", + useColors: true, + invert: !options.pattern, + grep: options.pattern || "extensionContext" + })); +} + +gulp.task("check-imports", () => { + const tsProject = ts.createProject("tsconfig.json"); return tsProject.src() .pipe(imports()); }); -gulp.task("check-copyright", function () { +gulp.task("check-copyright", () => { return gulp.src([ "**/*.ts", "**/*.js", @@ -85,41 +132,8 @@ gulp.task("check-copyright", function () { .pipe(copyright()); }); - -function build(failOnError, buildNls) { - var tsProject = ts.createProject("tsconfig.json"); - var isProd = options.env === "production"; - var preprocessorContext = isProd ? { PROD: true } : { DEBUG: true }; - let gotError = false; - log(`Building with preprocessor context: ${JSON.stringify(preprocessorContext)}`); - var tsResult = tsProject.src() - .pipe(preprocess({ context: preprocessorContext })) //To set environment variables in-line - .pipe(sourcemaps.init()) - .pipe(tsProject()); - - return tsResult.js - .pipe(buildNls ? nls.rewriteLocalizeCalls() : es.through()) - .pipe(buildNls ? nls.createAdditionalLanguageFiles(defaultLanguages, "i18n", ".") : es.through()) - .pipe(buildNls ? nls.bundleMetaDataFiles("vsmobile.vscode-react-native", ".") : es.through()) - .pipe(buildNls ? nls.bundleLanguageFiles() : es.through()) - .pipe(sourcemaps.write(".", { includeContent: false, sourceRoot: "." })) - .pipe(gulp.dest(function (file) { - return file.cwd; - })) - .once("error", () => { - gotError = true; - }) - .once("finish", () => { - if (failOnError && gotError) { - process.exit(1); - } - }); -} - -var libtslint = require("tslint"); -var tslint = require("gulp-tslint"); -gulp.task("tslint", function () { - var program = libtslint.Linter.createProgram("./tsconfig.json"); +gulp.task("tslint", () => { + const program = libtslint.Linter.createProgram("./tsconfig.json"); return gulp.src(lintSources, { base: "." }) .pipe(tslint({ formatter: "verbose", @@ -131,30 +145,30 @@ gulp.task("tslint", function () { // TODO: The file property should point to the generated source (this implementation adds an extra folder to the path) // We should also make sure that we always generate urls in all the path properties (We shouldn"t have \\s. This seems to // be an issue on Windows platforms) -gulp.task("build", gulp.series("check-imports", "check-copyright", "tslint", function (done) { +gulp.task("build", gulp.series("check-imports", "check-copyright", "tslint", function runBuild(done) { build(true, true) - .once("finish", () => { - done(); - }); + .once("finish", () => { + done(); + }); })); -gulp.task("build-dev", gulp.series("check-imports", "check-copyright", function (done) { +gulp.task("build-dev", gulp.series("check-imports", "check-copyright", function runBuild(done) { build(false, false) - .once("finish", () => { - done(); - }); + .once("finish", () => { + done(); + }); })); gulp.task("quick-build", gulp.series("build-dev")); -gulp.task("watch", gulp.series("build", function () { +gulp.task("watch", gulp.series("build", function runWatch() { log("Watching build sources..."); return gulp.watch(sources, gulp.series("build")); })); -gulp.task("clean", function () { - var del = require("del"); - var pathsToDelete = [ +gulp.task("clean", () => { + const del = require("del"); + const pathsToDelete = [ "src/**/*.js", "src/**/*.js.map", "test/**/*.js", @@ -169,35 +183,9 @@ gulp.task("clean", function () { gulp.task("default", gulp.series("clean", "build")); -var lintSources = [ - srcPath, - testPath -].map(function (tsFolder) { return tsFolder + "/**/*.ts"; }); -lintSources = lintSources.concat([ - "!src/typings/**", - "!test/resources/sampleReactNative022Project/**" -]); - -function test() { - // Check if arguments were passed - if (options.pattern) { - console.log("\nTesting cases that match pattern: " + options.pattern); - } else { - console.log("\nTesting cases that don't match pattern: extensionContext"); - } - - return gulp.src(["test/**/*.test.js", "!test/extension/**"]) - .pipe(mocha({ - ui: "tdd", - useColors: true, - invert: !options.pattern, - grep: options.pattern || "extensionContext" - })); -} - gulp.task("test", gulp.series("build", "tslint", test)); -gulp.task("coverage:instrument", function () { +gulp.task("coverage:instrument", () => { return gulp.src(["src/**/*.js", "!test/**"]) .pipe(istanbul({ // Use the isparta instrumenter (code coverage for ES6) @@ -208,17 +196,17 @@ gulp.task("coverage:instrument", function () { .pipe(istanbul.hookRequire()); }); -gulp.task("coverage:report", function (done) { +gulp.task("coverage:report", () => { return gulp.src( ["src/**/*.js", "!test/**"], { read: false } ) - .pipe(istanbul.writeReports({ - reporters: ["json", "text-summary"] - })); + .pipe(istanbul.writeReports({ + reporters: ["json", "text-summary"] + })); }); -gulp.task("coverage:remap", function () { +gulp.task("coverage:remap", () => { return gulp.src("coverage/coverage-final.json") .pipe(remapIstanbul({ reports: { @@ -232,90 +220,90 @@ gulp.task("test-no-build", test); gulp.task("test:coverage", gulp.series("quick-build", "coverage:instrument", "test-no-build", "coverage:report", "coverage:remap")); -gulp.task("watch-build-test", gulp.series("build", "test", function () { +gulp.task("watch-build-test", gulp.series("build", "test", function runWatch() { return gulp.watch(sources, gulp.series("build", "test")); })); -gulp.task("package", function (callback) { - var command = path.join(__dirname, "node_modules", ".bin", "vsce"); - var args = ["package"]; +gulp.task("package", (callback) => { + const command = path.join(__dirname, "node_modules", ".bin", "vsce"); + const args = ["package"]; executeCommand(command, args, callback); }); -gulp.task("release", gulp.series("build", function () { - var licenseFiles = ["LICENSE.txt", "ThirdPartyNotices.txt"]; - var backupFolder = path.resolve(path.join(os.tmpdir(), "vscode-react-native")); +gulp.task("release", gulp.series("build", function prepareLicenses() { + const licenseFiles = ["LICENSE.txt", "ThirdPartyNotices.txt"]; + const backupFolder = path.resolve(path.join(os.tmpdir(), "vscode-react-native")); if (!fs.existsSync(backupFolder)) { fs.mkdirSync(backupFolder); } return Q({}) - .then(function () { + .then(() => { /* back up LICENSE.txt, ThirdPartyNotices.txt, README.md */ - console.log("Backing up license files to " + backupFolder + "..."); - licenseFiles.forEach(function (fileName) { + log("Backing up license files to " + backupFolder + "..."); + licenseFiles.forEach((fileName) => { fs.writeFileSync(path.join(backupFolder, fileName), fs.readFileSync(fileName)); }); /* copy over the release package license files */ - console.log("Preparing license files for release..."); + log("Preparing license files for release..."); fs.writeFileSync("LICENSE.txt", fs.readFileSync("release/LICENSE.txt")); fs.writeFileSync("ThirdPartyNotices.txt", fs.readFileSync("release/ThirdPartyNotices.txt")); }).then(() => { - console.log("Creating release package..."); + log("Creating release package..."); var deferred = Q.defer(); // NOTE: vsce must see npm 3.X otherwise it will not correctly strip out dev dependencies. - executeCommand("vsce", ["package"], function (arg) { if (arg) { deferred.reject(arg); } deferred.resolve() }, { cwd: path.resolve(__dirname) }); + executeCommand("vsce", ["package"], (arg) => { if (arg) { deferred.reject(arg); } deferred.resolve() }, { cwd: path.resolve(__dirname) }); return deferred.promise; - }).finally(function () { + }).finally(() => { /* restore backed up files */ - console.log("Restoring modified files..."); - licenseFiles.forEach(function (fileName) { + log("Restoring modified files..."); + licenseFiles.forEach((fileName) => { fs.writeFileSync(path.join(__dirname, fileName), fs.readFileSync(path.join(backupFolder, fileName))); }); }); })); // Creates package.i18n.json files for all languages from {workspaceRoot}/i18n folder into project root -gulp.task("add-i18n", function () { +gulp.task("add-i18n", () => { return gulp.src(["package.nls.json"]) .pipe(nls.createAdditionalLanguageFiles(defaultLanguages, "i18n")) - .pipe(gulp.dest(".")); + .pipe(gulp.dest(".")) }); // Gathers all strings to Transifex readable .xliff file for translating and pushes them to Transifex -gulp.task("transifex-push", gulp.series("build", function () { - return gulp.src(["package.nls.json", "nls.metadata.header.json","nls.metadata.json"]) +gulp.task("transifex-push", gulp.series("build", function runTransifexPush() { + return gulp.src(["package.nls.json", "nls.metadata.header.json", "nls.metadata.json"]) .pipe(nls.createXlfFiles(transifexProjectName, transifexExtensionName)) .pipe(nls.pushXlfFiles(transifexApiHostname, transifexApiName, transifexApiToken)); })); // Creates Transifex readable .xliff file and saves it locally -gulp.task("transifex-push-test", gulp.series("build", function() { - return gulp.src(["package.nls.json", "nls.metadata.header.json","nls.metadata.json"]) +gulp.task("transifex-push-local", gulp.series("build", function runTransifexPushLocal() { + return gulp.src(["package.nls.json", "nls.metadata.header.json", "nls.metadata.json"]) .pipe(nls.createXlfFiles(transifexProjectName, transifexExtensionName)) .pipe(gulp.dest(path.join("..", `${transifexExtensionName}-push-test`))); })); // Gets the files with localized strings from Transifex -gulp.task("transifex-pull", function (done) { - es.merge(defaultLanguages.map(function(language) { +gulp.task("transifex-pull", (done) => { + es.merge(defaultLanguages.map((language) => { return nls.pullXlfFiles(transifexApiHostname, transifexApiName, transifexApiToken, language, [{ name: transifexExtensionName, project: transifexProjectName }]) .pipe(gulp.dest(`../${transifexExtensionName}-localization/${language.folderName}`)) })) - .pipe(es.wait(function() { - done(); - })); + .pipe(es.wait(() => { + done(); + })); }); // Imports localization from raw localized Transifex strings to VS Code .i18n.json files -gulp.task("i18n-import", function(done) { - es.merge(defaultLanguages.map(function(language) { +gulp.task("i18n-import", (done) => { + es.merge(defaultLanguages.map((language) => { return gulp.src(`../${transifexExtensionName}-localization/${language.folderName}/**/*.xlf`) .pipe(nls.prepareJsonFiles()) .pipe(gulp.dest(path.join("./i18n", language.folderName))) })) - .pipe(es.wait(function() { - done(); - })); + .pipe(es.wait(() => { + done(); + })); }); diff --git a/tools/gulp-extras.js b/tools/gulp-extras.js index 16854f4d..dfabc7b6 100644 --- a/tools/gulp-extras.js +++ b/tools/gulp-extras.js @@ -2,13 +2,13 @@ // Licensed under the MIT license. See LICENSE file in the project root for details. "use strict"; -var child_process = require("child_process"); -var fs = require("fs"); -var log = require('fancy-log'); +const child_process = require("child_process"); +const fs = require("fs"); +const log = require('fancy-log'); const colors = require('ansi-colors'); -var path = require("path"); -var PluginError = require('plugin-error'); -var through = require("through2"); +const path = require("path"); +const PluginError = require('plugin-error'); +const through = require("through2"); /** * Pretty logger using 'log' @@ -16,22 +16,22 @@ var through = require("through2"); * @param {Object} file A gulp file to report on * @param {string} message The error message to display */ -var logError = function(pluginName, file, message) { - var sourcePath = path.relative(__dirname, file.path).replace("../",""); - log("[" + colors.cyan(pluginName) + "] " + colors.red("error") + " " + sourcePath + ": " + message); -}; +function logError(pluginName, file, message) { + const sourcePath = path.relative(__dirname, file.path).replace("../", ""); + log(`[${colors.cyan(pluginName)}] ${colors.red("error")} ${sourcePath}: ${message}`); +} /** * Plugin to verify the Microsoft copyright notice is present */ -var checkCopyright = function() { - var pluginName = "check-copyright"; - var hadErrors = false; - var copyrightNotice = "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for details."; +function checkCopyright() { + const pluginName = "check-copyright"; + let hadErrors = false; + const copyrightNotice = "// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for details."; - return through.obj(function(file, encoding, callback) { + return through.obj(function (file, encoding, callback) { if (file.isBuffer()) { - var fileContents = file.contents.toString(encoding); + let fileContents = file.contents.toString(encoding); fileContents = fileContents.replace("\r\n", "\n"); fileContents = fileContents.replace("\"use strict\";\n", ""); fileContents = fileContents.replace("Object.defineProperty(exports, \"__esModule\", { value: true });\n", ""); @@ -44,50 +44,50 @@ var checkCopyright = function() { callback(null, file); }, - function(callback) { - if (hadErrors) { - return this.emit("error", new PluginError(pluginName, "Failed copyright check")); - } - callback(); - }); -}; + function (callback) { + if (hadErrors) { + return this.emit("error", new PluginError(pluginName, "Failed copyright check")); + } + callback(); + }); +} /** * Helper function to check if a file exists case sensitive * @param {string} filePath The path to check * @returns {boolean} If the path exists case sensitive */ -var existsCaseSensitive = function(filePath) { +function existsCaseSensitive(filePath) { if (fs.existsSync(filePath)) { - var fileName = path.basename(filePath); + const fileName = path.basename(filePath); return fs.readdirSync(path.dirname(filePath)).indexOf(fileName) !== -1; } return false; -}; +} /** * Plugin to verify if import statements use correct casing */ -var checkImports = function() { - var pluginName = "check-imports"; - var hadErrors = false; - var re = /(?:\s|^)(?:[^\n:]*).*from ["'](\.[^"']*)["'];/; +function checkImports() { + const pluginName = "check-imports"; + let hadErrors = false; + const re = /(?:\s|^)(?:[^\n:]*).*from ["'](\.[^"']*)["'];/; - return through.obj(function(file, encoding, callback) { + return through.obj(function (file, encoding, callback) { if (file.isBuffer()) { var fileContents = file.contents.toString(encoding); var importStatements = fileContents.match(new RegExp(re.source, "g")) || []; var workingDirectory = path.dirname(file.path); - importStatements.forEach(function(importStatement) { + importStatements.forEach(function (importStatement) { var modulePath = re.exec(importStatement); if (modulePath && modulePath[1]) { var moduleFilePath = path.resolve(workingDirectory, modulePath[1] + ".ts"); if (!existsCaseSensitive(moduleFilePath)) { - logError(pluginName, file, "unresolved import: \"" + modulePath[1] + "\""); + logError(pluginName, file, `unresolved import: "${modulePath[1]}"`); hadErrors = true; } } @@ -96,45 +96,45 @@ var checkImports = function() { callback(null, file); }, - function(callback) { - if (hadErrors) { - return this.emit("error", new PluginError(pluginName, "Failed import casing check")); - } - callback(); - }); -}; + function (callback) { + if (hadErrors) { + return this.emit("error", new PluginError(pluginName, "Failed import casing check")); + } + callback(); + }); +} -var executeCommand = function(command, args, callback, opts) { - var proc = child_process.spawn(command + (process.platform === "win32" ? ".cmd" : ""), args, opts); - var errorSignaled = false; +function executeCommand(command, args, callback, opts) { + const proc = child_process.spawn(command + (process.platform === "win32" ? ".cmd" : ""), args, opts); + let errorSignaled = false; - proc.stdout.on("data", function(data) { - console.log("" + data); + proc.stdout.on("data", (data) => { + log(`${data}`); }); - proc.stderr.on("data", function(data) { - console.error("" + data); + proc.stderr.on("data", (data) => { + log.error(`${data}`); }); - proc.on("error", function(error) { + proc.on("error", (error) => { if (!errorSignaled) { - callback("An error occurred. " + error); + callback(`An error occurred. ${error}`); errorSignaled = true; } }); - proc.on("exit", function(code) { + proc.on("exit", (code) => { if (code === 0) { callback(); } else if (!errorSignaled) { - callback("Error code: " + code); + callback(`Error code: ${code}`); errorSignaled = true; } }); -}; +} module.exports = { - checkCopyright: checkCopyright, - checkImports: checkImports, - executeCommand: executeCommand + checkCopyright, + checkImports, + executeCommand } \ No newline at end of file