Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ typings/
.next

# TypeScript
dist/
build/

# IntelliJ stuff
.idea/

yarn.lock
2 changes: 2 additions & 0 deletions dist/bin/code-complexity.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
export {};
8 changes: 8 additions & 0 deletions dist/bin/code-complexity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env node
"use strict";
exports.__esModule = true;
var io_1 = require("../src/io");
io_1["default"]()["catch"](function (error) {
console.error(error);
process.exit(1);
});
72 changes: 72 additions & 0 deletions dist/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"name": "code-complexity",
"version": "4.1.0",
"description": "Measure the churn/complexity score. Higher values mean hotspots where refactorings should happen.",
"author": {
"name": "Simon Renoult",
"email": "contact@simonrenoult.me"
},
"main": "dist/src/lib",
"types": "dist/src/lib/types.d.ts",
"bin": {
"code-complexity": "dist/bin/code-complexity.js"
},
"repository": {
"type": "git",
"url": "https://github.com/simonrenoult/code-complexity"
},
"bugs": {
"url": "https://github.com/simonrenoult/code-complexity/issues"
},
"scripts": {
"build": "rm -rf dist && tsc",
"coverage": "codecov",
"lint": "eslint --ext .ts .",
"prepare": "npm run lint && npm run build",
"postversion": "git push --tags",
"pretest": "npm run lint",
"test": "mocha --require ts-node/register test/**/*.ts",
"test:ci": "nyc --reporter=lcov npm test"
},
"keywords": [
"quality",
"complexity",
"churn",
"refactoring",
"sloc",
"commit"
],
"license": "MIT",
"dependencies": {
"cli-table3": "^0.6.0",
"code-complexity": "l-marcel/code-complexity#module",
"commander": "^5.0.0",
"debug": "^4.1.1",
"del": "^6.0.0",
"micromatch": "^4.0.2",
"node-sloc": "^0.1.12",
"simple-git": "^3.7.1"
},
"devDependencies": {
"@types/chai": "^4.2.11",
"@types/debug": "^4.1.5",
"@types/micromatch": "^4.0.1",
"@types/mocha": "^7.0.2",
"@types/node": "^13.13.0",
"@typescript-eslint/eslint-plugin": "^2.28.0",
"@typescript-eslint/parser": "^2.28.0",
"chai": "^4.2.0",
"codecov": "^3.6.5",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.1",
"eslint-plugin-import": "^2.20.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.1.3",
"eslint-plugin-promise": "^4.2.1",
"mocha": "^7.1.1",
"nyc": "^15.0.1",
"prettier": "^2.0.4",
"ts-node": "^8.8.2",
"typescript": "^3.8.3"
}
}
8 changes: 8 additions & 0 deletions dist/src/io/cli.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Command, Options } from "../lib/types";
declare const _default: {
parse: typeof parse;
cleanup: typeof cleanup;
};
export default _default;
declare function parse(params?: Command): Promise<Options>;
declare function cleanup(options: Options): Promise<void>;
189 changes: 189 additions & 0 deletions dist/src/io/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
var commander = require("commander");
var url_1 = require("url");
var fs_1 = require("fs");
var simple_git_1 = require("simple-git");
var utils_1 = require("../utils");
var del = require("del");
var internal = { debug: utils_1.buildDebugger("cli") };
exports["default"] = { parse: parse, cleanup: cleanup };
function parse(params) {
return __awaiter(this, void 0, void 0, function () {
var cli, options, _a, description, version;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!!params) return [3 /*break*/, 3];
return [4 /*yield*/, utils_1.getPackageJson()];
case 1:
_a = _b.sent(), description = _a.description, version = _a.version;
cli = getRawCli(description, version).parse(process.argv);
assertArgsAreProvided(cli);
return [4 /*yield*/, buildOptions(cli)];
case 2:
options = _b.sent();
return [3 /*break*/, 5];
case 3: return [4 /*yield*/, buildOptions(params)];
case 4:
options = _b.sent();
_b.label = 5;
case 5:
;
internal.debug("applying options: " + JSON.stringify(options));
return [2 /*return*/, options];
}
});
});
}
function cleanup(options) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(options.target.startsWith("https://") || options.target.startsWith("http://"))) return [3 /*break*/, 2];
return [4 /*yield*/, del(options.directory)];
case 1:
_a.sent();
_a.label = 2;
case 2: return [2 /*return*/];
}
});
});
}
function getRawCli(description, version) {
return commander
.usage("<target> [options]")
.version(version || "")
.description(description || "")
.option("--filter <strings>", "list of globs (comma separated) to filter", commaSeparatedList)
.option("-f, --format [format]", "format results using table or json", /^(table|json|csv)$/i)
.option("-l, --limit [limit]", "limit the number of files to output", parseInt)
.option("-i, --since [since]", "limit analysis to commits more recent in age than date")
.option("-u, --until [until]", "limit analysis to commits older in age than date")
.option("-s, --sort [sort]", "sort results (allowed valued: score, churn, complexity or file)", /^(score|churn|complexity|file)$/i)
.on("--help", function () {
console.log();
console.log("Examples:");
console.log();
[
"$ code-complexity .",
"$ code-complexity https://github.com/simonrenoult/code-complexity",
"$ code-complexity foo --limit 3",
"$ code-complexity ../foo --sort score",
"$ code-complexity /foo/bar --filter 'src/**,!src/front/**'",
"$ code-complexity . --limit 10 --sort score",
].forEach(function (example) { return console.log(example.padStart(2)); });
});
}
function buildOptions(cli) {
return __awaiter(this, void 0, void 0, function () {
// FIXME: I'm not a fan of pulling the code here but it's good enough.
function parseDirectory(target) {
return __awaiter(this, void 0, void 0, function () {
var tmp;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(target.startsWith("https://github.com/") || target.startsWith("http://github.com/"))) return [3 /*break*/, 2];
tmp = "src/temp/" + (target === null || target === void 0 ? void 0 : target.split("//github.com/")[1].replace(/\//g, "-")) + "-" + new Date().getTime();
//old: execSync(`git clone ${target} ${tmp}`, { stdio: "ignore" });
return [4 /*yield*/, simple_git_1["default"]().clone(target, tmp)];
case 1:
//old: execSync(`git clone ${target} ${tmp}`, { stdio: "ignore" });
_a.sent();
return [2 /*return*/, tmp];
case 2: return [2 /*return*/, target];
}
});
});
}
function parseTarget(target) {
try {
return new url_1.URL(target); // \o/ typescript momments
}
catch (e) {
try {
fs_1.lstatSync(target);
return target;
}
catch (e) {
throw new Error("Argument 'target' is neither a directory nor a valid URL.");
}
}
}
var target, _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (cli.target) {
target = String(cli.target);
}
else if (cli.args[0]) {
target = parseTarget(cli.args[0]);
}
else {
throw new Error("Target is not defined.");
}
;
_a = {
target: target
};
return [4 /*yield*/, parseDirectory(target)];
case 1: return [2 /*return*/, (_a.directory = _b.sent(),
_a.format = cli.format ? String(cli.format) : "table",
_a.filter = cli.filter || [],
_a.limit = cli.limit ? Number(cli.limit) : undefined,
_a.since = cli.since ? String(cli.since) : undefined,
_a.until = cli.until ? String(cli.until) : undefined,
_a.sort = cli.sort ? String(cli.sort) : undefined,
_a)];
}
});
});
}
function commaSeparatedList(value) {
return value.split(",");
}
function assertArgsAreProvided(internalCli) {
if (!internalCli.args || !internalCli.args.length) {
internalCli.help();
process.exit(1);
}
}
1 change: 1 addition & 0 deletions dist/src/io/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default function main(): Promise<void>;
60 changes: 60 additions & 0 deletions dist/src/io/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
var lib_1 = require("../lib");
var cli_1 = require("./cli");
var output_1 = require("./output");
function main() {
return __awaiter(this, void 0, void 0, function () {
var options, statistics;
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, cli_1["default"].parse()];
case 1:
options = _a.sent();
return [4 /*yield*/, lib_1["default"].compute(options)];
case 2:
statistics = _a.sent();
cli_1["default"].cleanup(options);
output_1["default"].render(statistics, options);
return [2 /*return*/];
}
});
});
}
exports["default"] = main;
4 changes: 4 additions & 0 deletions dist/src/io/output.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare const _default: {
render: (...args: any[]) => void;
};
export default _default;
Loading