sadrazam 0.1.0-alpha.6

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/LICENSE +21 -0
  3. package/README.md +343 -0
  4. package/dist/aiClient.d.ts +4 -0
  5. package/dist/aiClient.d.ts.map +1 -0
  6. package/dist/aiClient.js +152 -0
  7. package/dist/aiClient.js.map +1 -0
  8. package/dist/aiConfig.d.ts +19 -0
  9. package/dist/aiConfig.d.ts.map +1 -0
  10. package/dist/aiConfig.js +28 -0
  11. package/dist/aiConfig.js.map +1 -0
  12. package/dist/config.d.ts +26 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/config.js +32 -0
  15. package/dist/config.js.map +1 -0
  16. package/dist/fileFinder.d.ts +2 -0
  17. package/dist/fileFinder.d.ts.map +1 -0
  18. package/dist/fileFinder.js +14 -0
  19. package/dist/fileFinder.js.map +1 -0
  20. package/dist/findings.d.ts +13 -0
  21. package/dist/findings.d.ts.map +1 -0
  22. package/dist/findings.js +52 -0
  23. package/dist/findings.js.map +1 -0
  24. package/dist/importParser.d.ts +6 -0
  25. package/dist/importParser.d.ts.map +1 -0
  26. package/dist/importParser.js +36 -0
  27. package/dist/importParser.js.map +1 -0
  28. package/dist/index.d.ts +3 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +185 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/packageReader.d.ts +14 -0
  33. package/dist/packageReader.d.ts.map +1 -0
  34. package/dist/packageReader.js +51 -0
  35. package/dist/packageReader.js.map +1 -0
  36. package/dist/reporters.d.ts +42 -0
  37. package/dist/reporters.d.ts.map +1 -0
  38. package/dist/reporters.js +138 -0
  39. package/dist/reporters.js.map +1 -0
  40. package/dist/scan.d.ts +25 -0
  41. package/dist/scan.d.ts.map +1 -0
  42. package/dist/scan.js +152 -0
  43. package/dist/scan.js.map +1 -0
  44. package/dist/scriptParser.d.ts +7 -0
  45. package/dist/scriptParser.d.ts.map +1 -0
  46. package/dist/scriptParser.js +117 -0
  47. package/dist/scriptParser.js.map +1 -0
  48. package/dist/sourceMapper.d.ts +2 -0
  49. package/dist/sourceMapper.d.ts.map +1 -0
  50. package/dist/sourceMapper.js +57 -0
  51. package/dist/sourceMapper.js.map +1 -0
  52. package/dist/workspaceFinder.d.ts +11 -0
  53. package/dist/workspaceFinder.d.ts.map +1 -0
  54. package/dist/workspaceFinder.js +62 -0
  55. package/dist/workspaceFinder.js.map +1 -0
  56. package/package.json +53 -0
package/dist/config.js ADDED
@@ -0,0 +1,32 @@
1
+ import { access, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { findNearestPackageJson, readPackageJson } from "./packageReader.js";
4
+ const CONFIG_FILENAMES = ["sarraf.json"];
5
+ export async function loadSarrafConfig(startDir) {
6
+ const packagePath = await findNearestPackageJson(startDir);
7
+ const packageDir = path.dirname(packagePath);
8
+ for (const filename of CONFIG_FILENAMES) {
9
+ const configPath = path.join(packageDir, filename);
10
+ if (await fileExists(configPath)) {
11
+ return {
12
+ config: JSON.parse(await readFile(configPath, "utf8")),
13
+ source: configPath,
14
+ };
15
+ }
16
+ }
17
+ const packageJson = (await readPackageJson(packagePath));
18
+ return {
19
+ config: packageJson.sarraf ?? {},
20
+ source: packageJson.sarraf ? `${packagePath}#sarraf` : "defaults",
21
+ };
22
+ }
23
+ async function fileExists(filePath) {
24
+ try {
25
+ await access(filePath);
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AA+B7E,MAAM,gBAAgB,GAAG,CAAC,aAAa,CAAC,CAAC;AAEzC,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IACrD,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAE7C,KAAK,MAAM,QAAQ,IAAI,gBAAgB,EAAE,CAAC;QACxC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAEnD,IAAI,MAAM,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACjC,OAAO;gBACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAiB;gBACtE,MAAM,EAAE,UAAU;aACnB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,CAAC,MAAM,eAAe,CAAC,WAAW,CAAC,CAA0B,CAAC;IAClF,OAAO;QACL,MAAM,EAAE,WAAW,CAAC,MAAM,IAAI,EAAE;QAChC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,WAAW,SAAS,CAAC,CAAC,CAAC,UAAU;KAClE,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function findSourceFiles(rootDir: string): Promise<string[]>;
2
+ //# sourceMappingURL=fileFinder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileFinder.d.ts","sourceRoot":"","sources":["../src/fileFinder.ts"],"names":[],"mappings":"AAMA,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CASxE"}
@@ -0,0 +1,14 @@
1
+ import fg from "fast-glob";
2
+ import path from "node:path";
3
+ const DEFAULT_PATTERNS = ["**/*.{js,cjs,mjs,ts,cts,mts,jsx,tsx}"];
4
+ const DEFAULT_IGNORES = ["**/node_modules/**", "**/dist/**", "**/.git/**"];
5
+ export async function findSourceFiles(rootDir) {
6
+ const cwd = path.resolve(rootDir);
7
+ return fg(DEFAULT_PATTERNS, {
8
+ cwd,
9
+ absolute: true,
10
+ onlyFiles: true,
11
+ ignore: DEFAULT_IGNORES,
12
+ });
13
+ }
14
+ //# sourceMappingURL=fileFinder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileFinder.js","sourceRoot":"","sources":["../src/fileFinder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,gBAAgB,GAAG,CAAC,sCAAsC,CAAC,CAAC;AAClE,MAAM,eAAe,GAAG,CAAC,oBAAoB,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;AAE3E,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAElC,OAAO,EAAE,CAAC,gBAAgB,EAAE;QAC1B,GAAG;QACH,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,MAAM,EAAE,eAAe;KACxB,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { ActiveFinding, FindingType } from "./reporters.js";
2
+ import type { ScanResult } from "./scan.js";
3
+ export interface FindingRules {
4
+ include: FindingType[];
5
+ exclude: FindingType[];
6
+ allowUnusedDependencies: string[];
7
+ allowUnusedDevDependencies: string[];
8
+ allowMissingPackages: string[];
9
+ allowMisplacedDevDependencies: string[];
10
+ ignorePackages: string[];
11
+ }
12
+ export declare function getActiveFindings(result: ScanResult, rules: FindingRules, production: boolean): ActiveFinding[];
13
+ //# sourceMappingURL=findings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../src/findings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAClC,0BAA0B,EAAE,MAAM,EAAE,CAAC;IACrC,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,6BAA6B,EAAE,MAAM,EAAE,CAAC;IACxC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,YAAY,EACnB,UAAU,EAAE,OAAO,GAClB,aAAa,EAAE,CAiDjB"}
@@ -0,0 +1,52 @@
1
+ export function getActiveFindings(result, rules, production) {
2
+ const candidates = [
3
+ {
4
+ type: "missing",
5
+ title: "Missing from package.json",
6
+ items: filterPackages(result.missingPackages, [
7
+ ...rules.allowMissingPackages,
8
+ ...rules.ignorePackages,
9
+ ]),
10
+ },
11
+ {
12
+ type: "unused-dependencies",
13
+ title: "Unused dependencies",
14
+ items: filterPackages(result.unusedDependencies, [
15
+ ...rules.allowUnusedDependencies,
16
+ ...rules.ignorePackages,
17
+ ]),
18
+ },
19
+ {
20
+ type: "unused-devDependencies",
21
+ title: "Unused devDependencies",
22
+ items: production
23
+ ? []
24
+ : filterPackages(result.unusedDevDependencies, [
25
+ ...rules.allowUnusedDevDependencies,
26
+ ...rules.ignorePackages,
27
+ ]),
28
+ },
29
+ {
30
+ type: "misplaced-devDependencies",
31
+ title: "Dev dependencies used in production files",
32
+ items: filterPackages(result.misplacedDevDependencies, [
33
+ ...rules.allowMisplacedDevDependencies,
34
+ ...rules.ignorePackages,
35
+ ]),
36
+ },
37
+ ];
38
+ return candidates.filter((candidate) => {
39
+ if (rules.include.length > 0 && !rules.include.includes(candidate.type)) {
40
+ return false;
41
+ }
42
+ if (rules.exclude.includes(candidate.type)) {
43
+ return false;
44
+ }
45
+ return candidate.items.length > 0;
46
+ });
47
+ }
48
+ function filterPackages(items, blocked) {
49
+ const blockedSet = new Set(blocked);
50
+ return items.filter((item) => !blockedSet.has(item));
51
+ }
52
+ //# sourceMappingURL=findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../src/findings.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,iBAAiB,CAC/B,MAAkB,EAClB,KAAmB,EACnB,UAAmB;IAEnB,MAAM,UAAU,GAAoB;QAClC;YACE,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,2BAA2B;YAClC,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,eAAe,EAAE;gBAC5C,GAAG,KAAK,CAAC,oBAAoB;gBAC7B,GAAG,KAAK,CAAC,cAAc;aACxB,CAAC;SACH;QACD;YACE,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,qBAAqB;YAC5B,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,kBAAkB,EAAE;gBAC/C,GAAG,KAAK,CAAC,uBAAuB;gBAChC,GAAG,KAAK,CAAC,cAAc;aACxB,CAAC;SACH;QACD;YACE,IAAI,EAAE,wBAAwB;YAC9B,KAAK,EAAE,wBAAwB;YAC/B,KAAK,EAAE,UAAU;gBACf,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,qBAAqB,EAAE;oBAC3C,GAAG,KAAK,CAAC,0BAA0B;oBACnC,GAAG,KAAK,CAAC,cAAc;iBACxB,CAAC;SACP;QACD;YACE,IAAI,EAAE,2BAA2B;YACjC,KAAK,EAAE,2CAA2C;YAClD,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,wBAAwB,EAAE;gBACrD,GAAG,KAAK,CAAC,6BAA6B;gBACtC,GAAG,KAAK,CAAC,cAAc;aACxB,CAAC;SACH;KACF,CAAC;IAEF,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE;QACrC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YACxE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,SAAS,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,cAAc,CAAC,KAAe,EAAE,OAAiB;IACxD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IACpC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,6 @@
1
+ export interface ParsedImport {
2
+ specifier: string;
3
+ kind: "import" | "import-equals" | "export-from" | "dynamic-import" | "require" | "require-resolve";
4
+ }
5
+ export declare function parseImports(source: string): ParsedImport[];
6
+ //# sourceMappingURL=importParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importParser.d.ts","sourceRoot":"","sources":["../src/importParser.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EACA,QAAQ,GACR,eAAe,GACf,aAAa,GACb,gBAAgB,GAChB,SAAS,GACT,iBAAiB,CAAC;CACvB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAW3D"}
@@ -0,0 +1,36 @@
1
+ const IMPORT_RE = /\bimport\s+(?:type\s+)?(?:[^"'`]+?\s+from\s+)?["'`]([^"'`]+)["'`]/g;
2
+ const IMPORT_EQUALS_RE = /\bimport\s+[\w*\s{},]+\s*=\s*require\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g;
3
+ const DYNAMIC_IMPORT_RE = /\bimport\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g;
4
+ const REQUIRE_RE = /\brequire\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g;
5
+ const REQUIRE_RESOLVE_RE = /\brequire\.resolve\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g;
6
+ const EXPORT_FROM_RE = /\bexport\s+(?:\*|{[^}]+})\s+from\s+["'`]([^"'`]+)["'`]/g;
7
+ export function parseImports(source) {
8
+ const matches = [];
9
+ collectMatches(matches, source, IMPORT_RE, "import");
10
+ collectMatches(matches, source, IMPORT_EQUALS_RE, "import-equals");
11
+ collectMatches(matches, source, EXPORT_FROM_RE, "export-from");
12
+ collectMatches(matches, source, DYNAMIC_IMPORT_RE, "dynamic-import");
13
+ collectMatches(matches, source, REQUIRE_RE, "require");
14
+ collectMatches(matches, source, REQUIRE_RESOLVE_RE, "require-resolve");
15
+ return dedupe(matches);
16
+ }
17
+ function collectMatches(matches, source, pattern, kind) {
18
+ for (const match of source.matchAll(pattern)) {
19
+ const specifier = match[1]?.trim();
20
+ if (specifier) {
21
+ matches.push({ specifier, kind });
22
+ }
23
+ }
24
+ }
25
+ function dedupe(items) {
26
+ const seen = new Set();
27
+ return items.filter((item) => {
28
+ const key = `${item.kind}:${item.specifier}`;
29
+ if (seen.has(key)) {
30
+ return false;
31
+ }
32
+ seen.add(key);
33
+ return true;
34
+ });
35
+ }
36
+ //# sourceMappingURL=importParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"importParser.js","sourceRoot":"","sources":["../src/importParser.ts"],"names":[],"mappings":"AAAA,MAAM,SAAS,GACb,oEAAoE,CAAC;AACvE,MAAM,gBAAgB,GAAG,uEAAuE,CAAC;AACjG,MAAM,iBAAiB,GAAG,2CAA2C,CAAC;AACtE,MAAM,UAAU,GAAG,4CAA4C,CAAC;AAChE,MAAM,kBAAkB,GAAG,qDAAqD,CAAC;AACjF,MAAM,cAAc,GAAG,yDAAyD,CAAC;AAajF,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,OAAO,GAAmB,EAAE,CAAC;IAEnC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACrD,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,eAAe,CAAC,CAAC;IACnE,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,aAAa,CAAC,CAAC;IAC/D,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;IACrE,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IACvD,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,iBAAiB,CAAC,CAAC;IAEvE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,cAAc,CACrB,OAAuB,EACvB,MAAc,EACd,OAAe,EACf,IAA0B;IAE1B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QAEnC,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,KAAqB;IACnC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC3B,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAE7C,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAClB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+ import path from "node:path";
3
+ import pc from "picocolors";
4
+ import { Command } from "commander";
5
+ import { generateAiSummary } from "./aiClient.js";
6
+ import { resolveAiConfig, SUPPORTED_AI_PROVIDERS } from "./aiConfig.js";
7
+ import { loadSarrafConfig } from "./config.js";
8
+ import { getActiveFindings } from "./findings.js";
9
+ import { renderReport, SUPPORTED_REPORTERS, } from "./reporters.js";
10
+ import { scanProject } from "./scan.js";
11
+ import { discoverWorkspaces } from "./workspaceFinder.js";
12
+ const program = new Command();
13
+ const SUPPORTED_FINDING_TYPES = [
14
+ "missing",
15
+ "unused-dependencies",
16
+ "unused-devDependencies",
17
+ "misplaced-devDependencies",
18
+ ];
19
+ program
20
+ .name("sarraf")
21
+ .description("Analyze dependency usage, detect hygiene issues, and trace why packages are used.")
22
+ .argument("[target]", "directory to scan", ".")
23
+ .option("--ai", "enable AI-assisted analysis")
24
+ .option("--provider <provider>", `AI provider (${SUPPORTED_AI_PROVIDERS.join(", ")})`)
25
+ .option("--model <model>", "AI model name")
26
+ .option("--reporter <type>", `reporter (${SUPPORTED_REPORTERS.join(", ")})`)
27
+ .option("--include <types>", "comma-separated finding types to include")
28
+ .option("--exclude <types>", "comma-separated finding types to exclude")
29
+ .option("--workspace <names>", "comma-separated workspace filters")
30
+ .option("--production", "scan production files only")
31
+ .option("--strict", "flag devDependencies used in production files")
32
+ .option("--debug", "print resolved debug information")
33
+ .option("--trace <package>", "trace where a package is used")
34
+ .option("--ignore-packages <names>", "comma-separated package names to ignore in findings")
35
+ .option("--allow-unused-dependencies <names>", "comma-separated dependency allowlist")
36
+ .option("--allow-unused-dev-dependencies <names>", "comma-separated devDependency allowlist")
37
+ .option("--allow-missing-packages <names>", "comma-separated missing package allowlist")
38
+ .option("--allow-misplaced-dev-dependencies <names>", "comma-separated misplaced devDependency allowlist")
39
+ .addHelpText("after", `
40
+ Examples:
41
+ sarraf .
42
+ sarraf . --reporter json
43
+ sarraf . --trace typescript
44
+ sarraf . --workspace packages/web
45
+ sarraf . --production --strict
46
+ AI_PROVIDER=openai AI_TOKEN=... sarraf . --ai
47
+ `)
48
+ .action(async (target, options) => {
49
+ try {
50
+ const targetDir = path.resolve(target);
51
+ const loadedConfig = await loadSarrafConfig(targetDir);
52
+ const mergedOptions = mergeCliWithConfig(options, loadedConfig.config);
53
+ const aiConfig = resolveAiConfig({
54
+ ai: mergedOptions.ai,
55
+ provider: mergedOptions.provider,
56
+ model: mergedOptions.model,
57
+ configAi: loadedConfig.config.ai,
58
+ });
59
+ const reporter = parseReporter(mergedOptions.reporter);
60
+ const include = parseFindingTypes(mergedOptions.include);
61
+ const exclude = parseFindingTypes(mergedOptions.exclude);
62
+ const workspaceFilters = parseCsvOption(mergedOptions.workspace);
63
+ const rules = buildFindingRules(mergedOptions, include, exclude);
64
+ const { rootDir, workspaces } = await discoverWorkspaces(targetDir, workspaceFilters);
65
+ const workspaceReports = await Promise.all(workspaces.map(async (workspace) => {
66
+ const result = await scanProject(workspace.dir, {
67
+ production: Boolean(mergedOptions.production),
68
+ strict: Boolean(mergedOptions.strict),
69
+ });
70
+ const findings = getActiveFindings(result, rules, Boolean(mergedOptions.production));
71
+ return {
72
+ workspace,
73
+ result,
74
+ findings,
75
+ };
76
+ }));
77
+ const warnings = [];
78
+ let aiSummary;
79
+ if (aiConfig) {
80
+ try {
81
+ aiSummary = await generateAiSummary(aiConfig, workspaceReports);
82
+ }
83
+ catch (error) {
84
+ const message = error instanceof Error ? error.message : String(error);
85
+ warnings.push(`AI summary unavailable: ${message}`);
86
+ }
87
+ }
88
+ const report = renderReport({
89
+ targetDir: rootDir,
90
+ reporter,
91
+ debug: Boolean(mergedOptions.debug),
92
+ production: Boolean(mergedOptions.production),
93
+ strict: Boolean(mergedOptions.strict),
94
+ include,
95
+ exclude,
96
+ workspaces: workspaceReports,
97
+ configSource: loadedConfig.source,
98
+ rulesSummary: {
99
+ ignorePackages: rules.ignorePackages,
100
+ allowUnusedDependencies: rules.allowUnusedDependencies,
101
+ allowUnusedDevDependencies: rules.allowUnusedDevDependencies,
102
+ allowMissingPackages: rules.allowMissingPackages,
103
+ allowMisplacedDevDependencies: rules.allowMisplacedDevDependencies,
104
+ },
105
+ ...(warnings.length > 0 ? { warnings } : {}),
106
+ ...(mergedOptions.trace ? { trace: String(mergedOptions.trace) } : {}),
107
+ ...(aiSummary ? { aiSummary } : {}),
108
+ ...(aiConfig
109
+ ? {
110
+ ai: {
111
+ provider: aiConfig.provider,
112
+ ...(aiConfig.model ? { model: aiConfig.model } : {}),
113
+ },
114
+ }
115
+ : {}),
116
+ });
117
+ console.log(report);
118
+ if (workspaceReports.some((workspace) => workspace.findings.some((finding) => finding.items.length > 0))) {
119
+ process.exitCode = 2;
120
+ }
121
+ }
122
+ catch (error) {
123
+ const message = error instanceof Error ? error.message : "Unknown error";
124
+ console.error(pc.red(`Error: ${message}`));
125
+ process.exitCode = 1;
126
+ }
127
+ });
128
+ program.parseAsync(process.argv);
129
+ function parseReporter(value) {
130
+ if (SUPPORTED_REPORTERS.includes(value)) {
131
+ return value;
132
+ }
133
+ throw new Error(`Unsupported reporter "${value}". Supported reporters: ${SUPPORTED_REPORTERS.join(", ")}`);
134
+ }
135
+ function parseFindingTypes(value) {
136
+ const items = parseCsvOption(value);
137
+ for (const item of items) {
138
+ if (!SUPPORTED_FINDING_TYPES.includes(item)) {
139
+ throw new Error(`Unsupported finding type "${item}". Supported finding types: ${SUPPORTED_FINDING_TYPES.join(", ")}`);
140
+ }
141
+ }
142
+ return items;
143
+ }
144
+ function parseCsvOption(value) {
145
+ return (value ?? "")
146
+ .split(",")
147
+ .map((item) => item.trim())
148
+ .filter(Boolean);
149
+ }
150
+ function buildFindingRules(options, include, exclude) {
151
+ return {
152
+ include,
153
+ exclude,
154
+ ignorePackages: parseCsvOption(options.ignorePackages),
155
+ allowUnusedDependencies: parseCsvOption(options.allowUnusedDependencies),
156
+ allowUnusedDevDependencies: parseCsvOption(options.allowUnusedDevDependencies),
157
+ allowMissingPackages: parseCsvOption(options.allowMissingPackages),
158
+ allowMisplacedDevDependencies: parseCsvOption(options.allowMisplacedDevDependencies),
159
+ };
160
+ }
161
+ function mergeCliWithConfig(rawOptions, config) {
162
+ return {
163
+ ai: Boolean(rawOptions.ai),
164
+ provider: asOptionalString(rawOptions.provider) ?? config.ai?.provider,
165
+ model: asOptionalString(rawOptions.model) ?? config.ai?.model,
166
+ reporter: asOptionalString(rawOptions.reporter) ?? config.reporter ?? "text",
167
+ include: asOptionalString(rawOptions.include) ?? config.include?.join(","),
168
+ exclude: asOptionalString(rawOptions.exclude) ?? config.exclude?.join(","),
169
+ workspace: asOptionalString(rawOptions.workspace) ?? config.workspace?.join(","),
170
+ production: rawOptions.production === true ? true : config.production ?? false,
171
+ strict: rawOptions.strict === true ? true : config.strict ?? false,
172
+ debug: rawOptions.debug === true ? true : config.debug ?? false,
173
+ trace: asOptionalString(rawOptions.trace) ?? config.trace,
174
+ ignorePackages: asOptionalString(rawOptions.ignorePackages) ?? config.ignorePackages?.join(","),
175
+ allowUnusedDependencies: asOptionalString(rawOptions.allowUnusedDependencies) ?? config.allowUnusedDependencies?.join(","),
176
+ allowUnusedDevDependencies: asOptionalString(rawOptions.allowUnusedDevDependencies) ?? config.allowUnusedDevDependencies?.join(","),
177
+ allowMissingPackages: asOptionalString(rawOptions.allowMissingPackages) ?? config.allowMissingPackages?.join(","),
178
+ allowMisplacedDevDependencies: asOptionalString(rawOptions.allowMisplacedDevDependencies)
179
+ ?? config.allowMisplacedDevDependencies?.join(","),
180
+ };
181
+ }
182
+ function asOptionalString(value) {
183
+ return typeof value === "string" && value.trim() ? value : undefined;
184
+ }
185
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface PackageMetadata {
2
+ packagePath: string;
3
+ packageDir: string;
4
+ dependencies: Set<string>;
5
+ devDependencies: Set<string>;
6
+ peerDependencies: Set<string>;
7
+ optionalDependencies: Set<string>;
8
+ allDependencies: Set<string>;
9
+ scripts: Record<string, string>;
10
+ }
11
+ export declare function readPackageMetadata(rootDir: string): Promise<PackageMetadata>;
12
+ export declare function readPackageJson(packagePath: string): Promise<unknown>;
13
+ export declare function findNearestPackageJson(startDir: string): Promise<string>;
14
+ //# sourceMappingURL=packageReader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageReader.d.ts","sourceRoot":"","sources":["../src/packageReader.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,oBAAoB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClC,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAUD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAyBnF;AAED,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE3E;AAED,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyB9E"}
@@ -0,0 +1,51 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ export async function readPackageMetadata(rootDir) {
4
+ const packagePath = await findNearestPackageJson(rootDir);
5
+ const packageJson = (await readPackageJson(packagePath));
6
+ const dependencies = new Set(Object.keys(packageJson.dependencies ?? {}));
7
+ const devDependencies = new Set(Object.keys(packageJson.devDependencies ?? {}));
8
+ const peerDependencies = new Set(Object.keys(packageJson.peerDependencies ?? {}));
9
+ const optionalDependencies = new Set(Object.keys(packageJson.optionalDependencies ?? {}));
10
+ const allDependencies = new Set([
11
+ ...dependencies,
12
+ ...devDependencies,
13
+ ...peerDependencies,
14
+ ...optionalDependencies,
15
+ ]);
16
+ return {
17
+ packagePath,
18
+ packageDir: path.dirname(packagePath),
19
+ dependencies,
20
+ devDependencies,
21
+ peerDependencies,
22
+ optionalDependencies,
23
+ allDependencies,
24
+ scripts: packageJson.scripts ?? {},
25
+ };
26
+ }
27
+ export async function readPackageJson(packagePath) {
28
+ return JSON.parse(await readFile(packagePath, "utf8"));
29
+ }
30
+ export async function findNearestPackageJson(startDir) {
31
+ let currentDir = path.resolve(startDir);
32
+ while (true) {
33
+ const candidate = path.join(currentDir, "package.json");
34
+ try {
35
+ await readFile(candidate, "utf8");
36
+ return candidate;
37
+ }
38
+ catch (error) {
39
+ const typedError = error;
40
+ if (typedError.code !== "ENOENT") {
41
+ throw error;
42
+ }
43
+ }
44
+ const parentDir = path.dirname(currentDir);
45
+ if (parentDir === currentDir) {
46
+ throw new Error(`No package.json found from ${startDir}`);
47
+ }
48
+ currentDir = parentDir;
49
+ }
50
+ }
51
+ //# sourceMappingURL=packageReader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"packageReader.js","sourceRoot":"","sources":["../src/packageReader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAqB7B,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe;IACvD,MAAM,WAAW,GAAG,MAAM,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,CAAC,MAAM,eAAe,CAAC,WAAW,CAAC,CAAqB,CAAC;IAE7E,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,CAAC;IAClF,MAAM,eAAe,GAAG,IAAI,GAAG,CAAS,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,CAAC;IACxF,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAS,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1F,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAS,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC,CAAC;IAClG,MAAM,eAAe,GAAG,IAAI,GAAG,CAAS;QACtC,GAAG,YAAY;QACf,GAAG,eAAe;QAClB,GAAG,gBAAgB;QACnB,GAAG,oBAAoB;KACxB,CAAC,CAAC;IAEH,OAAO;QACL,WAAW;QACX,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;QACrC,YAAY;QACZ,eAAe;QACf,gBAAgB;QAChB,oBAAoB;QACpB,eAAe;QACf,OAAO,EAAE,WAAW,CAAC,OAAO,IAAI,EAAE;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,WAAmB;IACvD,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,QAAgB;IAC3D,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAExC,OAAO,IAAI,EAAE,CAAC;QACZ,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QAExD,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAClC,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,UAAU,GAAG,KAA8B,CAAC;YAElD,IAAI,UAAU,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACjC,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAE3C,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,UAAU,GAAG,SAAS,CAAC;IACzB,CAAC;AACH,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { ScanResult } from "./scan.js";
2
+ import type { WorkspaceTarget } from "./workspaceFinder.js";
3
+ export declare const SUPPORTED_REPORTERS: readonly ["text", "json"];
4
+ export type ReporterType = (typeof SUPPORTED_REPORTERS)[number];
5
+ export type FindingType = "missing" | "unused-dependencies" | "unused-devDependencies" | "misplaced-devDependencies";
6
+ export interface ActiveFinding {
7
+ type: FindingType;
8
+ title: string;
9
+ items: string[];
10
+ }
11
+ export interface ReportWorkspace {
12
+ workspace: WorkspaceTarget;
13
+ result: ScanResult;
14
+ findings: ActiveFinding[];
15
+ }
16
+ export interface RenderReportInput {
17
+ targetDir: string;
18
+ reporter: ReporterType;
19
+ debug: boolean;
20
+ production: boolean;
21
+ strict: boolean;
22
+ include: FindingType[];
23
+ exclude: FindingType[];
24
+ workspaces: ReportWorkspace[];
25
+ trace?: string;
26
+ aiSummary?: string;
27
+ warnings?: string[];
28
+ configSource?: string;
29
+ rulesSummary?: {
30
+ ignorePackages: string[];
31
+ allowUnusedDependencies: string[];
32
+ allowUnusedDevDependencies: string[];
33
+ allowMissingPackages: string[];
34
+ allowMisplacedDevDependencies: string[];
35
+ };
36
+ ai?: {
37
+ provider: string;
38
+ model?: string;
39
+ };
40
+ }
41
+ export declare function renderReport(input: RenderReportInput): string;
42
+ //# sourceMappingURL=reporters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporters.d.ts","sourceRoot":"","sources":["../src/reporters.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,eAAO,MAAM,mBAAmB,2BAA4B,CAAC;AAE7D,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAChE,MAAM,MAAM,WAAW,GACnB,SAAS,GACT,qBAAqB,GACrB,wBAAwB,GACxB,2BAA2B,CAAC;AAEhC,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,eAAe,CAAC;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,YAAY,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE;QACb,cAAc,EAAE,MAAM,EAAE,CAAC;QACzB,uBAAuB,EAAE,MAAM,EAAE,CAAC;QAClC,0BAA0B,EAAE,MAAM,EAAE,CAAC;QACrC,oBAAoB,EAAE,MAAM,EAAE,CAAC;QAC/B,6BAA6B,EAAE,MAAM,EAAE,CAAC;KACzC,CAAC;IACF,EAAE,CAAC,EAAE;QACH,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAyJ7D"}