@aiready/core 0.5.6 → 0.7.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/dist/index.d.mts CHANGED
@@ -54,6 +54,9 @@ interface AIReadyConfig {
54
54
  focus?: 'fragmentation' | 'cohesion' | 'depth' | 'all';
55
55
  includeNodeModules?: boolean;
56
56
  maxResults?: number;
57
+ domainKeywords?: string[];
58
+ domainPatterns?: string[];
59
+ pathDomainMap?: Record<string, string>;
57
60
  };
58
61
  };
59
62
  output?: {
@@ -82,6 +85,39 @@ declare function readFileContent(filePath: string): Promise<string>;
82
85
  declare function getFileExtension(filePath: string): string;
83
86
  declare function isSourceFile(filePath: string): boolean;
84
87
 
88
+ interface ExportWithImports {
89
+ name: string;
90
+ type: 'function' | 'class' | 'const' | 'type' | 'interface' | 'default';
91
+ imports: string[];
92
+ dependencies: string[];
93
+ typeReferences: string[];
94
+ loc?: {
95
+ start: {
96
+ line: number;
97
+ column: number;
98
+ };
99
+ end: {
100
+ line: number;
101
+ column: number;
102
+ };
103
+ };
104
+ }
105
+ interface FileImport {
106
+ source: string;
107
+ specifiers: string[];
108
+ isTypeOnly: boolean;
109
+ }
110
+ /**
111
+ * Parse TypeScript/JavaScript file and extract exports with their import dependencies
112
+ */
113
+ declare function parseFileExports(code: string, filePath: string): {
114
+ exports: ExportWithImports[];
115
+ imports: FileImport[];
116
+ };
117
+ /**
118
+ * Calculate import-based similarity between two exports (Jaccard index)
119
+ */
120
+ declare function calculateImportSimilarity(export1: ExportWithImports, export2: ExportWithImports): number;
85
121
  interface ASTNode {
86
122
  type: string;
87
123
  loc?: {
@@ -145,4 +181,4 @@ declare function handleCLIError(error: unknown, commandName: string): never;
145
181
  */
146
182
  declare function getElapsedTime(startTime: number): string;
147
183
 
148
- export { type AIReadyConfig, type ASTNode, type AnalysisResult, type CLIOptions, DEFAULT_EXCLUDE, type Issue, type IssueType, type Location, type Metrics, type Report, type ScanOptions, estimateTokens, extractFunctions, extractImports, getElapsedTime, getFileExtension, handleCLIError, handleJSONOutput, isSourceFile, loadConfig, loadMergedConfig, mergeConfigWithDefaults, parseCode, readFileContent, resolveOutputPath, scanFiles };
184
+ export { type AIReadyConfig, type ASTNode, type AnalysisResult, type CLIOptions, DEFAULT_EXCLUDE, type ExportWithImports, type FileImport, type Issue, type IssueType, type Location, type Metrics, type Report, type ScanOptions, calculateImportSimilarity, estimateTokens, extractFunctions, extractImports, getElapsedTime, getFileExtension, handleCLIError, handleJSONOutput, isSourceFile, loadConfig, loadMergedConfig, mergeConfigWithDefaults, parseCode, parseFileExports, readFileContent, resolveOutputPath, scanFiles };
package/dist/index.d.ts CHANGED
@@ -54,6 +54,9 @@ interface AIReadyConfig {
54
54
  focus?: 'fragmentation' | 'cohesion' | 'depth' | 'all';
55
55
  includeNodeModules?: boolean;
56
56
  maxResults?: number;
57
+ domainKeywords?: string[];
58
+ domainPatterns?: string[];
59
+ pathDomainMap?: Record<string, string>;
57
60
  };
58
61
  };
59
62
  output?: {
@@ -82,6 +85,39 @@ declare function readFileContent(filePath: string): Promise<string>;
82
85
  declare function getFileExtension(filePath: string): string;
83
86
  declare function isSourceFile(filePath: string): boolean;
84
87
 
88
+ interface ExportWithImports {
89
+ name: string;
90
+ type: 'function' | 'class' | 'const' | 'type' | 'interface' | 'default';
91
+ imports: string[];
92
+ dependencies: string[];
93
+ typeReferences: string[];
94
+ loc?: {
95
+ start: {
96
+ line: number;
97
+ column: number;
98
+ };
99
+ end: {
100
+ line: number;
101
+ column: number;
102
+ };
103
+ };
104
+ }
105
+ interface FileImport {
106
+ source: string;
107
+ specifiers: string[];
108
+ isTypeOnly: boolean;
109
+ }
110
+ /**
111
+ * Parse TypeScript/JavaScript file and extract exports with their import dependencies
112
+ */
113
+ declare function parseFileExports(code: string, filePath: string): {
114
+ exports: ExportWithImports[];
115
+ imports: FileImport[];
116
+ };
117
+ /**
118
+ * Calculate import-based similarity between two exports (Jaccard index)
119
+ */
120
+ declare function calculateImportSimilarity(export1: ExportWithImports, export2: ExportWithImports): number;
85
121
  interface ASTNode {
86
122
  type: string;
87
123
  loc?: {
@@ -145,4 +181,4 @@ declare function handleCLIError(error: unknown, commandName: string): never;
145
181
  */
146
182
  declare function getElapsedTime(startTime: number): string;
147
183
 
148
- export { type AIReadyConfig, type ASTNode, type AnalysisResult, type CLIOptions, DEFAULT_EXCLUDE, type Issue, type IssueType, type Location, type Metrics, type Report, type ScanOptions, estimateTokens, extractFunctions, extractImports, getElapsedTime, getFileExtension, handleCLIError, handleJSONOutput, isSourceFile, loadConfig, loadMergedConfig, mergeConfigWithDefaults, parseCode, readFileContent, resolveOutputPath, scanFiles };
184
+ export { type AIReadyConfig, type ASTNode, type AnalysisResult, type CLIOptions, DEFAULT_EXCLUDE, type ExportWithImports, type FileImport, type Issue, type IssueType, type Location, type Metrics, type Report, type ScanOptions, calculateImportSimilarity, estimateTokens, extractFunctions, extractImports, getElapsedTime, getFileExtension, handleCLIError, handleJSONOutput, isSourceFile, loadConfig, loadMergedConfig, mergeConfigWithDefaults, parseCode, parseFileExports, readFileContent, resolveOutputPath, scanFiles };
package/dist/index.js CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  DEFAULT_EXCLUDE: () => DEFAULT_EXCLUDE,
24
+ calculateImportSimilarity: () => calculateImportSimilarity,
24
25
  estimateTokens: () => estimateTokens,
25
26
  extractFunctions: () => extractFunctions,
26
27
  extractImports: () => extractImports,
@@ -33,6 +34,7 @@ __export(index_exports, {
33
34
  loadMergedConfig: () => loadMergedConfig,
34
35
  mergeConfigWithDefaults: () => mergeConfigWithDefaults,
35
36
  parseCode: () => parseCode,
37
+ parseFileExports: () => parseFileExports,
36
38
  readFileContent: () => readFileContent,
37
39
  resolveOutputPath: () => resolveOutputPath,
38
40
  scanFiles: () => scanFiles
@@ -108,6 +110,169 @@ function isSourceFile(filePath) {
108
110
  }
109
111
 
110
112
  // src/utils/ast-parser.ts
113
+ var import_typescript_estree = require("@typescript-eslint/typescript-estree");
114
+ function parseFileExports(code, filePath) {
115
+ try {
116
+ const ast = (0, import_typescript_estree.parse)(code, {
117
+ loc: true,
118
+ range: true,
119
+ jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
120
+ filePath
121
+ });
122
+ const imports = extractFileImports(ast);
123
+ const exports2 = extractExportsWithDependencies(ast, imports);
124
+ return { exports: exports2, imports };
125
+ } catch (error) {
126
+ return { exports: [], imports: [] };
127
+ }
128
+ }
129
+ function extractFileImports(ast) {
130
+ const imports = [];
131
+ for (const node of ast.body) {
132
+ if (node.type === "ImportDeclaration") {
133
+ const source = node.source.value;
134
+ const specifiers = [];
135
+ const isTypeOnly = node.importKind === "type";
136
+ for (const spec of node.specifiers) {
137
+ if (spec.type === "ImportSpecifier") {
138
+ const imported = spec.imported;
139
+ const importName = imported.type === "Identifier" ? imported.name : imported.value;
140
+ specifiers.push(importName);
141
+ } else if (spec.type === "ImportDefaultSpecifier") {
142
+ specifiers.push("default");
143
+ } else if (spec.type === "ImportNamespaceSpecifier") {
144
+ specifiers.push("*");
145
+ }
146
+ }
147
+ imports.push({ source, specifiers, isTypeOnly });
148
+ }
149
+ }
150
+ return imports;
151
+ }
152
+ function extractExportsWithDependencies(ast, fileImports) {
153
+ const exports2 = [];
154
+ const importedNames = new Set(fileImports.flatMap((imp) => imp.specifiers));
155
+ for (const node of ast.body) {
156
+ if (node.type === "ExportNamedDeclaration") {
157
+ if (node.declaration) {
158
+ const exportNodes = extractFromDeclaration(node.declaration);
159
+ for (const exp of exportNodes) {
160
+ const usedImports = findUsedImports(node.declaration, importedNames);
161
+ const typeReferences = extractTypeReferences(node.declaration);
162
+ exports2.push({
163
+ ...exp,
164
+ imports: usedImports,
165
+ dependencies: [],
166
+ typeReferences,
167
+ loc: node.loc
168
+ });
169
+ }
170
+ }
171
+ } else if (node.type === "ExportDefaultDeclaration") {
172
+ const usedImports = findUsedImports(node.declaration, importedNames);
173
+ const typeReferences = extractTypeReferences(node.declaration);
174
+ exports2.push({
175
+ name: "default",
176
+ type: "default",
177
+ imports: usedImports,
178
+ dependencies: [],
179
+ typeReferences,
180
+ loc: node.loc
181
+ });
182
+ }
183
+ }
184
+ return exports2;
185
+ }
186
+ function extractFromDeclaration(declaration) {
187
+ const results = [];
188
+ if (declaration.type === "FunctionDeclaration" && "id" in declaration && declaration.id) {
189
+ results.push({ name: declaration.id.name, type: "function" });
190
+ } else if (declaration.type === "ClassDeclaration" && "id" in declaration && declaration.id) {
191
+ results.push({ name: declaration.id.name, type: "class" });
192
+ } else if (declaration.type === "VariableDeclaration") {
193
+ for (const declarator of declaration.declarations) {
194
+ if (declarator.id.type === "Identifier") {
195
+ results.push({ name: declarator.id.name, type: "const" });
196
+ }
197
+ }
198
+ } else if (declaration.type === "TSTypeAliasDeclaration") {
199
+ results.push({ name: declaration.id.name, type: "type" });
200
+ } else if (declaration.type === "TSInterfaceDeclaration") {
201
+ results.push({ name: declaration.id.name, type: "interface" });
202
+ }
203
+ return results;
204
+ }
205
+ function findUsedImports(node, importedNames) {
206
+ const usedImports = /* @__PURE__ */ new Set();
207
+ function visit(n) {
208
+ if (n.type === "Identifier" && importedNames.has(n.name)) {
209
+ usedImports.add(n.name);
210
+ }
211
+ for (const key in n) {
212
+ const value = n[key];
213
+ if (value && typeof value === "object") {
214
+ if (Array.isArray(value)) {
215
+ value.forEach((child) => {
216
+ if (child && typeof child === "object" && "type" in child) {
217
+ visit(child);
218
+ }
219
+ });
220
+ } else if ("type" in value) {
221
+ visit(value);
222
+ }
223
+ }
224
+ }
225
+ }
226
+ visit(node);
227
+ return Array.from(usedImports);
228
+ }
229
+ function calculateImportSimilarity(export1, export2) {
230
+ if (export1.imports.length === 0 && export2.imports.length === 0) {
231
+ return 1;
232
+ }
233
+ const set1 = new Set(export1.imports);
234
+ const set2 = new Set(export2.imports);
235
+ const intersection = new Set([...set1].filter((x) => set2.has(x)));
236
+ const union = /* @__PURE__ */ new Set([...set1, ...set2]);
237
+ return intersection.size / union.size;
238
+ }
239
+ function extractTypeReferences(node) {
240
+ const types = /* @__PURE__ */ new Set();
241
+ function visit(n) {
242
+ if (!n || typeof n !== "object") return;
243
+ if (n.type === "TSTypeReference" && n.typeName) {
244
+ if (n.typeName.type === "Identifier") {
245
+ types.add(n.typeName.name);
246
+ } else if (n.typeName.type === "TSQualifiedName") {
247
+ let current = n.typeName;
248
+ while (current.type === "TSQualifiedName") {
249
+ if (current.right?.type === "Identifier") {
250
+ types.add(current.right.name);
251
+ }
252
+ current = current.left;
253
+ }
254
+ if (current.type === "Identifier") {
255
+ types.add(current.name);
256
+ }
257
+ }
258
+ }
259
+ if (n.type === "TSInterfaceHeritage" && n.expression) {
260
+ if (n.expression.type === "Identifier") {
261
+ types.add(n.expression.name);
262
+ }
263
+ }
264
+ for (const key of Object.keys(n)) {
265
+ const value = n[key];
266
+ if (Array.isArray(value)) {
267
+ value.forEach(visit);
268
+ } else if (value && typeof value === "object") {
269
+ visit(value);
270
+ }
271
+ }
272
+ }
273
+ visit(node);
274
+ return Array.from(types);
275
+ }
111
276
  function parseCode(code, language) {
112
277
  return null;
113
278
  }
@@ -238,6 +403,7 @@ function getElapsedTime(startTime) {
238
403
  // Annotate the CommonJS export names for ESM import in node:
239
404
  0 && (module.exports = {
240
405
  DEFAULT_EXCLUDE,
406
+ calculateImportSimilarity,
241
407
  estimateTokens,
242
408
  extractFunctions,
243
409
  extractImports,
@@ -250,6 +416,7 @@ function getElapsedTime(startTime) {
250
416
  loadMergedConfig,
251
417
  mergeConfigWithDefaults,
252
418
  parseCode,
419
+ parseFileExports,
253
420
  readFileContent,
254
421
  resolveOutputPath,
255
422
  scanFiles
package/dist/index.mjs CHANGED
@@ -74,6 +74,169 @@ function isSourceFile(filePath) {
74
74
  }
75
75
 
76
76
  // src/utils/ast-parser.ts
77
+ import { parse } from "@typescript-eslint/typescript-estree";
78
+ function parseFileExports(code, filePath) {
79
+ try {
80
+ const ast = parse(code, {
81
+ loc: true,
82
+ range: true,
83
+ jsx: filePath.endsWith(".tsx") || filePath.endsWith(".jsx"),
84
+ filePath
85
+ });
86
+ const imports = extractFileImports(ast);
87
+ const exports = extractExportsWithDependencies(ast, imports);
88
+ return { exports, imports };
89
+ } catch (error) {
90
+ return { exports: [], imports: [] };
91
+ }
92
+ }
93
+ function extractFileImports(ast) {
94
+ const imports = [];
95
+ for (const node of ast.body) {
96
+ if (node.type === "ImportDeclaration") {
97
+ const source = node.source.value;
98
+ const specifiers = [];
99
+ const isTypeOnly = node.importKind === "type";
100
+ for (const spec of node.specifiers) {
101
+ if (spec.type === "ImportSpecifier") {
102
+ const imported = spec.imported;
103
+ const importName = imported.type === "Identifier" ? imported.name : imported.value;
104
+ specifiers.push(importName);
105
+ } else if (spec.type === "ImportDefaultSpecifier") {
106
+ specifiers.push("default");
107
+ } else if (spec.type === "ImportNamespaceSpecifier") {
108
+ specifiers.push("*");
109
+ }
110
+ }
111
+ imports.push({ source, specifiers, isTypeOnly });
112
+ }
113
+ }
114
+ return imports;
115
+ }
116
+ function extractExportsWithDependencies(ast, fileImports) {
117
+ const exports = [];
118
+ const importedNames = new Set(fileImports.flatMap((imp) => imp.specifiers));
119
+ for (const node of ast.body) {
120
+ if (node.type === "ExportNamedDeclaration") {
121
+ if (node.declaration) {
122
+ const exportNodes = extractFromDeclaration(node.declaration);
123
+ for (const exp of exportNodes) {
124
+ const usedImports = findUsedImports(node.declaration, importedNames);
125
+ const typeReferences = extractTypeReferences(node.declaration);
126
+ exports.push({
127
+ ...exp,
128
+ imports: usedImports,
129
+ dependencies: [],
130
+ typeReferences,
131
+ loc: node.loc
132
+ });
133
+ }
134
+ }
135
+ } else if (node.type === "ExportDefaultDeclaration") {
136
+ const usedImports = findUsedImports(node.declaration, importedNames);
137
+ const typeReferences = extractTypeReferences(node.declaration);
138
+ exports.push({
139
+ name: "default",
140
+ type: "default",
141
+ imports: usedImports,
142
+ dependencies: [],
143
+ typeReferences,
144
+ loc: node.loc
145
+ });
146
+ }
147
+ }
148
+ return exports;
149
+ }
150
+ function extractFromDeclaration(declaration) {
151
+ const results = [];
152
+ if (declaration.type === "FunctionDeclaration" && "id" in declaration && declaration.id) {
153
+ results.push({ name: declaration.id.name, type: "function" });
154
+ } else if (declaration.type === "ClassDeclaration" && "id" in declaration && declaration.id) {
155
+ results.push({ name: declaration.id.name, type: "class" });
156
+ } else if (declaration.type === "VariableDeclaration") {
157
+ for (const declarator of declaration.declarations) {
158
+ if (declarator.id.type === "Identifier") {
159
+ results.push({ name: declarator.id.name, type: "const" });
160
+ }
161
+ }
162
+ } else if (declaration.type === "TSTypeAliasDeclaration") {
163
+ results.push({ name: declaration.id.name, type: "type" });
164
+ } else if (declaration.type === "TSInterfaceDeclaration") {
165
+ results.push({ name: declaration.id.name, type: "interface" });
166
+ }
167
+ return results;
168
+ }
169
+ function findUsedImports(node, importedNames) {
170
+ const usedImports = /* @__PURE__ */ new Set();
171
+ function visit(n) {
172
+ if (n.type === "Identifier" && importedNames.has(n.name)) {
173
+ usedImports.add(n.name);
174
+ }
175
+ for (const key in n) {
176
+ const value = n[key];
177
+ if (value && typeof value === "object") {
178
+ if (Array.isArray(value)) {
179
+ value.forEach((child) => {
180
+ if (child && typeof child === "object" && "type" in child) {
181
+ visit(child);
182
+ }
183
+ });
184
+ } else if ("type" in value) {
185
+ visit(value);
186
+ }
187
+ }
188
+ }
189
+ }
190
+ visit(node);
191
+ return Array.from(usedImports);
192
+ }
193
+ function calculateImportSimilarity(export1, export2) {
194
+ if (export1.imports.length === 0 && export2.imports.length === 0) {
195
+ return 1;
196
+ }
197
+ const set1 = new Set(export1.imports);
198
+ const set2 = new Set(export2.imports);
199
+ const intersection = new Set([...set1].filter((x) => set2.has(x)));
200
+ const union = /* @__PURE__ */ new Set([...set1, ...set2]);
201
+ return intersection.size / union.size;
202
+ }
203
+ function extractTypeReferences(node) {
204
+ const types = /* @__PURE__ */ new Set();
205
+ function visit(n) {
206
+ if (!n || typeof n !== "object") return;
207
+ if (n.type === "TSTypeReference" && n.typeName) {
208
+ if (n.typeName.type === "Identifier") {
209
+ types.add(n.typeName.name);
210
+ } else if (n.typeName.type === "TSQualifiedName") {
211
+ let current = n.typeName;
212
+ while (current.type === "TSQualifiedName") {
213
+ if (current.right?.type === "Identifier") {
214
+ types.add(current.right.name);
215
+ }
216
+ current = current.left;
217
+ }
218
+ if (current.type === "Identifier") {
219
+ types.add(current.name);
220
+ }
221
+ }
222
+ }
223
+ if (n.type === "TSInterfaceHeritage" && n.expression) {
224
+ if (n.expression.type === "Identifier") {
225
+ types.add(n.expression.name);
226
+ }
227
+ }
228
+ for (const key of Object.keys(n)) {
229
+ const value = n[key];
230
+ if (Array.isArray(value)) {
231
+ value.forEach(visit);
232
+ } else if (value && typeof value === "object") {
233
+ visit(value);
234
+ }
235
+ }
236
+ }
237
+ visit(node);
238
+ return Array.from(types);
239
+ }
77
240
  function parseCode(code, language) {
78
241
  return null;
79
242
  }
@@ -203,6 +366,7 @@ function getElapsedTime(startTime) {
203
366
  }
204
367
  export {
205
368
  DEFAULT_EXCLUDE,
369
+ calculateImportSimilarity,
206
370
  estimateTokens,
207
371
  extractFunctions,
208
372
  extractImports,
@@ -215,6 +379,7 @@ export {
215
379
  loadMergedConfig,
216
380
  mergeConfigWithDefaults,
217
381
  parseCode,
382
+ parseFileExports,
218
383
  readFileContent,
219
384
  resolveOutputPath,
220
385
  scanFiles
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiready/core",
3
- "version": "0.5.6",
3
+ "version": "0.7.0",
4
4
  "description": "Shared utilities for AIReady analysis tools",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -12,6 +12,14 @@
12
12
  "import": "./dist/index.mjs"
13
13
  }
14
14
  },
15
+ "scripts": {
16
+ "build": "tsup src/index.ts --format cjs,esm --dts",
17
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
18
+ "lint": "eslint src",
19
+ "clean": "rm -rf dist",
20
+ "prepublishOnly": "pnpm build",
21
+ "release": "pnpm build && pnpm publish --no-git-checks"
22
+ },
15
23
  "keywords": [
16
24
  "aiready",
17
25
  "code-analysis",
@@ -34,18 +42,14 @@
34
42
  "CONTRIBUTING.md"
35
43
  ],
36
44
  "devDependencies": {
37
- "tsup": "^8.3.5",
38
- "eslint": "^9.17.0"
45
+ "eslint": "^9.17.0",
46
+ "tsup": "^8.3.5"
39
47
  },
40
48
  "dependencies": {
49
+ "@typescript-eslint/parser": "^8.53.0",
50
+ "@typescript-eslint/typescript-estree": "^8.53.0",
51
+ "chalk": "^5.4.1",
41
52
  "glob": "^13.0.0",
42
- "chalk": "^5.4.1"
43
- },
44
- "scripts": {
45
- "build": "tsup src/index.ts --format cjs,esm --dts",
46
- "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
47
- "lint": "eslint src",
48
- "clean": "rm -rf dist",
49
- "release": "pnpm build && pnpm publish --no-git-checks"
53
+ "typescript": "^5.9.3"
50
54
  }
51
- }
55
+ }