Converted checkCopyright and checkImports to Gulp Plugins

This commit is contained in:
Joshua Skelton 2016-03-11 17:32:11 -08:00
Родитель f3b1a3f899
Коммит 9adec70d2a
5 изменённых файлов: 264 добавлений и 295 удалений

Просмотреть файл

@ -10,6 +10,9 @@ var path = require('path');
var runSequence = require("run-sequence");
var ts = require('gulp-typescript');
var mocha = require('gulp-mocha');
var GulpExtras = require("./tools/gulp-extras");
var copyright = GulpExtras.checkCopyright;
var imports = GulpExtras.checkImports;
var srcPath = 'src';
var outPath = 'out';
@ -22,10 +25,12 @@ var sources = [
// 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', ['checkImports', 'checkCopyright'], function () {
gulp.task('build', function () {
var tsProject = ts.createProject('tsconfig.json');
return tsProject.src()
.pipe(sourcemaps.init())
.pipe(copyright())
.pipe(imports())
.pipe(ts(tsProject))
.pipe(sourcemaps.write('.', {
includeContent: false,
@ -72,28 +77,16 @@ function test() {
gulp.task('build-test', ['build'], test);
gulp.task('test', test);
function runCustomVerification(pathInTools, errorMessage, cb) {
var checkProcess = child_process.fork(path.join(__dirname, "tools", pathInTools),
{
cwd: path.resolve(__dirname, "src"),
stdio: "inherit"
});
checkProcess.on("error", cb);
checkProcess.on("exit", function (code, signal) {
if (code || signal) {
cb(new Error(errorMessage));
} else {
cb();
}
});
}
gulp.task('checkImports', function (cb) {
runCustomVerification("checkCasing.js", "Mismatches found in import casing", cb);
var tsProject = ts.createProject('tsconfig.json');
return tsProject.src()
.pipe(imports());
});
gulp.task('checkCopyright', function (cb) {
runCustomVerification("checkCopyright.js", "Some source code files don't have the expected copyright notice", cb);
var tsProject = ts.createProject('tsconfig.json');
return tsProject.src()
.pipe(copyright());
});
gulp.task('watch-build-test', ['build', 'build-test'], function () {

Просмотреть файл

@ -1,155 +1,155 @@
{
"name": "vscode-react-native",
"displayName": "React Native Tools",
"version": "0.1.1",
"private": true,
"publisher": "vsmobile",
"icon": "images/icon.svg",
"galleryBanner": {
"color": "#3B3738",
"theme": "dark"
},
"description": "Code-hinting, debugging and integrated commands for React Native",
"bugs": "https://github.com/Microsoft/vscode-react-native/issues",
"license": "SEE LICENSE IN LICENSE.txt",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vscode-react-native"
},
"engines": {
"vscode": "^0.10.1"
},
"categories": [
"Debuggers",
"Other"
"name": "vscode-react-native",
"displayName": "React Native Tools",
"version": "0.1.1",
"private": true,
"publisher": "vsmobile",
"icon": "images/icon.svg",
"galleryBanner": {
"color": "#3B3738",
"theme": "dark"
},
"description": "Code-hinting, debugging and integrated commands for React Native",
"bugs": "https://github.com/Microsoft/vscode-react-native/issues",
"license": "SEE LICENSE IN LICENSE.txt",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/vscode-react-native"
},
"engines": {
"vscode": "^0.10.1"
},
"categories": [
"Debuggers",
"Other"
],
"activationEvents": [
"workspaceContains:package.json"
],
"main": "./out/extension/rn-extension",
"contributes": {
"commands": [
{
"command": "reactNative.runAndroid",
"title": "React Native: Run Android"
},
{
"command": "reactNative.runIos",
"title": "React Native: Run iOS"
},
{
"command": "reactNative.startPackager",
"title": "React Native: Start Packager"
},
{
"command": "reactNative.stopPackager",
"title": "React Native: Stop Packager"
}
],
"activationEvents": [
"workspaceContains:package.json"
],
"main": "./out/extension/rn-extension",
"contributes": {
"commands": [
{
"command": "reactNative.runAndroid",
"title": "React Native: Run Android"
},
{
"command": "reactNative.runIos",
"title": "React Native: Run iOS"
},
{
"command": "reactNative.startPackager",
"title": "React Native: Start Packager"
},
{
"command": "reactNative.stopPackager",
"title": "React Native: Stop Packager"
}
"debuggers": [
{
"type": "reactnative",
"label": "React Native",
"program": "./out/debugger/nodeDebugWrapper.js",
"runtime": "node",
"enableBrekapointsFor": {
"languageIds": [
"javascript",
"typescript",
"javascriptreact",
"typescriptreact"
]
},
"initialConfigurations": [
{
"name": "Debug Android",
"program": "${workspaceRoot}/.vscode/launchReactNative.js",
"type": "reactnative",
"request": "launch",
"platform": "android",
"internalDebuggerPort": 9090,
"sourceMaps": true,
"outDir": "${workspaceRoot}/.vscode/.react"
},
{
"name": "Debug iOS",
"program": "${workspaceRoot}/.vscode/launchReactNative.js",
"type": "reactnative",
"request": "launch",
"platform": "ios",
"target": "iPhone 5s",
"internalDebuggerPort": 9090,
"sourceMaps": true,
"outDir": "${workspaceRoot}/.vscode/.react"
}
],
"debuggers": [
{
"type": "reactnative",
"label": "React Native",
"program": "./out/debugger/nodeDebugWrapper.js",
"runtime": "node",
"enableBrekapointsFor": {
"languageIds": [
"javascript",
"typescript",
"javascriptreact",
"typescriptreact"
]
},
"initialConfigurations": [
{
"name": "Debug Android",
"program": "${workspaceRoot}/.vscode/launchReactNative.js",
"type": "reactnative",
"request": "launch",
"platform": "android",
"internalDebuggerPort": 9090,
"sourceMaps": true,
"outDir": "${workspaceRoot}/.vscode/.react"
},
{
"name": "Debug iOS",
"program": "${workspaceRoot}/.vscode/launchReactNative.js",
"type": "reactnative",
"request": "launch",
"platform": "ios",
"target": "iPhone 5s",
"internalDebuggerPort": 9090,
"sourceMaps": true,
"outDir": "${workspaceRoot}/.vscode/.react"
}
],
"configurationAttributes": {
"launch": {
"required": [
"platform",
"program"
],
"properties": {
"platform": {
"type": "string",
"description": "The platform ('ios' or 'android') to target"
},
"program": {
"type": "string",
"description": "The path to launchReactNative.js in the vscode folder"
},
"target": {
"type": "string",
"description": "'simulator', 'device', or the name of the emulator to run on"
},
"internalDebuggerPort": {
"type": "number",
"description": "A port to be used to enable automatic reloading of breakpoints when sourcemaps change.",
"default": 9090
}
}
}
}
"configurationAttributes": {
"launch": {
"required": [
"platform",
"program"
],
"properties": {
"platform": {
"type": "string",
"description": "The platform ('ios' or 'android') to target"
},
"program": {
"type": "string",
"description": "The path to launchReactNative.js in the vscode folder"
},
"target": {
"type": "string",
"description": "'simulator', 'device', or the name of the emulator to run on"
},
"internalDebuggerPort": {
"type": "number",
"description": "A port to be used to enable automatic reloading of breakpoints when sourcemaps change.",
"default": 9090
}
}
]
},
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"compile": "node ./node_modules/vscode/bin/compile -watch -p ./",
"vscode:prepublish": "gulp",
"test": "node ./node_modules/vscode/bin/test"
},
"extensionDependencies": [
"andreweinand.node-debug"
],
"dependencies": {
"applicationinsights": "0.15.8",
"extract-opts": "2.2.0",
"getmac": "1.0.7",
"options": "0.0.6",
"q": "1.4.1",
"semver": "5.1.0",
"typechecker": "2.0.8",
"ultron": "1.0.2",
"winreg": "0.0.16",
"ws": "1.0.1"
},
"devDependencies": {
"del": "2.2.0",
"gulp": "^3.9.0",
"gulp-mocha": "^2.2.0",
"gulp-sourcemaps": "^1.5.2",
"gulp-tslint": "^3.3.1",
"gulp-typescript": "^2.8.0",
"gulp-util": "^3.0.5",
"mocha-teamcity-reporter": "^1.0.0",
"node-find-files": "0.0.4",
"run-sequence": "^1.1.5",
"sinon": "^1.17.3",
"should": "^8.2.2",
"tslint": "^2.5.1",
"typescript": "^1.7.5",
"vsce": "1.0.0",
"vscode": "^0.10.7"
}
}
}
}
}
]
},
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"compile": "node ./node_modules/vscode/bin/compile -watch -p ./",
"vscode:prepublish": "gulp",
"test": "node ./node_modules/vscode/bin/test"
},
"extensionDependencies": [
"andreweinand.node-debug"
],
"dependencies": {
"applicationinsights": "0.15.8",
"extract-opts": "2.2.0",
"getmac": "1.0.7",
"options": "0.0.6",
"q": "1.4.1",
"semver": "5.1.0",
"typechecker": "2.0.8",
"ultron": "1.0.2",
"winreg": "0.0.16",
"ws": "1.0.1"
},
"devDependencies": {
"del": "2.2.0",
"gulp": "^3.9.0",
"gulp-mocha": "^2.2.0",
"gulp-sourcemaps": "^1.5.2",
"gulp-tslint": "^3.3.1",
"gulp-typescript": "^2.8.0",
"gulp-util": "^3.0.5",
"mocha-teamcity-reporter": "^1.0.0",
"run-sequence": "^1.1.5",
"should": "^8.2.2",
"sinon": "^1.17.3",
"through2": "^2.0.1",
"tslint": "^2.5.1",
"typescript": "^1.7.5",
"vsce": "1.0.0",
"vscode": "^0.10.7"
}
}

Просмотреть файл

@ -1,46 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
var fs = require("fs");
var path = require("path");
var os = require("os");
var child_process = require("child_process");
// Recursively find all instances of 'import [...] from "[...]";'
if (os.platform() === "win32") {
child_process.exec("findstr /sir /C:\"import.*from\" *.ts", parseOutput);
} else {
child_process.exec("grep -Ri 'import.*from' .", parseOutput);
}
function parseOutput(err, out, stderr) {
// Extract out the filename containing the match,
// and the relative path of the file it is searching for
var regex = /(\s|^)([^\n:]*):.*from ["'](\.[^"']*)["'];/g;
var imports = [];
out.replace(regex, function (all, _, file, from) {
imports.push({ path: file, relative: from });
});
checkImports(imports);
}
function checkImports(imports) {
// Check to see if the import references a source file
// with an exact match of a name, and complain otherwise
imports.map(function (i) {
i.resolved = path.resolve(path.dirname(i.path), i.relative + ".ts");
return i;
}).filter(function (i) {
var dirpath = path.dirname(i.resolved);
try {
var entries = fs.readdirSync(dirpath);
return entries.indexOf(path.basename(i.resolved)) === -1;
} catch (exception) {
console.log("Missing folder for import in " + i.path + ": " + dirpath);
process.exitCode = 1;
}
}).forEach(function (i) {
console.log("Missing file for import in " + i.path + ": " + i.relative);
process.exitCode = 1;
});
}

Просмотреть файл

@ -1,79 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
"use strict";
/// <reference path="../../node_modules/vscode/typings/node.d.ts" />
/// <reference path="../../src/typings/q/q.d.ts" />
var FindFiles = require("node-find-files");
var fs = require("fs");
var Q = require("q");
var path_module = require("path");
var CopyrightVerifier = (function () {
function CopyrightVerifier() {
this.foundMissing = false;
}
CopyrightVerifier.prototype.findIn = function (path) {
var defer = Q.defer();
var foundFiles = [];
var finder = new FindFiles({
rootFolder: path,
filterFunction: function (path, stat) {
// match only filename
return path.match(CopyrightVerifier.SOURCE_CODE_FILE_PATTERN) && !path.match(CopyrightVerifier.EXCLUDED_FILE_PATTERN);
}
});
finder.on("match", function (filePath, fileStats) {
var contents = fs.readFileSync(filePath).toString().replace(/\r\n/g, "\n");
if (contents.indexOf(CopyrightVerifier.UTB_BYTE_ORDER_MARKER) === 0) {
contents = contents.substr(1);
}
if (!(contents.indexOf(CopyrightVerifier.COPYRIGHT_NOTICE) === 0)) {
foundFiles.push(filePath);
}
});
finder.on("complete", function () {
return defer.resolve(foundFiles);
});
finder.on("patherror", function (err, strPath) {
defer.reject("Error for Path " + strPath + " " + err + "\nStackTrace: " + err.stack);
});
finder.on("error", function (err) {
defer.reject("Global Error " + err);
});
finder.startSearch();
return defer.promise;
};
CopyrightVerifier.prototype.findInAll = function (paths) {
var _this = this;
return Q.all(paths.map(function (path) { return _this.findIn(path_module.resolve(path)); })).then(function (invalids) {
return [].concat.apply([], invalids);
});
};
CopyrightVerifier.prototype.verify = function () {
var paths = [];
for (var _i = 0; _i < arguments.length; _i++) {
paths[_i - 0] = arguments[_i];
}
return this.findInAll(paths).done(function (filePaths) {
if (filePaths.length !== 0) {
process.stderr.write("Found files which don't match the expected copyright notice:\n");
filePaths.forEach(function (filePath) { return process.stderr.write("\t" + filePath + "\n"); });
process.exit(1);
}
else {
process.exit(0);
}
}, function (reason) {
process.stderr.write("Uknown error while trying to check files copyright: " + reason);
process.exit(1);
});
};
CopyrightVerifier.UTB_BYTE_ORDER_MARKER = "\ufeff";
CopyrightVerifier.SOURCE_CODE_FILE_PATTERN = /.*\.(ts|js)$/;
CopyrightVerifier.EXCLUDED_FILE_PATTERN = /.*\.d\.ts/;
CopyrightVerifier.COPYRIGHT_NOTICE = "// Copyright (c) Microsoft Corporation. All rights reserved.\n" +
"// Licensed under the MIT license. See LICENSE file in the project root for details.\n";
return CopyrightVerifier;
}());
new CopyrightVerifier().verify("../src", "../tools");
//# sourceMappingURL=checkCopyright.js.map

101
tools/gulp-extras.js Normal file
Просмотреть файл

@ -0,0 +1,101 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
"use strict";
var fs = require("fs");
var gutil = require("gulp-util");
var path = require("path");
var through = require("through2");
/**
* Pretty logger using gutil.log
* @param {string} pluginName Name of the pluginName
* @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("../","");
gutil.log(`[${gutil.colors.cyan(pluginName)}] ${gutil.colors.red("error")} ${sourcePath}: ${message}`);
};
/**
* Helper function to return a list of matches for a given pattern
* @param {string|RegExp} pattern The pattern to match against
* @param {string} text The text to search
* @returns {string[]} An array of matches
*/
var find = function(pattern, text) {
var results = [];
text.toString().replace(pattern, function(match) {
results.push(match);
});
return results;
};
/**
* Plugin to verify the Microsoft copyright notice is present
*/
var checkCopyright = function() {
var re = /\/\/ Copyright \(c\) Microsoft Corporation. All rights reserved.\s+\/\/ Licensed under the MIT license. See LICENSE file in the project root for details.\s+/
return through.obj(function(file, encoding, callback) {
if (file.isBuffer() && !file.path.endsWith(".d.ts")) {
var fileContents = file.contents.toString(encoding);
var matches = re.exec(fileContents);
if (!matches) {
logError("check-copyright", file, "missing copyright notice");
}
}
callback(null, file);
});
};
/**
* 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) {
if (fs.existsSync(filePath)) {
var 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 re = /(?:\s|^)(?:[^\n:]*).*from ["'](\.[^"']*)["'];/g;
return through.obj(function(file, encoding, callback) {
if (file.isBuffer() && !file.path.endsWith(".d.ts")) {
var fileContents = file.contents.toString(encoding);
var importStatements = find(re, fileContents);
var workingDirectory = path.dirname(file.path);
importStatements.forEach(function(importStatement) {
var modulePath = re.exec(importStatement);
if (modulePath && modulePath.length === 2) {
var moduleFilePath = path.resolve(workingDirectory, modulePath[1] + ".ts");
if (!existsCaseSensitive(moduleFilePath)) {
logError("check-imports", file, `unresolved import: ${modulePath[1]}`);
}
}
});
}
callback(null, file);
});
};
module.exports = {
checkCopyright: checkCopyright,
checkImports: checkImports
}