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.
@@ -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,4 @@
1
+ import { ICodeContentType } from '../../types';
2
+ export declare const analyzeFile: (filePath: string, output: ICodeContentType) => {
3
+ fileNameCase: import("../../utils").NamingCase;
4
+ };
@@ -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,2 @@
1
+ import { IAnalysisOptions } from '../types';
2
+ export declare const analyzeCodebase: (options: IAnalysisOptions) => Promise<void>;
@@ -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;
@@ -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
+ }
@@ -0,0 +1,5 @@
1
+ import { IAnalysisOptions } from "./types";
2
+ export interface IRunnerProps extends IAnalysisOptions {
3
+ directory: string;
4
+ }
5
+ export default function runner(props: IRunnerProps): void;
package/dist/runner.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const analyze_1 = require("./analyze");
4
+ function runner(props) {
5
+ (0, analyze_1.analyzeCodebase)(props);
6
+ }
7
+ exports.default = runner;
@@ -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,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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
+ ![Example Image](./example-output.png)
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
+ }