@aiready/core 0.1.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/.turbo/turbo-build.log +61 -0
- package/.turbo/turbo-test.log +13 -0
- package/LICENSE +21 -0
- package/dist/index.d.mts +85 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +126 -0
- package/dist/index.mjs +90 -0
- package/package.json +45 -0
- package/src/index.ts +4 -0
- package/src/types.ts +59 -0
- package/src/utils/ast-parser.ts +28 -0
- package/src/utils/file-scanner.ts +42 -0
- package/src/utils/metrics.ts +47 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @aiready/core@0.1.0 build /Users/pengcao/projects/aiready/packages/core
|
|
4
|
+
> tsup src/index.ts --format cjs,esm --dts
|
|
5
|
+
|
|
6
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
7
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
8
|
+
[34mCLI[39m tsup v8.5.1
|
|
9
|
+
[34mCLI[39m Target: es2020
|
|
10
|
+
[34mCJS[39m Build start
|
|
11
|
+
[34mESM[39m Build start
|
|
12
|
+
DTS Build start
|
|
13
|
+
|
|
14
|
+
[90m[[90m12:59:20 AM[90m][39m [43m[30m WARN [39m[49m [33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mThe condition "types" here will never be used as it comes after both "import" and "require"[0m [package.json]
|
|
15
|
+
|
|
16
|
+
package.json:12:6:
|
|
17
|
+
[37m 12 │ [32m"types"[37m: "./dist/index.d.ts"
|
|
18
|
+
╵ [32m~~~~~~~[0m
|
|
19
|
+
|
|
20
|
+
The "import" condition comes earlier and will be used for all "import" statements:
|
|
21
|
+
|
|
22
|
+
package.json:11:6:
|
|
23
|
+
[37m 11 │ [32m"import"[37m: "./dist/index.mjs",
|
|
24
|
+
╵ [32m~~~~~~~~[0m
|
|
25
|
+
|
|
26
|
+
The "require" condition comes earlier and will be used for all "require" calls:
|
|
27
|
+
|
|
28
|
+
package.json:10:6:
|
|
29
|
+
[37m 10 │ [32m"require"[37m: "./dist/index.js",
|
|
30
|
+
╵ [32m~~~~~~~~~[0m
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
[90m[[90m12:59:20 AM[90m][39m [43m[30m WARN [39m[49m [33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mThe condition "types" here will never be used as it comes after both "import" and "require"[0m [package.json]
|
|
36
|
+
|
|
37
|
+
package.json:12:6:
|
|
38
|
+
[37m 12 │ [32m"types"[37m: "./dist/index.d.ts"
|
|
39
|
+
╵ [32m~~~~~~~[0m
|
|
40
|
+
|
|
41
|
+
The "import" condition comes earlier and will be used for all "import" statements:
|
|
42
|
+
|
|
43
|
+
package.json:11:6:
|
|
44
|
+
[37m 11 │ [32m"import"[37m: "./dist/index.mjs",
|
|
45
|
+
╵ [32m~~~~~~~~[0m
|
|
46
|
+
|
|
47
|
+
The "require" condition comes earlier and will be used for all "require" calls:
|
|
48
|
+
|
|
49
|
+
package.json:10:6:
|
|
50
|
+
[37m 10 │ [32m"require"[37m: "./dist/index.js",
|
|
51
|
+
╵ [32m~~~~~~~~~[0m
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m2.02 KB[39m
|
|
56
|
+
[32mESM[39m ⚡️ Build success in 273ms
|
|
57
|
+
[32mCJS[39m [1mdist/index.js [22m[32m3.42 KB[39m
|
|
58
|
+
[32mCJS[39m ⚡️ Build success in 274ms
|
|
59
|
+
DTS ⚡️ Build success in 435ms
|
|
60
|
+
DTS dist/index.d.ts 2.48 KB
|
|
61
|
+
DTS dist/index.d.mts 2.48 KB
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @aiready/core@0.1.0 test /Users/pengcao/projects/aiready/packages/core
|
|
4
|
+
> vitest run
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
[1m[7m[36m RUN [39m[27m[22m [36mv2.1.9 [39m[90m/Users/pengcao/projects/aiready/packages/core[39m
|
|
8
|
+
|
|
9
|
+
[2minclude: [22m[33m**/*.{test,spec}.?(c|m)[jt]s?(x)[39m
|
|
10
|
+
[2mexclude: [22m[33m**/node_modules/**[2m, [22m**/dist/**[2m, [22m**/cypress/**[2m, [22m**/.{idea,git,cache,output,temp}/**[2m, [22m**/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build,eslint,prettier}.config.*[39m
|
|
11
|
+
[31m
|
|
12
|
+
No test files found, exiting with code 1[39m
|
|
13
|
+
[?25h[41m[30m ELIFECYCLE [39m[49m [31mTest failed. See above for more details.[39m
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AIReady Team
|
|
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.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
interface AnalysisResult {
|
|
2
|
+
fileName: string;
|
|
3
|
+
issues: Issue[];
|
|
4
|
+
metrics: Metrics;
|
|
5
|
+
}
|
|
6
|
+
interface Issue {
|
|
7
|
+
type: IssueType;
|
|
8
|
+
severity: 'critical' | 'major' | 'minor' | 'info';
|
|
9
|
+
message: string;
|
|
10
|
+
location: Location;
|
|
11
|
+
suggestion?: string;
|
|
12
|
+
}
|
|
13
|
+
type IssueType = 'duplicate-pattern' | 'context-fragmentation' | 'doc-drift' | 'naming-inconsistency' | 'dead-code' | 'circular-dependency' | 'missing-types';
|
|
14
|
+
interface Location {
|
|
15
|
+
file: string;
|
|
16
|
+
line: number;
|
|
17
|
+
column?: number;
|
|
18
|
+
endLine?: number;
|
|
19
|
+
endColumn?: number;
|
|
20
|
+
}
|
|
21
|
+
interface Metrics {
|
|
22
|
+
tokenCost?: number;
|
|
23
|
+
complexityScore?: number;
|
|
24
|
+
consistencyScore?: number;
|
|
25
|
+
docFreshnessScore?: number;
|
|
26
|
+
}
|
|
27
|
+
interface ScanOptions {
|
|
28
|
+
rootDir: string;
|
|
29
|
+
include?: string[];
|
|
30
|
+
exclude?: string[];
|
|
31
|
+
maxDepth?: number;
|
|
32
|
+
}
|
|
33
|
+
interface Report {
|
|
34
|
+
summary: {
|
|
35
|
+
totalFiles: number;
|
|
36
|
+
totalIssues: number;
|
|
37
|
+
criticalIssues: number;
|
|
38
|
+
majorIssues: number;
|
|
39
|
+
};
|
|
40
|
+
results: AnalysisResult[];
|
|
41
|
+
metrics: {
|
|
42
|
+
overallScore: number;
|
|
43
|
+
tokenCostTotal: number;
|
|
44
|
+
avgConsistency: number;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
declare function scanFiles(options: ScanOptions): Promise<string[]>;
|
|
49
|
+
declare function readFileContent(filePath: string): Promise<string>;
|
|
50
|
+
declare function getFileExtension(filePath: string): string;
|
|
51
|
+
declare function isSourceFile(filePath: string): boolean;
|
|
52
|
+
|
|
53
|
+
interface ASTNode {
|
|
54
|
+
type: string;
|
|
55
|
+
loc?: {
|
|
56
|
+
start: {
|
|
57
|
+
line: number;
|
|
58
|
+
column: number;
|
|
59
|
+
};
|
|
60
|
+
end: {
|
|
61
|
+
line: number;
|
|
62
|
+
column: number;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
declare function parseCode(code: string, language: string): ASTNode | null;
|
|
67
|
+
declare function extractFunctions(ast: ASTNode): ASTNode[];
|
|
68
|
+
declare function extractImports(ast: ASTNode): string[];
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Estimate token count for text (rough approximation)
|
|
72
|
+
* ~1 token ≈ 4 characters for code
|
|
73
|
+
*/
|
|
74
|
+
declare function estimateTokens(text: string): number;
|
|
75
|
+
/**
|
|
76
|
+
* Calculate Levenshtein distance between two strings
|
|
77
|
+
* Useful for similarity detection
|
|
78
|
+
*/
|
|
79
|
+
declare function levenshteinDistance(str1: string, str2: string): number;
|
|
80
|
+
/**
|
|
81
|
+
* Calculate similarity score (0-1) between two strings
|
|
82
|
+
*/
|
|
83
|
+
declare function similarityScore(str1: string, str2: string): number;
|
|
84
|
+
|
|
85
|
+
export { type ASTNode, type AnalysisResult, type Issue, type IssueType, type Location, type Metrics, type Report, type ScanOptions, estimateTokens, extractFunctions, extractImports, getFileExtension, isSourceFile, levenshteinDistance, parseCode, readFileContent, scanFiles, similarityScore };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
interface AnalysisResult {
|
|
2
|
+
fileName: string;
|
|
3
|
+
issues: Issue[];
|
|
4
|
+
metrics: Metrics;
|
|
5
|
+
}
|
|
6
|
+
interface Issue {
|
|
7
|
+
type: IssueType;
|
|
8
|
+
severity: 'critical' | 'major' | 'minor' | 'info';
|
|
9
|
+
message: string;
|
|
10
|
+
location: Location;
|
|
11
|
+
suggestion?: string;
|
|
12
|
+
}
|
|
13
|
+
type IssueType = 'duplicate-pattern' | 'context-fragmentation' | 'doc-drift' | 'naming-inconsistency' | 'dead-code' | 'circular-dependency' | 'missing-types';
|
|
14
|
+
interface Location {
|
|
15
|
+
file: string;
|
|
16
|
+
line: number;
|
|
17
|
+
column?: number;
|
|
18
|
+
endLine?: number;
|
|
19
|
+
endColumn?: number;
|
|
20
|
+
}
|
|
21
|
+
interface Metrics {
|
|
22
|
+
tokenCost?: number;
|
|
23
|
+
complexityScore?: number;
|
|
24
|
+
consistencyScore?: number;
|
|
25
|
+
docFreshnessScore?: number;
|
|
26
|
+
}
|
|
27
|
+
interface ScanOptions {
|
|
28
|
+
rootDir: string;
|
|
29
|
+
include?: string[];
|
|
30
|
+
exclude?: string[];
|
|
31
|
+
maxDepth?: number;
|
|
32
|
+
}
|
|
33
|
+
interface Report {
|
|
34
|
+
summary: {
|
|
35
|
+
totalFiles: number;
|
|
36
|
+
totalIssues: number;
|
|
37
|
+
criticalIssues: number;
|
|
38
|
+
majorIssues: number;
|
|
39
|
+
};
|
|
40
|
+
results: AnalysisResult[];
|
|
41
|
+
metrics: {
|
|
42
|
+
overallScore: number;
|
|
43
|
+
tokenCostTotal: number;
|
|
44
|
+
avgConsistency: number;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
declare function scanFiles(options: ScanOptions): Promise<string[]>;
|
|
49
|
+
declare function readFileContent(filePath: string): Promise<string>;
|
|
50
|
+
declare function getFileExtension(filePath: string): string;
|
|
51
|
+
declare function isSourceFile(filePath: string): boolean;
|
|
52
|
+
|
|
53
|
+
interface ASTNode {
|
|
54
|
+
type: string;
|
|
55
|
+
loc?: {
|
|
56
|
+
start: {
|
|
57
|
+
line: number;
|
|
58
|
+
column: number;
|
|
59
|
+
};
|
|
60
|
+
end: {
|
|
61
|
+
line: number;
|
|
62
|
+
column: number;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
declare function parseCode(code: string, language: string): ASTNode | null;
|
|
67
|
+
declare function extractFunctions(ast: ASTNode): ASTNode[];
|
|
68
|
+
declare function extractImports(ast: ASTNode): string[];
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Estimate token count for text (rough approximation)
|
|
72
|
+
* ~1 token ≈ 4 characters for code
|
|
73
|
+
*/
|
|
74
|
+
declare function estimateTokens(text: string): number;
|
|
75
|
+
/**
|
|
76
|
+
* Calculate Levenshtein distance between two strings
|
|
77
|
+
* Useful for similarity detection
|
|
78
|
+
*/
|
|
79
|
+
declare function levenshteinDistance(str1: string, str2: string): number;
|
|
80
|
+
/**
|
|
81
|
+
* Calculate similarity score (0-1) between two strings
|
|
82
|
+
*/
|
|
83
|
+
declare function similarityScore(str1: string, str2: string): number;
|
|
84
|
+
|
|
85
|
+
export { type ASTNode, type AnalysisResult, type Issue, type IssueType, type Location, type Metrics, type Report, type ScanOptions, estimateTokens, extractFunctions, extractImports, getFileExtension, isSourceFile, levenshteinDistance, parseCode, readFileContent, scanFiles, similarityScore };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
estimateTokens: () => estimateTokens,
|
|
24
|
+
extractFunctions: () => extractFunctions,
|
|
25
|
+
extractImports: () => extractImports,
|
|
26
|
+
getFileExtension: () => getFileExtension,
|
|
27
|
+
isSourceFile: () => isSourceFile,
|
|
28
|
+
levenshteinDistance: () => levenshteinDistance,
|
|
29
|
+
parseCode: () => parseCode,
|
|
30
|
+
readFileContent: () => readFileContent,
|
|
31
|
+
scanFiles: () => scanFiles,
|
|
32
|
+
similarityScore: () => similarityScore
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
|
|
36
|
+
// src/utils/file-scanner.ts
|
|
37
|
+
var import_glob = require("glob");
|
|
38
|
+
var import_promises = require("fs/promises");
|
|
39
|
+
var DEFAULT_EXCLUDE = [
|
|
40
|
+
"**/node_modules/**",
|
|
41
|
+
"**/dist/**",
|
|
42
|
+
"**/build/**",
|
|
43
|
+
"**/.git/**",
|
|
44
|
+
"**/coverage/**",
|
|
45
|
+
"**/*.min.js",
|
|
46
|
+
"**/*.bundle.js"
|
|
47
|
+
];
|
|
48
|
+
async function scanFiles(options) {
|
|
49
|
+
const {
|
|
50
|
+
rootDir,
|
|
51
|
+
include = ["**/*.{ts,tsx,js,jsx,py,java}"],
|
|
52
|
+
exclude = DEFAULT_EXCLUDE
|
|
53
|
+
} = options;
|
|
54
|
+
const files = await (0, import_glob.glob)(include, {
|
|
55
|
+
cwd: rootDir,
|
|
56
|
+
ignore: exclude,
|
|
57
|
+
absolute: true
|
|
58
|
+
});
|
|
59
|
+
return files;
|
|
60
|
+
}
|
|
61
|
+
async function readFileContent(filePath) {
|
|
62
|
+
return (0, import_promises.readFile)(filePath, "utf-8");
|
|
63
|
+
}
|
|
64
|
+
function getFileExtension(filePath) {
|
|
65
|
+
return filePath.split(".").pop() || "";
|
|
66
|
+
}
|
|
67
|
+
function isSourceFile(filePath) {
|
|
68
|
+
const ext = getFileExtension(filePath);
|
|
69
|
+
return ["ts", "tsx", "js", "jsx", "py", "java", "go", "rs"].includes(ext);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/utils/ast-parser.ts
|
|
73
|
+
function parseCode(code, language) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
function extractFunctions(ast) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
function extractImports(ast) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/utils/metrics.ts
|
|
84
|
+
function estimateTokens(text) {
|
|
85
|
+
return Math.ceil(text.length / 4);
|
|
86
|
+
}
|
|
87
|
+
function levenshteinDistance(str1, str2) {
|
|
88
|
+
const len1 = str1.length;
|
|
89
|
+
const len2 = str2.length;
|
|
90
|
+
const matrix = [];
|
|
91
|
+
for (let i = 0; i <= len1; i++) {
|
|
92
|
+
matrix[i] = [i];
|
|
93
|
+
}
|
|
94
|
+
for (let j = 0; j <= len2; j++) {
|
|
95
|
+
matrix[0][j] = j;
|
|
96
|
+
}
|
|
97
|
+
for (let i = 1; i <= len1; i++) {
|
|
98
|
+
for (let j = 1; j <= len2; j++) {
|
|
99
|
+
const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
|
100
|
+
matrix[i][j] = Math.min(
|
|
101
|
+
matrix[i - 1][j] + 1,
|
|
102
|
+
matrix[i][j - 1] + 1,
|
|
103
|
+
matrix[i - 1][j - 1] + cost
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return matrix[len1][len2];
|
|
108
|
+
}
|
|
109
|
+
function similarityScore(str1, str2) {
|
|
110
|
+
const distance = levenshteinDistance(str1, str2);
|
|
111
|
+
const maxLength = Math.max(str1.length, str2.length);
|
|
112
|
+
return maxLength === 0 ? 1 : 1 - distance / maxLength;
|
|
113
|
+
}
|
|
114
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
115
|
+
0 && (module.exports = {
|
|
116
|
+
estimateTokens,
|
|
117
|
+
extractFunctions,
|
|
118
|
+
extractImports,
|
|
119
|
+
getFileExtension,
|
|
120
|
+
isSourceFile,
|
|
121
|
+
levenshteinDistance,
|
|
122
|
+
parseCode,
|
|
123
|
+
readFileContent,
|
|
124
|
+
scanFiles,
|
|
125
|
+
similarityScore
|
|
126
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// src/utils/file-scanner.ts
|
|
2
|
+
import { glob } from "glob";
|
|
3
|
+
import { readFile } from "fs/promises";
|
|
4
|
+
var DEFAULT_EXCLUDE = [
|
|
5
|
+
"**/node_modules/**",
|
|
6
|
+
"**/dist/**",
|
|
7
|
+
"**/build/**",
|
|
8
|
+
"**/.git/**",
|
|
9
|
+
"**/coverage/**",
|
|
10
|
+
"**/*.min.js",
|
|
11
|
+
"**/*.bundle.js"
|
|
12
|
+
];
|
|
13
|
+
async function scanFiles(options) {
|
|
14
|
+
const {
|
|
15
|
+
rootDir,
|
|
16
|
+
include = ["**/*.{ts,tsx,js,jsx,py,java}"],
|
|
17
|
+
exclude = DEFAULT_EXCLUDE
|
|
18
|
+
} = options;
|
|
19
|
+
const files = await glob(include, {
|
|
20
|
+
cwd: rootDir,
|
|
21
|
+
ignore: exclude,
|
|
22
|
+
absolute: true
|
|
23
|
+
});
|
|
24
|
+
return files;
|
|
25
|
+
}
|
|
26
|
+
async function readFileContent(filePath) {
|
|
27
|
+
return readFile(filePath, "utf-8");
|
|
28
|
+
}
|
|
29
|
+
function getFileExtension(filePath) {
|
|
30
|
+
return filePath.split(".").pop() || "";
|
|
31
|
+
}
|
|
32
|
+
function isSourceFile(filePath) {
|
|
33
|
+
const ext = getFileExtension(filePath);
|
|
34
|
+
return ["ts", "tsx", "js", "jsx", "py", "java", "go", "rs"].includes(ext);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/utils/ast-parser.ts
|
|
38
|
+
function parseCode(code, language) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function extractFunctions(ast) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
function extractImports(ast) {
|
|
45
|
+
return [];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/utils/metrics.ts
|
|
49
|
+
function estimateTokens(text) {
|
|
50
|
+
return Math.ceil(text.length / 4);
|
|
51
|
+
}
|
|
52
|
+
function levenshteinDistance(str1, str2) {
|
|
53
|
+
const len1 = str1.length;
|
|
54
|
+
const len2 = str2.length;
|
|
55
|
+
const matrix = [];
|
|
56
|
+
for (let i = 0; i <= len1; i++) {
|
|
57
|
+
matrix[i] = [i];
|
|
58
|
+
}
|
|
59
|
+
for (let j = 0; j <= len2; j++) {
|
|
60
|
+
matrix[0][j] = j;
|
|
61
|
+
}
|
|
62
|
+
for (let i = 1; i <= len1; i++) {
|
|
63
|
+
for (let j = 1; j <= len2; j++) {
|
|
64
|
+
const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
|
65
|
+
matrix[i][j] = Math.min(
|
|
66
|
+
matrix[i - 1][j] + 1,
|
|
67
|
+
matrix[i][j - 1] + 1,
|
|
68
|
+
matrix[i - 1][j - 1] + cost
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return matrix[len1][len2];
|
|
73
|
+
}
|
|
74
|
+
function similarityScore(str1, str2) {
|
|
75
|
+
const distance = levenshteinDistance(str1, str2);
|
|
76
|
+
const maxLength = Math.max(str1.length, str2.length);
|
|
77
|
+
return maxLength === 0 ? 1 : 1 - distance / maxLength;
|
|
78
|
+
}
|
|
79
|
+
export {
|
|
80
|
+
estimateTokens,
|
|
81
|
+
extractFunctions,
|
|
82
|
+
extractImports,
|
|
83
|
+
getFileExtension,
|
|
84
|
+
isSourceFile,
|
|
85
|
+
levenshteinDistance,
|
|
86
|
+
parseCode,
|
|
87
|
+
readFileContent,
|
|
88
|
+
scanFiles,
|
|
89
|
+
similarityScore
|
|
90
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aiready/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared utilities for AIReady analysis tools",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"aiready",
|
|
17
|
+
"code-analysis",
|
|
18
|
+
"utilities"
|
|
19
|
+
],
|
|
20
|
+
"author": "AIReady Team",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/caopengau/aiready-core.git"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/caopengau/aiready-core",
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/caopengau/aiready-core/issues"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"tsup": "^8.3.5",
|
|
32
|
+
"eslint": "^9.17.0"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"glob": "^11.0.0",
|
|
36
|
+
"chalk": "^5.4.1"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
40
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"lint": "eslint src",
|
|
43
|
+
"clean": "rm -rf dist"
|
|
44
|
+
}
|
|
45
|
+
}
|
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export interface AnalysisResult {
|
|
2
|
+
fileName: string;
|
|
3
|
+
issues: Issue[];
|
|
4
|
+
metrics: Metrics;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface Issue {
|
|
8
|
+
type: IssueType;
|
|
9
|
+
severity: 'critical' | 'major' | 'minor' | 'info';
|
|
10
|
+
message: string;
|
|
11
|
+
location: Location;
|
|
12
|
+
suggestion?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type IssueType =
|
|
16
|
+
| 'duplicate-pattern'
|
|
17
|
+
| 'context-fragmentation'
|
|
18
|
+
| 'doc-drift'
|
|
19
|
+
| 'naming-inconsistency'
|
|
20
|
+
| 'dead-code'
|
|
21
|
+
| 'circular-dependency'
|
|
22
|
+
| 'missing-types';
|
|
23
|
+
|
|
24
|
+
export interface Location {
|
|
25
|
+
file: string;
|
|
26
|
+
line: number;
|
|
27
|
+
column?: number;
|
|
28
|
+
endLine?: number;
|
|
29
|
+
endColumn?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface Metrics {
|
|
33
|
+
tokenCost?: number;
|
|
34
|
+
complexityScore?: number;
|
|
35
|
+
consistencyScore?: number;
|
|
36
|
+
docFreshnessScore?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface ScanOptions {
|
|
40
|
+
rootDir: string;
|
|
41
|
+
include?: string[];
|
|
42
|
+
exclude?: string[];
|
|
43
|
+
maxDepth?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface Report {
|
|
47
|
+
summary: {
|
|
48
|
+
totalFiles: number;
|
|
49
|
+
totalIssues: number;
|
|
50
|
+
criticalIssues: number;
|
|
51
|
+
majorIssues: number;
|
|
52
|
+
};
|
|
53
|
+
results: AnalysisResult[];
|
|
54
|
+
metrics: {
|
|
55
|
+
overallScore: number;
|
|
56
|
+
tokenCostTotal: number;
|
|
57
|
+
avgConsistency: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Placeholder for AST parsing utilities
|
|
2
|
+
// Will be implemented with specific parsers (TypeScript, Babel, etc.)
|
|
3
|
+
|
|
4
|
+
export interface ASTNode {
|
|
5
|
+
type: string;
|
|
6
|
+
loc?: {
|
|
7
|
+
start: { line: number; column: number };
|
|
8
|
+
end: { line: number; column: number };
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function parseCode(code: string, language: string): ASTNode | null {
|
|
13
|
+
// TODO: Implement language-specific parsing
|
|
14
|
+
// TypeScript: @typescript-eslint/parser
|
|
15
|
+
// JavaScript: @babel/parser
|
|
16
|
+
// Python: tree-sitter-python
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function extractFunctions(ast: ASTNode): ASTNode[] {
|
|
21
|
+
// TODO: Extract function declarations
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function extractImports(ast: ASTNode): string[] {
|
|
26
|
+
// TODO: Extract import statements
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { glob } from 'glob';
|
|
2
|
+
import { readFile } from 'fs/promises';
|
|
3
|
+
import { ScanOptions } from '../types';
|
|
4
|
+
|
|
5
|
+
const DEFAULT_EXCLUDE = [
|
|
6
|
+
'**/node_modules/**',
|
|
7
|
+
'**/dist/**',
|
|
8
|
+
'**/build/**',
|
|
9
|
+
'**/.git/**',
|
|
10
|
+
'**/coverage/**',
|
|
11
|
+
'**/*.min.js',
|
|
12
|
+
'**/*.bundle.js',
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
export async function scanFiles(options: ScanOptions): Promise<string[]> {
|
|
16
|
+
const {
|
|
17
|
+
rootDir,
|
|
18
|
+
include = ['**/*.{ts,tsx,js,jsx,py,java}'],
|
|
19
|
+
exclude = DEFAULT_EXCLUDE,
|
|
20
|
+
} = options;
|
|
21
|
+
|
|
22
|
+
const files = await glob(include, {
|
|
23
|
+
cwd: rootDir,
|
|
24
|
+
ignore: exclude,
|
|
25
|
+
absolute: true,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return files;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function readFileContent(filePath: string): Promise<string> {
|
|
32
|
+
return readFile(filePath, 'utf-8');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getFileExtension(filePath: string): string {
|
|
36
|
+
return filePath.split('.').pop() || '';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isSourceFile(filePath: string): boolean {
|
|
40
|
+
const ext = getFileExtension(filePath);
|
|
41
|
+
return ['ts', 'tsx', 'js', 'jsx', 'py', 'java', 'go', 'rs'].includes(ext);
|
|
42
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Estimate token count for text (rough approximation)
|
|
3
|
+
* ~1 token ≈ 4 characters for code
|
|
4
|
+
*/
|
|
5
|
+
export function estimateTokens(text: string): number {
|
|
6
|
+
return Math.ceil(text.length / 4);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Calculate Levenshtein distance between two strings
|
|
11
|
+
* Useful for similarity detection
|
|
12
|
+
*/
|
|
13
|
+
export function levenshteinDistance(str1: string, str2: string): number {
|
|
14
|
+
const len1 = str1.length;
|
|
15
|
+
const len2 = str2.length;
|
|
16
|
+
const matrix: number[][] = [];
|
|
17
|
+
|
|
18
|
+
for (let i = 0; i <= len1; i++) {
|
|
19
|
+
matrix[i] = [i];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
for (let j = 0; j <= len2; j++) {
|
|
23
|
+
matrix[0][j] = j;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (let i = 1; i <= len1; i++) {
|
|
27
|
+
for (let j = 1; j <= len2; j++) {
|
|
28
|
+
const cost = str1[i - 1] === str2[j - 1] ? 0 : 1;
|
|
29
|
+
matrix[i][j] = Math.min(
|
|
30
|
+
matrix[i - 1][j] + 1,
|
|
31
|
+
matrix[i][j - 1] + 1,
|
|
32
|
+
matrix[i - 1][j - 1] + cost
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return matrix[len1][len2];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Calculate similarity score (0-1) between two strings
|
|
42
|
+
*/
|
|
43
|
+
export function similarityScore(str1: string, str2: string): number {
|
|
44
|
+
const distance = levenshteinDistance(str1, str2);
|
|
45
|
+
const maxLength = Math.max(str1.length, str2.length);
|
|
46
|
+
return maxLength === 0 ? 1 : 1 - distance / maxLength;
|
|
47
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"lib": ["ES2020"],
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"sourceMap": true,
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"rootDir": "./src",
|
|
12
|
+
"strict": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"resolveJsonModule": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist"]
|
|
20
|
+
}
|