@aiready/core 0.7.13 → 0.8.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.js CHANGED
@@ -22,7 +22,13 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  DEFAULT_EXCLUDE: () => DEFAULT_EXCLUDE,
24
24
  DEFAULT_TOOL_WEIGHTS: () => DEFAULT_TOOL_WEIGHTS,
25
+ LANGUAGE_EXTENSIONS: () => LANGUAGE_EXTENSIONS,
26
+ Language: () => Language,
27
+ ParseError: () => ParseError,
28
+ ParserFactory: () => ParserFactory,
29
+ PythonParser: () => PythonParser,
25
30
  TOOL_NAME_MAP: () => TOOL_NAME_MAP,
31
+ TypeScriptParser: () => TypeScriptParser,
26
32
  calculateImportSimilarity: () => calculateImportSimilarity,
27
33
  calculateOverallScore: () => calculateOverallScore,
28
34
  estimateTokens: () => estimateTokens,
@@ -32,11 +38,14 @@ __export(index_exports, {
32
38
  formatToolScore: () => formatToolScore,
33
39
  getElapsedTime: () => getElapsedTime,
34
40
  getFileExtension: () => getFileExtension,
41
+ getParser: () => getParser,
35
42
  getRating: () => getRating,
36
43
  getRatingDisplay: () => getRatingDisplay,
44
+ getSupportedLanguages: () => getSupportedLanguages,
37
45
  getToolWeight: () => getToolWeight,
38
46
  handleCLIError: () => handleCLIError,
39
47
  handleJSONOutput: () => handleJSONOutput,
48
+ isFileSupported: () => isFileSupported,
40
49
  isSourceFile: () => isSourceFile,
41
50
  loadConfig: () => loadConfig,
42
51
  loadMergedConfig: () => loadMergedConfig,
@@ -51,6 +60,37 @@ __export(index_exports, {
51
60
  });
52
61
  module.exports = __toCommonJS(index_exports);
53
62
 
63
+ // src/types/language.ts
64
+ var Language = /* @__PURE__ */ ((Language3) => {
65
+ Language3["TypeScript"] = "typescript";
66
+ Language3["JavaScript"] = "javascript";
67
+ Language3["Python"] = "python";
68
+ Language3["Java"] = "java";
69
+ Language3["Go"] = "go";
70
+ Language3["Rust"] = "rust";
71
+ Language3["CSharp"] = "csharp";
72
+ return Language3;
73
+ })(Language || {});
74
+ var LANGUAGE_EXTENSIONS = {
75
+ ".ts": "typescript" /* TypeScript */,
76
+ ".tsx": "typescript" /* TypeScript */,
77
+ ".js": "javascript" /* JavaScript */,
78
+ ".jsx": "javascript" /* JavaScript */,
79
+ ".py": "python" /* Python */,
80
+ ".java": "java" /* Java */,
81
+ ".go": "go" /* Go */,
82
+ ".rs": "rust" /* Rust */,
83
+ ".cs": "csharp" /* CSharp */
84
+ };
85
+ var ParseError = class extends Error {
86
+ constructor(message, filePath, loc) {
87
+ super(message);
88
+ this.filePath = filePath;
89
+ this.loc = loc;
90
+ this.name = "ParseError";
91
+ }
92
+ };
93
+
54
94
  // src/utils/file-scanner.ts
55
95
  var import_glob = require("glob");
56
96
  var import_promises = require("fs/promises");
@@ -104,8 +144,8 @@ var DEFAULT_EXCLUDE = [
104
144
  async function scanFiles(options) {
105
145
  const {
106
146
  rootDir,
107
- include = ["**/*.{ts,tsx,js,jsx,py,java}"],
108
- // Broad default - tools should filter further
147
+ include = ["**/*.{ts,tsx,js,jsx,py,java,go,rs,cs}"],
148
+ // Multi-language support
109
149
  exclude
110
150
  } = options;
111
151
  const ignoreFilePath = (0, import_path.join)(rootDir || ".", ".aireadyignore");
@@ -575,11 +615,497 @@ function formatToolScore(output) {
575
615
  }
576
616
  return result;
577
617
  }
618
+
619
+ // src/parsers/typescript-parser.ts
620
+ var import_typescript_estree2 = require("@typescript-eslint/typescript-estree");
621
+ var TypeScriptParser = class {
622
+ constructor() {
623
+ this.language = "typescript" /* TypeScript */;
624
+ this.extensions = [".ts", ".tsx", ".js", ".jsx"];
625
+ }
626
+ parse(code, filePath) {
627
+ try {
628
+ const isJavaScript = filePath.match(/\.jsx?$/i);
629
+ const ast = (0, import_typescript_estree2.parse)(code, {
630
+ loc: true,
631
+ range: true,
632
+ jsx: filePath.match(/\.[jt]sx$/i) !== null,
633
+ filePath,
634
+ sourceType: "module",
635
+ ecmaVersion: "latest"
636
+ });
637
+ const imports = this.extractImports(ast);
638
+ const exports2 = this.extractExports(ast, imports);
639
+ return {
640
+ exports: exports2,
641
+ imports,
642
+ language: isJavaScript ? "javascript" /* JavaScript */ : "typescript" /* TypeScript */,
643
+ warnings: []
644
+ };
645
+ } catch (error) {
646
+ const err = error;
647
+ throw new ParseError(
648
+ `Failed to parse ${filePath}: ${err.message}`,
649
+ filePath
650
+ );
651
+ }
652
+ }
653
+ getNamingConventions() {
654
+ return {
655
+ // camelCase for variables and functions
656
+ variablePattern: /^[a-z][a-zA-Z0-9]*$/,
657
+ functionPattern: /^[a-z][a-zA-Z0-9]*$/,
658
+ // PascalCase for classes
659
+ classPattern: /^[A-Z][a-zA-Z0-9]*$/,
660
+ // UPPER_CASE for constants
661
+ constantPattern: /^[A-Z][A-Z0-9_]*$/,
662
+ // Common exceptions (React hooks, etc.)
663
+ exceptions: ["__filename", "__dirname", "__esModule"]
664
+ };
665
+ }
666
+ canHandle(filePath) {
667
+ return this.extensions.some((ext) => filePath.toLowerCase().endsWith(ext));
668
+ }
669
+ extractImports(ast) {
670
+ const imports = [];
671
+ for (const node of ast.body) {
672
+ if (node.type === "ImportDeclaration") {
673
+ const specifiers = [];
674
+ let isTypeOnly = false;
675
+ if (node.importKind === "type") {
676
+ isTypeOnly = true;
677
+ }
678
+ for (const spec of node.specifiers) {
679
+ if (spec.type === "ImportSpecifier") {
680
+ const imported = spec.imported;
681
+ const name = imported.type === "Identifier" ? imported.name : imported.value;
682
+ specifiers.push(name);
683
+ } else if (spec.type === "ImportDefaultSpecifier") {
684
+ specifiers.push("default");
685
+ } else if (spec.type === "ImportNamespaceSpecifier") {
686
+ specifiers.push("*");
687
+ }
688
+ }
689
+ imports.push({
690
+ source: node.source.value,
691
+ specifiers,
692
+ isTypeOnly,
693
+ loc: node.loc ? {
694
+ start: { line: node.loc.start.line, column: node.loc.start.column },
695
+ end: { line: node.loc.end.line, column: node.loc.end.column }
696
+ } : void 0
697
+ });
698
+ }
699
+ }
700
+ return imports;
701
+ }
702
+ extractExports(ast, imports) {
703
+ const exports2 = [];
704
+ const importedNames = new Set(
705
+ imports.flatMap((imp) => imp.specifiers.filter((s) => s !== "*" && s !== "default"))
706
+ );
707
+ for (const node of ast.body) {
708
+ if (node.type === "ExportNamedDeclaration" && node.declaration) {
709
+ const extracted = this.extractFromDeclaration(node.declaration, importedNames);
710
+ exports2.push(...extracted);
711
+ } else if (node.type === "ExportDefaultDeclaration") {
712
+ let name = "default";
713
+ let type = "default";
714
+ if (node.declaration.type === "FunctionDeclaration" && node.declaration.id) {
715
+ name = node.declaration.id.name;
716
+ type = "function";
717
+ } else if (node.declaration.type === "ClassDeclaration" && node.declaration.id) {
718
+ name = node.declaration.id.name;
719
+ type = "class";
720
+ }
721
+ exports2.push({
722
+ name,
723
+ type,
724
+ loc: node.loc ? {
725
+ start: { line: node.loc.start.line, column: node.loc.start.column },
726
+ end: { line: node.loc.end.line, column: node.loc.end.column }
727
+ } : void 0
728
+ });
729
+ }
730
+ }
731
+ return exports2;
732
+ }
733
+ extractFromDeclaration(declaration, importedNames) {
734
+ const exports2 = [];
735
+ if (declaration.type === "FunctionDeclaration" && declaration.id) {
736
+ exports2.push({
737
+ name: declaration.id.name,
738
+ type: "function",
739
+ parameters: declaration.params.map(
740
+ (p) => p.type === "Identifier" ? p.name : "unknown"
741
+ ),
742
+ loc: declaration.loc ? {
743
+ start: {
744
+ line: declaration.loc.start.line,
745
+ column: declaration.loc.start.column
746
+ },
747
+ end: { line: declaration.loc.end.line, column: declaration.loc.end.column }
748
+ } : void 0
749
+ });
750
+ } else if (declaration.type === "ClassDeclaration" && declaration.id) {
751
+ exports2.push({
752
+ name: declaration.id.name,
753
+ type: "class",
754
+ loc: declaration.loc ? {
755
+ start: {
756
+ line: declaration.loc.start.line,
757
+ column: declaration.loc.start.column
758
+ },
759
+ end: { line: declaration.loc.end.line, column: declaration.loc.end.column }
760
+ } : void 0
761
+ });
762
+ } else if (declaration.type === "VariableDeclaration") {
763
+ for (const declarator of declaration.declarations) {
764
+ if (declarator.id.type === "Identifier") {
765
+ exports2.push({
766
+ name: declarator.id.name,
767
+ type: "const",
768
+ loc: declarator.loc ? {
769
+ start: {
770
+ line: declarator.loc.start.line,
771
+ column: declarator.loc.start.column
772
+ },
773
+ end: {
774
+ line: declarator.loc.end.line,
775
+ column: declarator.loc.end.column
776
+ }
777
+ } : void 0
778
+ });
779
+ }
780
+ }
781
+ } else if (declaration.type === "TSTypeAliasDeclaration") {
782
+ exports2.push({
783
+ name: declaration.id.name,
784
+ type: "type",
785
+ loc: declaration.loc ? {
786
+ start: {
787
+ line: declaration.loc.start.line,
788
+ column: declaration.loc.start.column
789
+ },
790
+ end: { line: declaration.loc.end.line, column: declaration.loc.end.column }
791
+ } : void 0
792
+ });
793
+ } else if (declaration.type === "TSInterfaceDeclaration") {
794
+ exports2.push({
795
+ name: declaration.id.name,
796
+ type: "interface",
797
+ loc: declaration.loc ? {
798
+ start: {
799
+ line: declaration.loc.start.line,
800
+ column: declaration.loc.start.column
801
+ },
802
+ end: { line: declaration.loc.end.line, column: declaration.loc.end.column }
803
+ } : void 0
804
+ });
805
+ }
806
+ return exports2;
807
+ }
808
+ };
809
+
810
+ // src/parsers/python-parser.ts
811
+ var PythonParser = class {
812
+ constructor() {
813
+ this.language = "python" /* Python */;
814
+ this.extensions = [".py"];
815
+ this.parser = null;
816
+ this.initialized = false;
817
+ }
818
+ /**
819
+ * Initialize the tree-sitter parser
820
+ * This is async because tree-sitter WASM needs to be loaded
821
+ */
822
+ async initialize() {
823
+ if (this.initialized) return;
824
+ try {
825
+ this.initialized = true;
826
+ } catch (error) {
827
+ throw new Error(`Failed to initialize Python parser: ${error.message}`);
828
+ }
829
+ }
830
+ parse(code, filePath) {
831
+ try {
832
+ const imports = this.extractImportsRegex(code, filePath);
833
+ const exports2 = this.extractExportsRegex(code, filePath);
834
+ return {
835
+ exports: exports2,
836
+ imports,
837
+ language: "python" /* Python */,
838
+ warnings: ["Python parsing is currently using regex-based extraction. Tree-sitter support coming soon."]
839
+ };
840
+ } catch (error) {
841
+ throw new ParseError(
842
+ `Failed to parse Python file ${filePath}: ${error.message}`,
843
+ filePath
844
+ );
845
+ }
846
+ }
847
+ getNamingConventions() {
848
+ return {
849
+ // snake_case for variables and functions
850
+ variablePattern: /^[a-z_][a-z0-9_]*$/,
851
+ functionPattern: /^[a-z_][a-z0-9_]*$/,
852
+ // PascalCase for classes
853
+ classPattern: /^[A-Z][a-zA-Z0-9]*$/,
854
+ // UPPER_CASE for constants
855
+ constantPattern: /^[A-Z][A-Z0-9_]*$/,
856
+ // Python special methods and common exceptions
857
+ exceptions: [
858
+ "__init__",
859
+ "__str__",
860
+ "__repr__",
861
+ "__name__",
862
+ "__main__",
863
+ "__file__",
864
+ "__doc__",
865
+ "__all__",
866
+ "__version__",
867
+ "__author__",
868
+ "__dict__",
869
+ "__class__",
870
+ "__module__",
871
+ "__bases__"
872
+ ]
873
+ };
874
+ }
875
+ canHandle(filePath) {
876
+ return filePath.toLowerCase().endsWith(".py");
877
+ }
878
+ /**
879
+ * Regex-based import extraction (temporary implementation)
880
+ */
881
+ extractImportsRegex(code, filePath) {
882
+ const imports = [];
883
+ const lines = code.split("\n");
884
+ const importRegex = /^\s*import\s+([a-zA-Z0-9_., ]+)/;
885
+ const fromImportRegex = /^\s*from\s+([a-zA-Z0-9_.]+)\s+import\s+(.+)/;
886
+ lines.forEach((line, idx) => {
887
+ if (line.trim().startsWith("#")) return;
888
+ const importMatch = line.match(importRegex);
889
+ if (importMatch) {
890
+ const modules = importMatch[1].split(",").map((m) => m.trim().split(" as ")[0]);
891
+ modules.forEach((module2) => {
892
+ imports.push({
893
+ source: module2,
894
+ specifiers: [module2],
895
+ loc: {
896
+ start: { line: idx + 1, column: 0 },
897
+ end: { line: idx + 1, column: line.length }
898
+ }
899
+ });
900
+ });
901
+ return;
902
+ }
903
+ const fromMatch = line.match(fromImportRegex);
904
+ if (fromMatch) {
905
+ const module2 = fromMatch[1];
906
+ const imports_str = fromMatch[2];
907
+ if (imports_str.trim() === "*") {
908
+ imports.push({
909
+ source: module2,
910
+ specifiers: ["*"],
911
+ loc: {
912
+ start: { line: idx + 1, column: 0 },
913
+ end: { line: idx + 1, column: line.length }
914
+ }
915
+ });
916
+ return;
917
+ }
918
+ const specifiers = imports_str.split(",").map((s) => s.trim().split(" as ")[0]);
919
+ imports.push({
920
+ source: module2,
921
+ specifiers,
922
+ loc: {
923
+ start: { line: idx + 1, column: 0 },
924
+ end: { line: idx + 1, column: line.length }
925
+ }
926
+ });
927
+ }
928
+ });
929
+ return imports;
930
+ }
931
+ /**
932
+ * Regex-based export extraction (temporary implementation)
933
+ *
934
+ * Python doesn't have explicit exports like JavaScript.
935
+ * We extract:
936
+ * - Functions defined at module level (def)
937
+ * - Classes defined at module level (class)
938
+ * - Variables in __all__ list
939
+ */
940
+ extractExportsRegex(code, filePath) {
941
+ const exports2 = [];
942
+ const lines = code.split("\n");
943
+ const functionRegex = /^def\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/;
944
+ const classRegex = /^class\s+([a-zA-Z_][a-zA-Z0-9_]*)/;
945
+ const allRegex = /__all__\s*=\s*\[([^\]]+)\]/;
946
+ let inClass = false;
947
+ let classIndent = 0;
948
+ lines.forEach((line, idx) => {
949
+ const indent = line.search(/\S/);
950
+ if (line.match(classRegex)) {
951
+ inClass = true;
952
+ classIndent = indent;
953
+ } else if (inClass && indent <= classIndent && line.trim()) {
954
+ inClass = false;
955
+ }
956
+ if (inClass) {
957
+ const classMatch = line.match(classRegex);
958
+ if (classMatch) {
959
+ exports2.push({
960
+ name: classMatch[1],
961
+ type: "class",
962
+ loc: {
963
+ start: { line: idx + 1, column: indent },
964
+ end: { line: idx + 1, column: line.length }
965
+ }
966
+ });
967
+ }
968
+ return;
969
+ }
970
+ const funcMatch = line.match(functionRegex);
971
+ if (funcMatch && indent === 0) {
972
+ const name = funcMatch[1];
973
+ if (!name.startsWith("_") || name.startsWith("__")) {
974
+ exports2.push({
975
+ name,
976
+ type: "function",
977
+ loc: {
978
+ start: { line: idx + 1, column: 0 },
979
+ end: { line: idx + 1, column: line.length }
980
+ }
981
+ });
982
+ }
983
+ }
984
+ const allMatch = line.match(allRegex);
985
+ if (allMatch) {
986
+ const names = allMatch[1].split(",").map((n) => n.trim().replace(/['"]/g, ""));
987
+ names.forEach((name) => {
988
+ if (name && !exports2.find((e) => e.name === name)) {
989
+ exports2.push({
990
+ name,
991
+ type: "variable",
992
+ loc: {
993
+ start: { line: idx + 1, column: 0 },
994
+ end: { line: idx + 1, column: line.length }
995
+ }
996
+ });
997
+ }
998
+ });
999
+ }
1000
+ });
1001
+ return exports2;
1002
+ }
1003
+ };
1004
+
1005
+ // src/parsers/parser-factory.ts
1006
+ var ParserFactory = class _ParserFactory {
1007
+ constructor() {
1008
+ this.parsers = /* @__PURE__ */ new Map();
1009
+ this.extensionMap = new Map(
1010
+ Object.entries(LANGUAGE_EXTENSIONS).map(([ext, lang]) => [ext, lang])
1011
+ );
1012
+ this.registerParser(new TypeScriptParser());
1013
+ this.registerParser(new PythonParser());
1014
+ }
1015
+ /**
1016
+ * Get singleton instance
1017
+ */
1018
+ static getInstance() {
1019
+ if (!_ParserFactory.instance) {
1020
+ _ParserFactory.instance = new _ParserFactory();
1021
+ }
1022
+ return _ParserFactory.instance;
1023
+ }
1024
+ /**
1025
+ * Register a language parser
1026
+ */
1027
+ registerParser(parser) {
1028
+ this.parsers.set(parser.language, parser);
1029
+ parser.extensions.forEach((ext) => {
1030
+ this.extensionMap.set(ext, parser.language);
1031
+ });
1032
+ }
1033
+ /**
1034
+ * Get parser for a specific language
1035
+ */
1036
+ getParserForLanguage(language) {
1037
+ return this.parsers.get(language) || null;
1038
+ }
1039
+ /**
1040
+ * Get parser for a file based on its extension
1041
+ */
1042
+ getParserForFile(filePath) {
1043
+ const ext = this.getFileExtension(filePath);
1044
+ const language = this.extensionMap.get(ext);
1045
+ if (!language) {
1046
+ return null;
1047
+ }
1048
+ return this.parsers.get(language) || null;
1049
+ }
1050
+ /**
1051
+ * Check if a file is supported
1052
+ */
1053
+ isSupported(filePath) {
1054
+ return this.getParserForFile(filePath) !== null;
1055
+ }
1056
+ /**
1057
+ * Get all registered languages
1058
+ */
1059
+ getSupportedLanguages() {
1060
+ return Array.from(this.parsers.keys());
1061
+ }
1062
+ /**
1063
+ * Get all supported file extensions
1064
+ */
1065
+ getSupportedExtensions() {
1066
+ return Array.from(this.extensionMap.keys());
1067
+ }
1068
+ /**
1069
+ * Get language for a file
1070
+ */
1071
+ getLanguageForFile(filePath) {
1072
+ const ext = this.getFileExtension(filePath);
1073
+ return this.extensionMap.get(ext) || null;
1074
+ }
1075
+ /**
1076
+ * Extract file extension (with dot)
1077
+ */
1078
+ getFileExtension(filePath) {
1079
+ const match = filePath.match(/\.[^.]+$/);
1080
+ return match ? match[0].toLowerCase() : "";
1081
+ }
1082
+ /**
1083
+ * Reset factory (useful for testing)
1084
+ */
1085
+ static reset() {
1086
+ _ParserFactory.instance = new _ParserFactory();
1087
+ }
1088
+ };
1089
+ function getParser(filePath) {
1090
+ return ParserFactory.getInstance().getParserForFile(filePath);
1091
+ }
1092
+ function isFileSupported(filePath) {
1093
+ return ParserFactory.getInstance().isSupported(filePath);
1094
+ }
1095
+ function getSupportedLanguages() {
1096
+ return ParserFactory.getInstance().getSupportedLanguages();
1097
+ }
578
1098
  // Annotate the CommonJS export names for ESM import in node:
579
1099
  0 && (module.exports = {
580
1100
  DEFAULT_EXCLUDE,
581
1101
  DEFAULT_TOOL_WEIGHTS,
1102
+ LANGUAGE_EXTENSIONS,
1103
+ Language,
1104
+ ParseError,
1105
+ ParserFactory,
1106
+ PythonParser,
582
1107
  TOOL_NAME_MAP,
1108
+ TypeScriptParser,
583
1109
  calculateImportSimilarity,
584
1110
  calculateOverallScore,
585
1111
  estimateTokens,
@@ -589,11 +1115,14 @@ function formatToolScore(output) {
589
1115
  formatToolScore,
590
1116
  getElapsedTime,
591
1117
  getFileExtension,
1118
+ getParser,
592
1119
  getRating,
593
1120
  getRatingDisplay,
1121
+ getSupportedLanguages,
594
1122
  getToolWeight,
595
1123
  handleCLIError,
596
1124
  handleJSONOutput,
1125
+ isFileSupported,
597
1126
  isSourceFile,
598
1127
  loadConfig,
599
1128
  loadMergedConfig,