analyze-codebase 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.development +1 -0
- package/LICENSE +21 -0
- package/dist/analyze/file/fileName.d.ts +1 -0
- package/dist/analyze/file/fileName.js +35 -0
- package/dist/analyze/file/index.d.ts +4 -0
- package/dist/analyze/file/index.js +36 -0
- package/dist/analyze/index.d.ts +2 -0
- package/dist/analyze/index.js +51 -0
- package/dist/analyze/sourceCode/lineCount.d.ts +12 -0
- package/dist/analyze/sourceCode/lineCount.js +90 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +34 -0
- package/dist/runner.d.ts +5 -0
- package/dist/runner.js +7 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.js +2 -0
- package/dist/utils/file.d.ts +9 -0
- package/dist/utils/file.js +60 -0
- package/dist/utils/index.d.ts +23 -0
- package/dist/utils/index.js +44 -0
- package/dist/utils/output.d.ts +9 -0
- package/dist/utils/output.js +44 -0
- package/example-output.png +0 -0
- package/package.json +37 -0
- package/readme.md +132 -0
- package/tsconfig.json +16 -0
package/.env.development
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
EXAMPLE_SCRIPT= "yarn cli ../../projects/PowerDev-Portal/ --extensions .js .ts .tsx .jsx --exclude node_modules public .log .next"
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Taha GÖÇER
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const analyzeFileName: (filePath: string) => import("../../utils").NamingCase;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.analyzeFileName = void 0;
|
|
27
|
+
const path = __importStar(require("path"));
|
|
28
|
+
const utils_1 = require("../../utils");
|
|
29
|
+
const analyzeFileName = (filePath) => {
|
|
30
|
+
// Example: Check if file name contains uppercase characters
|
|
31
|
+
const fileName = path.basename(filePath);
|
|
32
|
+
const fileNameWithoutExtension = fileName.split(path.extname(fileName))[0];
|
|
33
|
+
return (0, utils_1.whatCase)(fileNameWithoutExtension);
|
|
34
|
+
};
|
|
35
|
+
exports.analyzeFileName = analyzeFileName;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.analyzeFile = void 0;
|
|
27
|
+
const path = __importStar(require("path"));
|
|
28
|
+
const fileName_1 = require("../../analyze/file/fileName");
|
|
29
|
+
const lineCount_1 = require("../../analyze/sourceCode/lineCount");
|
|
30
|
+
const analyzeFile = (filePath, output) => {
|
|
31
|
+
const fileName = path.basename(filePath);
|
|
32
|
+
const fileNameCase = (0, fileName_1.analyzeFileName)(fileName);
|
|
33
|
+
(0, lineCount_1.analyzeLineCountByCategory)(filePath, output);
|
|
34
|
+
return { fileNameCase };
|
|
35
|
+
};
|
|
36
|
+
exports.analyzeFile = analyzeFile;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.analyzeCodebase = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const file_1 = require("../analyze/file");
|
|
9
|
+
const file_2 = require("../utils/file");
|
|
10
|
+
const output_1 = require("../utils/output");
|
|
11
|
+
const analyzeCodebase = async (options) => {
|
|
12
|
+
const start = Date.now();
|
|
13
|
+
const fileNameCases = {};
|
|
14
|
+
const output = {
|
|
15
|
+
Physical: 0,
|
|
16
|
+
Source: 0,
|
|
17
|
+
Comment: 0,
|
|
18
|
+
SingleLineComment: 0,
|
|
19
|
+
BlockComment: 0,
|
|
20
|
+
Mixed: 0,
|
|
21
|
+
EmptyBlockComment: 0,
|
|
22
|
+
Empty: 0,
|
|
23
|
+
ToDo: 0
|
|
24
|
+
};
|
|
25
|
+
console.log(chalk_1.default.bold(`\n\nAnalyzing codebase in ${chalk_1.default.cyan(options.directory)} ${(options === null || options === void 0 ? void 0 : options.framework) ? `framework: ${chalk_1.default.cyan(options.framework)}` : ""}\n`));
|
|
26
|
+
let fileCount = 0;
|
|
27
|
+
await (0, file_2.traverseDirectory)({
|
|
28
|
+
extensions: options.extensions,
|
|
29
|
+
directory: options.directory,
|
|
30
|
+
exclude: options.exclude,
|
|
31
|
+
checkFileNames: options.checkFileNames,
|
|
32
|
+
onFile: (filePath) => {
|
|
33
|
+
fileCount++;
|
|
34
|
+
const { fileNameCase } = (0, file_1.analyzeFile)(filePath, output);
|
|
35
|
+
//@ts-ignore
|
|
36
|
+
if (fileNameCases[fileNameCase] !== undefined)
|
|
37
|
+
fileNameCases[fileNameCase] += 1;
|
|
38
|
+
else
|
|
39
|
+
fileNameCases[fileNameCase] = 0;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
(0, output_1.logOutput)({
|
|
43
|
+
fileCount,
|
|
44
|
+
fileNameCases,
|
|
45
|
+
options,
|
|
46
|
+
output
|
|
47
|
+
});
|
|
48
|
+
const totalSecond = ((Date.now() - start) / 1000).toFixed(2);
|
|
49
|
+
console.log(chalk_1.default.bold(`Time taken: ${chalk_1.default.yellow(totalSecond)}s\n`));
|
|
50
|
+
};
|
|
51
|
+
exports.analyzeCodebase = analyzeCodebase;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ICodeContentType } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Analyze the line count of the specified file
|
|
4
|
+
*/
|
|
5
|
+
export declare const analyzeLineCount: (filePath: string) => number;
|
|
6
|
+
export declare const isSingleLineComment: (line?: string) => boolean;
|
|
7
|
+
export declare const isBlockComment: (line?: string) => boolean;
|
|
8
|
+
export declare const isMixedComment: (line?: string) => boolean;
|
|
9
|
+
export declare const isEmptyBlockComment: (line?: string) => boolean;
|
|
10
|
+
export declare const isComment: (line?: string) => boolean;
|
|
11
|
+
export declare const isToDo: (line?: string) => boolean;
|
|
12
|
+
export declare const analyzeLineCountByCategory: (filePath: string, output: ICodeContentType) => ICodeContentType;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.analyzeLineCountByCategory = exports.isToDo = exports.isComment = exports.isEmptyBlockComment = exports.isMixedComment = exports.isBlockComment = exports.isSingleLineComment = exports.analyzeLineCount = void 0;
|
|
27
|
+
const fs = __importStar(require("fs"));
|
|
28
|
+
/**
|
|
29
|
+
* Analyze the line count of the specified file
|
|
30
|
+
*/
|
|
31
|
+
const analyzeLineCount = (filePath) => {
|
|
32
|
+
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
33
|
+
return fileContent.split('\n').length;
|
|
34
|
+
};
|
|
35
|
+
exports.analyzeLineCount = analyzeLineCount;
|
|
36
|
+
const isSingleLineComment = (line = "") => line.startsWith('//');
|
|
37
|
+
exports.isSingleLineComment = isSingleLineComment;
|
|
38
|
+
const isBlockComment = (line = "") => line.startsWith('/*') && line.endsWith('*/');
|
|
39
|
+
exports.isBlockComment = isBlockComment;
|
|
40
|
+
const isMixedComment = (line = "") => (line.startsWith('/*') && !line.endsWith('*/')) || line.startsWith('*');
|
|
41
|
+
exports.isMixedComment = isMixedComment;
|
|
42
|
+
const isEmptyBlockComment = (line = "") => line.startsWith('/*') && !line.endsWith('*/');
|
|
43
|
+
exports.isEmptyBlockComment = isEmptyBlockComment;
|
|
44
|
+
const isComment = (line = "") => {
|
|
45
|
+
return (0, exports.isSingleLineComment)(line) || (0, exports.isBlockComment)(line) || (0, exports.isMixedComment)(line) || (0, exports.isEmptyBlockComment)(line);
|
|
46
|
+
};
|
|
47
|
+
exports.isComment = isComment;
|
|
48
|
+
const isToDo = (line = "") => {
|
|
49
|
+
return (line.includes('TODO'));
|
|
50
|
+
};
|
|
51
|
+
exports.isToDo = isToDo;
|
|
52
|
+
const analyzeLineCountByCategory = (filePath, output) => {
|
|
53
|
+
var _a;
|
|
54
|
+
const fileContent = fs.readFileSync(filePath, 'utf8');
|
|
55
|
+
const lines = fileContent.split('\n') || "";
|
|
56
|
+
let lineIndex = 0;
|
|
57
|
+
while (lineIndex < lines.length) {
|
|
58
|
+
const line = lines[lineIndex].trim();
|
|
59
|
+
output.Physical++;
|
|
60
|
+
if (line === '')
|
|
61
|
+
output.Empty++;
|
|
62
|
+
else if ((0, exports.isSingleLineComment)(line)) {
|
|
63
|
+
output.SingleLineComment++;
|
|
64
|
+
output.Comment++;
|
|
65
|
+
}
|
|
66
|
+
else if ((0, exports.isBlockComment)(line)) {
|
|
67
|
+
output.BlockComment++;
|
|
68
|
+
output.Comment++;
|
|
69
|
+
}
|
|
70
|
+
else if ((0, exports.isMixedComment)(line)) {
|
|
71
|
+
output.Mixed++;
|
|
72
|
+
output.Comment++;
|
|
73
|
+
let blockCommentLines = 0;
|
|
74
|
+
while (lineIndex < lines.length && !((_a = lines[lineIndex]) === null || _a === void 0 ? void 0 : _a.endsWith('*/'))) {
|
|
75
|
+
blockCommentLines++;
|
|
76
|
+
lineIndex++;
|
|
77
|
+
}
|
|
78
|
+
if ((0, exports.isEmptyBlockComment)(line))
|
|
79
|
+
output.EmptyBlockComment += blockCommentLines;
|
|
80
|
+
else
|
|
81
|
+
output.BlockComment += blockCommentLines;
|
|
82
|
+
}
|
|
83
|
+
if ((0, exports.isToDo)(line))
|
|
84
|
+
output.ToDo++;
|
|
85
|
+
lineIndex++;
|
|
86
|
+
}
|
|
87
|
+
output.Source = output.Physical - output.Comment - output.Empty - output.ToDo;
|
|
88
|
+
return output;
|
|
89
|
+
};
|
|
90
|
+
exports.analyzeLineCountByCategory = analyzeLineCountByCategory;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
7
|
+
const commander_1 = require("commander");
|
|
8
|
+
const runner_1 = __importDefault(require("./runner"));
|
|
9
|
+
chalk_1.default.level = 3;
|
|
10
|
+
commander_1.program
|
|
11
|
+
.arguments('<directory>')
|
|
12
|
+
.description('Analyze the specified directory')
|
|
13
|
+
.option('-f, --framework <framework>', 'Specify the framework')
|
|
14
|
+
.option('-e, --extensions <extensions...>', 'Specify the extensions', (value, previous) => previous.concat(value), [])
|
|
15
|
+
.option('-exc, --exclude <exclude...>', 'Specify the exclude', (value, previous) => previous.concat(value), [])
|
|
16
|
+
.option('--checkFileNames [checkFileNames]', 'Check file names', parseBoolean)
|
|
17
|
+
.option('--checkFileContent [checkFileContent]', 'Check directories', parseBoolean)
|
|
18
|
+
.action((directory, options) => {
|
|
19
|
+
var _a, _b, _c;
|
|
20
|
+
if (options.checkFileNames === false && options.checkFileContent === false) {
|
|
21
|
+
return console.error(chalk_1.default.red(`\nError: You must specify ${chalk_1.default.yellow("true")} at least one of the following options: ${chalk_1.default.yellow("--checkFileNames")}, ${chalk_1.default.yellow("--checkFileContent")}\n`));
|
|
22
|
+
}
|
|
23
|
+
if ((_a = options === null || options === void 0 ? void 0 : options.extensions) === null || _a === void 0 ? void 0 : _a.find((d) => !d.includes('.'))) {
|
|
24
|
+
return console.error(chalk_1.default.red('\nError: Extensions must include a dot (.)\n'));
|
|
25
|
+
}
|
|
26
|
+
(0, runner_1.default)({ ...options, directory, checkFileContent: (_b = options.checkFileContent) !== null && _b !== void 0 ? _b : true, checkFileNames: (_c = options.checkFileNames) !== null && _c !== void 0 ? _c : true });
|
|
27
|
+
});
|
|
28
|
+
commander_1.program.parse(process.argv);
|
|
29
|
+
function parseBoolean(value) {
|
|
30
|
+
if (typeof value === 'undefined') {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
return value.toLowerCase() === 'true';
|
|
34
|
+
}
|
package/dist/runner.d.ts
ADDED
package/dist/runner.js
ADDED
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface IAnalysisOptions {
|
|
2
|
+
directory: string;
|
|
3
|
+
framework?: string;
|
|
4
|
+
extensions?: string[];
|
|
5
|
+
exclude?: string[];
|
|
6
|
+
conventions?: string[];
|
|
7
|
+
checkFileNames?: boolean;
|
|
8
|
+
checkFileContent?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface IViolation {
|
|
11
|
+
filePath: string;
|
|
12
|
+
message: string;
|
|
13
|
+
type: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Identifier {
|
|
16
|
+
name: string;
|
|
17
|
+
line: number;
|
|
18
|
+
}
|
|
19
|
+
export interface ICodeContentType {
|
|
20
|
+
Physical: number;
|
|
21
|
+
Source: number;
|
|
22
|
+
Comment: number;
|
|
23
|
+
SingleLineComment: number;
|
|
24
|
+
BlockComment: number;
|
|
25
|
+
Mixed: number;
|
|
26
|
+
EmptyBlockComment: number;
|
|
27
|
+
Empty: number;
|
|
28
|
+
ToDo: number;
|
|
29
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface ITraverseDirectoryProps {
|
|
2
|
+
directory: string;
|
|
3
|
+
exclude?: string[];
|
|
4
|
+
extensions?: string[];
|
|
5
|
+
checkFileNames?: boolean;
|
|
6
|
+
onFile: (filePath: string) => void;
|
|
7
|
+
onDirectory?: (dirPath: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare const traverseDirectory: ({ directory, onFile, onDirectory, exclude, extensions, checkFileNames, }: ITraverseDirectoryProps) => Promise<void>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.traverseDirectory = void 0;
|
|
27
|
+
const fs = __importStar(require("fs/promises"));
|
|
28
|
+
const path = __importStar(require("path"));
|
|
29
|
+
const traverseDirectory = async ({ directory, onFile, onDirectory, exclude, extensions, checkFileNames = true, }) => {
|
|
30
|
+
const files = await fs.readdir(directory, { withFileTypes: true });
|
|
31
|
+
const tasks = files.map(async (file) => {
|
|
32
|
+
const filePath = path.join(directory, file.name);
|
|
33
|
+
if (exclude === null || exclude === void 0 ? void 0 : exclude.length) {
|
|
34
|
+
if (exclude.includes(file.name))
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (file.isDirectory()) {
|
|
38
|
+
onDirectory === null || onDirectory === void 0 ? void 0 : onDirectory(filePath);
|
|
39
|
+
await (0, exports.traverseDirectory)({
|
|
40
|
+
directory: filePath,
|
|
41
|
+
onFile,
|
|
42
|
+
exclude,
|
|
43
|
+
extensions,
|
|
44
|
+
onDirectory,
|
|
45
|
+
checkFileNames,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else if (checkFileNames) {
|
|
49
|
+
const ext = path.extname(file.name);
|
|
50
|
+
if (extensions === null || extensions === void 0 ? void 0 : extensions.length) {
|
|
51
|
+
if (extensions.includes(ext))
|
|
52
|
+
onFile(filePath);
|
|
53
|
+
}
|
|
54
|
+
else
|
|
55
|
+
onFile(filePath);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
await Promise.all(tasks);
|
|
59
|
+
};
|
|
60
|
+
exports.traverseDirectory = traverseDirectory;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare enum NamingCase {
|
|
2
|
+
CamelCase = "CamelCase",
|
|
3
|
+
PascalCase = "PascalCase",
|
|
4
|
+
SnakeCase = "SnakeCase",
|
|
5
|
+
UpperCase = "UpperCase",
|
|
6
|
+
LowerCase = "LowerCase",
|
|
7
|
+
KebabCase = "KebabCase",
|
|
8
|
+
StartCase = "StartCase",
|
|
9
|
+
DotCase = "DotCase",
|
|
10
|
+
PathCase = "PathCase",
|
|
11
|
+
SpaceCase = "SpaceCase",
|
|
12
|
+
NoCase = "NoCase",
|
|
13
|
+
ConstantCase = "ConstantCase",
|
|
14
|
+
SentenceCase = "SentenceCase",
|
|
15
|
+
Unknown = "Unknown"
|
|
16
|
+
}
|
|
17
|
+
export declare const NamingCases: Record<NamingCase, RegExp>;
|
|
18
|
+
export declare const NamingCasesArray: {
|
|
19
|
+
regexp: RegExp;
|
|
20
|
+
type: NamingCase;
|
|
21
|
+
}[];
|
|
22
|
+
export declare const controlCase: (str: string, caseType: NamingCase) => boolean;
|
|
23
|
+
export declare const whatCase: (str: string) => NamingCase;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.whatCase = exports.controlCase = exports.NamingCasesArray = exports.NamingCases = exports.NamingCase = void 0;
|
|
4
|
+
var NamingCase;
|
|
5
|
+
(function (NamingCase) {
|
|
6
|
+
NamingCase["CamelCase"] = "CamelCase";
|
|
7
|
+
NamingCase["PascalCase"] = "PascalCase";
|
|
8
|
+
NamingCase["SnakeCase"] = "SnakeCase";
|
|
9
|
+
NamingCase["UpperCase"] = "UpperCase";
|
|
10
|
+
NamingCase["LowerCase"] = "LowerCase";
|
|
11
|
+
NamingCase["KebabCase"] = "KebabCase";
|
|
12
|
+
NamingCase["StartCase"] = "StartCase";
|
|
13
|
+
NamingCase["DotCase"] = "DotCase";
|
|
14
|
+
NamingCase["PathCase"] = "PathCase";
|
|
15
|
+
NamingCase["SpaceCase"] = "SpaceCase";
|
|
16
|
+
NamingCase["NoCase"] = "NoCase";
|
|
17
|
+
NamingCase["ConstantCase"] = "ConstantCase";
|
|
18
|
+
NamingCase["SentenceCase"] = "SentenceCase";
|
|
19
|
+
NamingCase["Unknown"] = "Unknown";
|
|
20
|
+
})(NamingCase = exports.NamingCase || (exports.NamingCase = {}));
|
|
21
|
+
exports.NamingCases = {
|
|
22
|
+
[NamingCase.CamelCase]: /^[a-z][a-zA-Z0-9]*$/,
|
|
23
|
+
[NamingCase.PascalCase]: /^[A-Z][a-zA-Z0-9]*$/,
|
|
24
|
+
[NamingCase.SnakeCase]: /^[a-z][a-z0-9_]*$/,
|
|
25
|
+
[NamingCase.UpperCase]: /^[A-Z][A-Z0-9]*$/,
|
|
26
|
+
[NamingCase.LowerCase]: /^[a-z][a-z0-9]*$/,
|
|
27
|
+
[NamingCase.KebabCase]: /^[a-z][a-z0-9-]*$/,
|
|
28
|
+
[NamingCase.StartCase]: /^[A-Z][a-z0-9 ]*$/,
|
|
29
|
+
[NamingCase.DotCase]: /^[a-z][a-z0-9.]*$/,
|
|
30
|
+
[NamingCase.PathCase]: /^[a-z][a-z0-9/]*$/,
|
|
31
|
+
[NamingCase.SpaceCase]: /^[a-z][a-z0-9 ]*$/,
|
|
32
|
+
[NamingCase.NoCase]: /^[a-z][a-z0-9]*$/,
|
|
33
|
+
[NamingCase.ConstantCase]: /^[A-Z][A-Z0-9_]*$/,
|
|
34
|
+
[NamingCase.SentenceCase]: /^[A-Z][a-z0-9 ]*$/,
|
|
35
|
+
[NamingCase.Unknown]: /^.*$/
|
|
36
|
+
};
|
|
37
|
+
exports.NamingCasesArray = Object.entries(exports.NamingCases).map(([type, regexp]) => ({
|
|
38
|
+
regexp,
|
|
39
|
+
type: type
|
|
40
|
+
}));
|
|
41
|
+
const controlCase = (str, caseType) => exports.NamingCases[caseType].test(str);
|
|
42
|
+
exports.controlCase = controlCase;
|
|
43
|
+
const whatCase = (str) => { var _a; return ((_a = exports.NamingCasesArray.find(({ regexp }) => regexp.test(str))) === null || _a === void 0 ? void 0 : _a.type) || NamingCase.Unknown; };
|
|
44
|
+
exports.whatCase = whatCase;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NamingCase } from ".";
|
|
2
|
+
import { IAnalysisOptions, ICodeContentType } from "../types";
|
|
3
|
+
export interface IParams {
|
|
4
|
+
output: ICodeContentType;
|
|
5
|
+
fileCount: number;
|
|
6
|
+
options: IAnalysisOptions;
|
|
7
|
+
fileNameCases: Partial<Record<NamingCase, number>>;
|
|
8
|
+
}
|
|
9
|
+
export declare const logOutput: ({ fileCount, output, fileNameCases, options }: IParams) => void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.logOutput = void 0;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
9
|
+
const logOutput = ({ fileCount, output, fileNameCases, options }) => {
|
|
10
|
+
console.log(chalk_1.default.bold('------------- Result -------------\n'));
|
|
11
|
+
if (fileCount === 0) {
|
|
12
|
+
console.log(chalk_1.default.red(`No files found in ${chalk_1.default.cyan(options.directory)} with extensions ${chalk_1.default.cyan(options.extensions)}\n`));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
if (options.checkFileNames) {
|
|
16
|
+
console.log(chalk_1.default.bold('File Name Summary:\n'));
|
|
17
|
+
const fileNameTable = new cli_table3_1.default({
|
|
18
|
+
head: [chalk_1.default.bold('File Name Case'), chalk_1.default.bold('Count'), chalk_1.default.bold('Percentage')],
|
|
19
|
+
colWidths: [30, 10, 15],
|
|
20
|
+
});
|
|
21
|
+
Object.entries(fileNameCases).forEach(([key, value]) => {
|
|
22
|
+
const percentage = ((value / fileCount) * 100).toFixed(2);
|
|
23
|
+
fileNameTable.push([key, value.toString(), `${percentage}%`]);
|
|
24
|
+
});
|
|
25
|
+
console.log(fileNameTable.toString());
|
|
26
|
+
console.log('\n');
|
|
27
|
+
}
|
|
28
|
+
if (options.checkFileContent) {
|
|
29
|
+
console.log(chalk_1.default.bold('Content Type Summary:\n'));
|
|
30
|
+
const contentTypeTable = new cli_table3_1.default({
|
|
31
|
+
head: [chalk_1.default.bold('Content Type'), chalk_1.default.bold('Count'), chalk_1.default.bold('Percentage')],
|
|
32
|
+
colWidths: [30, 10, 15],
|
|
33
|
+
});
|
|
34
|
+
Object.entries(output).forEach(([key, value]) => {
|
|
35
|
+
const percentage = ((value / output.Physical) * 100).toFixed(2);
|
|
36
|
+
contentTypeTable.push([key, value.toString(), `${percentage}%`]);
|
|
37
|
+
});
|
|
38
|
+
console.log(contentTypeTable.toString());
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
console.log(chalk_1.default.bold('\n----------------------------'));
|
|
42
|
+
console.log(chalk_1.default.bold(`\nNumber of files read: ${chalk_1.default.yellow(fileCount)}\n`));
|
|
43
|
+
};
|
|
44
|
+
exports.logOutput = logOutput;
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "analyze-codebase",
|
|
3
|
+
"description": "Codebase Analyzer",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/mtahagocer/analyze-codebase"
|
|
7
|
+
},
|
|
8
|
+
"version": "1.0.0",
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"bin": {
|
|
12
|
+
"analyze-project": "dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"cli": "ts-node ./src/index.ts",
|
|
16
|
+
"start": "node ./dist/index.js",
|
|
17
|
+
"compile": "npx rimraf dist && npx tsc"
|
|
18
|
+
},
|
|
19
|
+
"contributes": {
|
|
20
|
+
"commands": [
|
|
21
|
+
{
|
|
22
|
+
"command": "extension.analyzeCode",
|
|
23
|
+
"title": "Analyze Codebase"
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^20.1.5",
|
|
29
|
+
"typescript": "^5.0.4",
|
|
30
|
+
"ts-node": "^10.9.1"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"chalk": "4.1.0",
|
|
34
|
+
"cli-table3": "^0.6.3",
|
|
35
|
+
"commander": "^10.0.1"
|
|
36
|
+
}
|
|
37
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
|
|
2
|
+
# Codebase Analyzer
|
|
3
|
+
|
|
4
|
+
Codebase Analyzer is a command-line tool that analyzes a specified directory and provides summary information about the code files it contains. It can help you gain insights into your codebase's structure, naming conventions, and content types.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- Analyzes the specified directory recursively
|
|
12
|
+
- Provides summary information about file name cases and content types
|
|
13
|
+
- Supports filtering by file extensions and excluding specific directories/files
|
|
14
|
+
- Customizable through command-line options
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
You can install Codebase Analyzer globally using NPM:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g analyze-codebase
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
To analyze a directory, use the analyze command followed by the directory path. Here's an example:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
analyze-codebase analyze ./src
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Options
|
|
33
|
+
|
|
34
|
+
- -f, --framework <framework>: Specify the framework used in the codebase.
|
|
35
|
+
- -e, --extensions <extensions...>: Specify the file extensions to include in the analysis. You can provide multiple extensions separated by spaces. Example: -e .js .ts.
|
|
36
|
+
|
|
37
|
+
- -e, --exclude <exclude...>: Specify directories or files to exclude from the analysis. You can provide multiple paths separated by spaces. Example: -e node_modules dist.
|
|
38
|
+
|
|
39
|
+
- --checkFileNames [checkFileNames]: Check file names. Default: true.
|
|
40
|
+
|
|
41
|
+
- --checkFileContent [checkFileContent]: Check file content. Default: true.
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
Analyze a directory with default options:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
analyze-codebase analyze ./src
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Analyze a directory with a specified framework and file extensions:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
analyze-codebase analyze ./src -f react --extensions .js .jsx .ts .tsx
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Exclude specific directories from the analysis:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
analyze-codebase analyze ./src --exclude node_modules dist
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Analyze only file names
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
analyze-codebase analyze ./src --exclude node_modules dist --checkFileContent=false
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Analyze only file content
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
analyze-codebase analyze ./src --exclude node_modules dist --checkFileNames=false
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Contribution
|
|
76
|
+
|
|
77
|
+
We welcome contributions to enhance the functionality and features of Codebase Analyzer. To contribute to the project, please follow these steps:
|
|
78
|
+
|
|
79
|
+
Fork the repository by clicking on the "Fork" button at the top right corner of this page.
|
|
80
|
+
|
|
81
|
+
Clone the forked repository to your local machine:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
git clone https://github.com/your-username/analyze-codebase.git
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Create a new branch for your feature or bug fix:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
git checkout -b feature/your-feature-name
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
or
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
git checkout -b bugfix/your-bug-fix
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Make your modifications and additions to the codebase.
|
|
101
|
+
|
|
102
|
+
Test your changes thoroughly to ensure they do not introduce any issues.
|
|
103
|
+
|
|
104
|
+
Commit your changes with a descriptive commit message:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
git commit -m "Add your commit message here"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Push your changes to your forked repository:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
git push origin feature/your-feature-name
|
|
114
|
+
```
|
|
115
|
+
or
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
git push origin bugfix/your-bug-fix
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Open a pull request (PR) from your forked repository to the original repository. Provide a clear and concise description of your changes in the PR.
|
|
122
|
+
|
|
123
|
+
Wait for the maintainers to review your PR. They may provide feedback or request additional changes.
|
|
124
|
+
|
|
125
|
+
Once your PR is approved, it will be merged into the main branch, and your contributions will become a part of the Codebase Analyzer project.
|
|
126
|
+
|
|
127
|
+
Please ensure that you adhere to our code of conduct and follow the guidelines provided in the CONTRIBUTING.md file for a smooth and collaborative contribution process.
|
|
128
|
+
|
|
129
|
+
Thank you for your interest in improving Codebase Analyzer! Your contributions are highly appreciated.
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
This project is licensed under the MIT License.
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2018",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"resolveJsonModule": true,
|
|
9
|
+
"sourceMap": false,
|
|
10
|
+
"declaration": true
|
|
11
|
+
},
|
|
12
|
+
"include": [
|
|
13
|
+
"src",
|
|
14
|
+
"extensions"
|
|
15
|
+
]
|
|
16
|
+
}
|