@sun-asterisk/sunlint 1.3.34 → 1.3.35

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 (90) hide show
  1. package/core/architecture-integration.js +16 -7
  2. package/core/auto-performance-manager.js +1 -1
  3. package/core/cli-action-handler.js +92 -2
  4. package/core/cli-program.js +96 -138
  5. package/core/file-targeting-service.js +62 -4
  6. package/core/git-utils.js +19 -12
  7. package/core/github-annotate-service.js +326 -11
  8. package/core/html-report-generator.js +326 -731
  9. package/core/impact-integration.js +433 -0
  10. package/core/output-service.js +293 -21
  11. package/core/scoring-service.js +3 -2
  12. package/engines/arch-detect/core/analyzer.js +413 -0
  13. package/engines/arch-detect/core/index.js +22 -0
  14. package/engines/arch-detect/engine/hybrid-detector.js +176 -0
  15. package/engines/arch-detect/engine/index.js +24 -0
  16. package/engines/arch-detect/engine/rule-executor.js +228 -0
  17. package/engines/arch-detect/engine/score-calculator.js +214 -0
  18. package/engines/arch-detect/engine/violation-detector.js +616 -0
  19. package/engines/arch-detect/index.js +50 -0
  20. package/engines/arch-detect/rules/base-rule.js +187 -0
  21. package/engines/arch-detect/rules/index.js +35 -0
  22. package/engines/arch-detect/rules/layered/index.js +28 -0
  23. package/engines/arch-detect/rules/layered/l001-presentation-layer.js +237 -0
  24. package/engines/arch-detect/rules/layered/l002-business-layer.js +215 -0
  25. package/engines/arch-detect/rules/layered/l003-data-layer.js +229 -0
  26. package/engines/arch-detect/rules/layered/l004-model-layer.js +204 -0
  27. package/engines/arch-detect/rules/layered/l005-layer-separation.js +215 -0
  28. package/engines/arch-detect/rules/layered/l006-dependency-direction.js +221 -0
  29. package/engines/arch-detect/rules/layered/layered-rules-collection.js +445 -0
  30. package/engines/arch-detect/rules/modular/index.js +27 -0
  31. package/engines/arch-detect/rules/modular/m001-feature-modules.js +238 -0
  32. package/engines/arch-detect/rules/modular/m002-core-module.js +169 -0
  33. package/engines/arch-detect/rules/modular/m003-module-declaration.js +186 -0
  34. package/engines/arch-detect/rules/modular/m004-public-api.js +171 -0
  35. package/engines/arch-detect/rules/modular/m005-no-deep-imports.js +220 -0
  36. package/engines/arch-detect/rules/modular/modular-rules-collection.js +357 -0
  37. package/engines/arch-detect/rules/presentation/index.js +27 -0
  38. package/engines/arch-detect/rules/presentation/pr001-view-layer.js +221 -0
  39. package/engines/arch-detect/rules/presentation/pr002-presentation-logic.js +192 -0
  40. package/engines/arch-detect/rules/presentation/pr004-data-binding.js +187 -0
  41. package/engines/arch-detect/rules/presentation/pr006-router-layer.js +185 -0
  42. package/engines/arch-detect/rules/presentation/pr007-interactor-layer.js +181 -0
  43. package/engines/arch-detect/rules/presentation/presentation-rules-collection.js +507 -0
  44. package/engines/arch-detect/rules/project-scanner/index.js +31 -0
  45. package/engines/arch-detect/rules/project-scanner/ps001-project-root.js +213 -0
  46. package/engines/arch-detect/rules/project-scanner/ps002-language-detection.js +192 -0
  47. package/engines/arch-detect/rules/project-scanner/ps003-framework-detection.js +339 -0
  48. package/engines/arch-detect/rules/project-scanner/ps004-build-system.js +171 -0
  49. package/engines/arch-detect/rules/project-scanner/ps005-source-directory.js +163 -0
  50. package/engines/arch-detect/rules/project-scanner/ps006-test-directory.js +184 -0
  51. package/engines/arch-detect/rules/project-scanner/ps007-documentation.js +149 -0
  52. package/engines/arch-detect/rules/project-scanner/ps008-cicd-detection.js +163 -0
  53. package/engines/arch-detect/rules/project-scanner/ps009-code-quality.js +152 -0
  54. package/engines/arch-detect/rules/project-scanner/ps010-statistics.js +180 -0
  55. package/engines/arch-detect/rules/rule-registry.js +111 -0
  56. package/engines/arch-detect/types/context.types.js +60 -0
  57. package/engines/arch-detect/types/enums.js +161 -0
  58. package/engines/arch-detect/types/index.js +25 -0
  59. package/engines/arch-detect/types/result.types.js +7 -0
  60. package/engines/arch-detect/types/rule.types.js +7 -0
  61. package/engines/arch-detect/utils/file-scanner.js +411 -0
  62. package/engines/arch-detect/utils/index.js +23 -0
  63. package/engines/arch-detect/utils/pattern-matcher.js +328 -0
  64. package/engines/impact/cli.js +106 -0
  65. package/engines/impact/config/default-config.js +54 -0
  66. package/engines/impact/core/change-detector.js +258 -0
  67. package/engines/impact/core/detectors/database-detector.js +1317 -0
  68. package/engines/impact/core/detectors/endpoint-detector.js +55 -0
  69. package/engines/impact/core/impact-analyzer.js +124 -0
  70. package/engines/impact/core/report-generator.js +462 -0
  71. package/engines/impact/core/utils/ast-parser.js +241 -0
  72. package/engines/impact/core/utils/dependency-graph.js +159 -0
  73. package/engines/impact/core/utils/file-utils.js +116 -0
  74. package/engines/impact/core/utils/git-utils.js +203 -0
  75. package/engines/impact/core/utils/logger.js +13 -0
  76. package/engines/impact/core/utils/method-call-graph.js +1192 -0
  77. package/engines/impact/index.js +135 -0
  78. package/engines/impact/package.json +29 -0
  79. package/package.json +18 -43
  80. package/scripts/build-release.sh +0 -0
  81. package/scripts/copy-impact-analyzer.js +135 -0
  82. package/scripts/install.sh +0 -0
  83. package/scripts/manual-release.sh +0 -0
  84. package/scripts/pre-release-test.sh +0 -0
  85. package/scripts/prepare-release.sh +0 -0
  86. package/scripts/quick-performance-test.js +0 -0
  87. package/scripts/setup-github-registry.sh +0 -0
  88. package/scripts/trigger-release.sh +0 -0
  89. package/scripts/verify-install.sh +0 -0
  90. package/templates/combined-report.html +1418 -0
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Impact Analyzer - Main Entry Point
5
+ * Orchestrates the entire impact analysis workflow
6
+ */
7
+
8
+ import { CLI } from './cli.js';
9
+ import { loadConfig } from './config/default-config.js';
10
+ import { ChangeDetector } from './core/change-detector.js';
11
+ import { ImpactAnalyzer } from './core/impact-analyzer.js';
12
+ import { ReportGenerator } from './core/report-generator.js';
13
+ import { GitUtils } from './core/utils/git-utils.js';
14
+ import fs from 'fs';
15
+ import path from 'path';
16
+
17
+ async function main() {
18
+ const cli = new CLI(process.argv);
19
+
20
+ // Show help if requested
21
+ if (cli.hasArg('help') || cli.hasArg('h')) {
22
+ cli.showHelp();
23
+ process.exit(0);
24
+ }
25
+
26
+ // Load configuration
27
+ const config = loadConfig(cli);
28
+ const absoluteSourceDir = path.resolve(config.sourceDir);
29
+
30
+ console.log('🚀 Starting Impact Analysis...\n');
31
+ console.log('Configuration:');
32
+ console.log(` Source Dir: ${config.sourceDir}`);
33
+ console.log(` Absolute Path: ${absoluteSourceDir}`);
34
+ console.log(` Base Ref: ${config.baseRef}`);
35
+ console.log(` Head Ref: ${config.headRef}`);
36
+ console.log(` Exclude: ${config.excludePaths.join(', ')}`);
37
+ console.log('');
38
+
39
+ try {
40
+ // ============================================
41
+ // Validation
42
+ // ============================================
43
+
44
+ // Check if source directory exists
45
+ if (! fs.existsSync(absoluteSourceDir)) {
46
+ throw new Error(`Source directory does not exist: ${absoluteSourceDir}`);
47
+ }
48
+
49
+ // Check if it's a git repository
50
+ if (!GitUtils.isGitRepo(absoluteSourceDir)) {
51
+ throw new Error(`Source directory is not a git repository: ${absoluteSourceDir}`);
52
+ }
53
+
54
+ // Check if refs exist
55
+ if (!GitUtils.refExists(config.baseRef, absoluteSourceDir)) {
56
+ throw new Error(`Base ref does not exist: ${config.baseRef}`);
57
+ }
58
+
59
+ console.log('✓ Validation passed\n');
60
+
61
+ // ============================================
62
+ // Step 1: Detect Changes
63
+ // ============================================
64
+ console.log('📝 Step 1: Detecting changes...');
65
+ const detector = new ChangeDetector(config);
66
+
67
+ const changedFiles = detector.detectChangedFiles();
68
+ console.log(` ✓ Found ${changedFiles.length} changed files`);
69
+
70
+ const changedSymbols = detector.detectChangedSymbols(changedFiles);
71
+ console.log(` ✓ Found ${changedSymbols.length} changed symbols\n`);
72
+
73
+ const changes = {
74
+ changedFiles,
75
+ changedSymbols,
76
+ };
77
+
78
+ // ============================================
79
+ // Step 2: Analyze Impact
80
+ // ============================================
81
+ console.log('🔍 Step 2: Analyzing impact...');
82
+ const analyzer = new ImpactAnalyzer(config);
83
+
84
+ // Initialize method-level call graph for precise tracking
85
+ await analyzer.initializeMethodCallGraph();
86
+
87
+ const impact = await analyzer.analyzeImpact(changes);
88
+ console.log(` ✓ Impact score: ${impact.impactScore}`);
89
+ console.log(` ✓ Severity: ${impact.severity.toUpperCase()}\n`);
90
+
91
+ // ============================================
92
+ // Step 3: Generate Reports
93
+ // ============================================
94
+ console.log('📄 Step 3: Generating reports...\n');
95
+ const reporter = new ReportGenerator();
96
+
97
+ // Console report
98
+ reporter.generateConsoleReport(changes, impact);
99
+
100
+ // Markdown report
101
+ const markdownReport = reporter.generateMarkdownReport(changes, impact);
102
+
103
+ // Save to file
104
+ const outputFile = cli.getArg('output', 'impact-report.md');
105
+ fs.writeFileSync(outputFile, markdownReport);
106
+ console.log(`✅ Report saved to: ${outputFile}\n`);
107
+
108
+ // JSON output (optional)
109
+ if (cli.hasArg('json')) {
110
+ const jsonOutput = cli.getArg('json');
111
+ const jsonReport = reporter.generateJSONReport(changes, impact);
112
+ fs.writeFileSync(jsonOutput, JSON.stringify(jsonReport, null, 2));
113
+ console.log(`✅ JSON report saved to: ${jsonOutput}\n`);
114
+ }
115
+
116
+ // Exit with code based on severity
117
+ if (impact.severity === 'critical' && ! cli.hasArg('no-fail')) {
118
+ console.log('⚠️ Critical impact detected - exiting with error code');
119
+ process.exit(1);
120
+ }
121
+
122
+ console.log('✨ Analysis completed successfully!\n');
123
+ process.exit(0);
124
+
125
+ } catch (error) {
126
+ console.error('❌ Error during analysis:', error.message);
127
+ if (cli.hasArg('verbose')) {
128
+ console.error(error.stack);
129
+ }
130
+ process.exit(1);
131
+ }
132
+ }
133
+
134
+ // Run if executed directly
135
+ main();
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@sunlint/impact-analyzer",
3
+ "version": "1.0.7",
4
+ "private": true,
5
+ "description": "Automated impact analysis for TypeScript/JavaScript projects (internal - bundled into sunlint)",
6
+ "main": "index.js",
7
+ "type": "module",
8
+ "bin": {
9
+ "impact-analyzer": "./index.js"
10
+ },
11
+ "scripts": {
12
+ "build": "echo 'No build required (pure Node.js)'",
13
+ "test": "echo 'No tests yet'",
14
+ "analyze": "node index.js"
15
+ },
16
+ "keywords": [
17
+ "impact-analysis",
18
+ "code-analysis",
19
+ "ci-cd"
20
+ ],
21
+ "author": "",
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "@babel/parser": "^7.23.0",
25
+ "@babel/traverse": "^7.23.0",
26
+ "glob": "^10.3.0",
27
+ "ts-morph": "^27.0.2"
28
+ }
29
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sun-asterisk/sunlint",
3
- "version": "1.3.34",
3
+ "version": "1.3.35",
4
4
  "description": "☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -15,46 +15,6 @@
15
15
  "registry": "https://registry.npmjs.org",
16
16
  "access": "public"
17
17
  },
18
- "scripts": {
19
- "test": "node examples/run-tests.js",
20
- "test:examples": "node examples/integration-tests/examples-integration-test.js",
21
- "test:architecture": "node examples/integration-tests/core-architecture-test.js",
22
- "test:integration": "echo 'Temporarily disabled - config extension issue'",
23
- "test:realworld": "node examples/integration-tests/realworld-integration-test.js",
24
- "test:cli": "node examples/integration-tests/direct-cli-test.js",
25
- "test:performance": "node test/performance-test.js",
26
- "test:c019": "node cli.js --rule=C019 --input=examples/test-fixtures --format=eslint",
27
- "test:c006": "node cli.js --rule=C006 --input=examples/test-fixtures --format=eslint",
28
- "test:c029": "node cli.js --rule=C029 --input=examples/test-fixtures --format=eslint",
29
- "test:multi": "node cli.js --rules=C019,C006,C029 --input=examples/test-fixtures --format=eslint",
30
- "test:all": "node cli.js --all --input=examples/test-fixtures --format=eslint",
31
- "test:quality": "node cli.js --category=quality --input=examples/test-fixtures --format=eslint",
32
- "test:security": "node cli.js --category=security --input=examples/test-fixtures --format=eslint",
33
- "demo": "./demo.sh",
34
- "demo:single": "node cli.js --rule=C019 --input=examples/test-fixtures/typescript --format=eslint",
35
- "demo:multi": "node cli.js --rules=C019,C006 --input=test/fixtures --format=summary",
36
- "demo:quality": "node cli.js --quality --input=test/fixtures --format=summary",
37
- "demo:security": "node cli.js --security --input=test/fixtures --format=summary",
38
- "demo:all": "node cli.js --all --input=test/fixtures --format=summary",
39
- "demo:config": "node cli.js --config=.sunlint.json --input=test/fixtures",
40
- "demo:eslint-integration": "./demo-eslint-integration.sh",
41
- "demo:file-targeting": "./demo-file-targeting.sh",
42
- "lint": "node cli.js --config=.sunlint.json --input=.",
43
- "lint:eslint-integration": "node cli.js --all --eslint-integration --input=.",
44
- "build": "npm run copy-rules && npm run generate-registry && npm run copy-arch-detect && echo 'Build completed'",
45
- "copy-rules": "node scripts/copy-rules.js",
46
- "generate-registry": "node scripts/generate-rules-registry.js",
47
- "copy-arch-detect": "node scripts/copy-arch-detect.js",
48
- "clean": "rm -rf coverage/ *.log reports/ *.tgz engines/arch-detect",
49
- "postpack": "echo '📦 Package created successfully! Size: ' && ls -lh *.tgz | awk '{print $5}'",
50
- "start": "node cli.js --help",
51
- "version": "node cli.js --version",
52
- "pack": "npm run build && npm pack",
53
- "publish:github": "npm publish --registry=https://npm.pkg.github.com",
54
- "publish:npmjs": "npm publish --registry=https://registry.npmjs.org",
55
- "publish:test": "npm publish --dry-run --registry=https://registry.npmjs.org",
56
- "prepublishOnly": "npm run clean && npm run build"
57
- },
58
18
  "keywords": [
59
19
  "linting",
60
20
  "code-quality",
@@ -79,6 +39,7 @@
79
39
  "integrations/",
80
40
  "rules/",
81
41
  "scripts/",
42
+ "templates/",
82
43
  "docs/",
83
44
  ".sunlint.json",
84
45
  "README.md",
@@ -139,5 +100,19 @@
139
100
  "bugs": {
140
101
  "url": "https://github.com/sun-asterisk/engineer-excellence/issues"
141
102
  },
142
- "homepage": "https://github.com/sun-asterisk/engineer-excellence/tree/main/coding-quality/extensions/sunlint#readme"
143
- }
103
+ "homepage": "https://github.com/sun-asterisk/engineer-excellence/tree/main/coding-quality/extensions/sunlint#readme",
104
+ "scripts": {
105
+ "test": "node examples/run-tests.js",
106
+ "test:perf": "node test/performance-test.js",
107
+ "lint": "node cli.js --all --input=. --format=summary",
108
+ "build": "pnpm run copy-rules && pnpm run generate-registry && pnpm run copy-arch-detect && pnpm run copy-impact",
109
+ "copy-rules": "node scripts/copy-rules.js",
110
+ "generate-registry": "node scripts/generate-rules-registry.js",
111
+ "copy-arch-detect": "node scripts/copy-arch-detect.js",
112
+ "copy-impact": "node scripts/copy-impact-analyzer.js",
113
+ "clean": "rm -rf coverage/ *.log reports/ *.tgz engines/arch-detect engines/impact",
114
+ "pack": "pnpm run build && pnpm pack",
115
+ "publish:npmjs": "pnpm publish --registry=https://registry.npmjs.org --no-git-checks",
116
+ "publish:test": "pnpm publish --dry-run --registry=https://registry.npmjs.org --no-git-checks"
117
+ }
118
+ }
File without changes
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Copy impact-analyzer to engines/impact
3
+ * This script is run during build to bundle impact analysis functionality
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const SOURCE = path.resolve(__dirname, '../../../../impact-analyzer');
10
+ const DEST = path.resolve(__dirname, '../engines/impact');
11
+
12
+ // Files to copy from impact-analyzer
13
+ const FILES_TO_COPY = [
14
+ 'index.js',
15
+ 'cli.js',
16
+ 'core',
17
+ 'config',
18
+ 'package.json'
19
+ ];
20
+
21
+ // Files/folders to skip
22
+ const SKIP_PATTERNS = [
23
+ 'node_modules',
24
+ '.git',
25
+ 'test',
26
+ 'tests',
27
+ '.DS_Store'
28
+ ];
29
+
30
+ function copyDir(src, dest) {
31
+ if (!fs.existsSync(src)) {
32
+ console.log('⚠️ Directory not found:', src);
33
+ return false;
34
+ }
35
+
36
+ if (!fs.existsSync(dest)) {
37
+ fs.mkdirSync(dest, { recursive: true });
38
+ }
39
+
40
+ const entries = fs.readdirSync(src, { withFileTypes: true });
41
+
42
+ for (const entry of entries) {
43
+ if (SKIP_PATTERNS.includes(entry.name)) {
44
+ continue;
45
+ }
46
+
47
+ const srcPath = path.join(src, entry.name);
48
+ const destPath = path.join(dest, entry.name);
49
+
50
+ if (entry.isDirectory()) {
51
+ copyDir(srcPath, destPath);
52
+ } else {
53
+ fs.copyFileSync(srcPath, destPath);
54
+ }
55
+ }
56
+
57
+ return true;
58
+ }
59
+
60
+ function copyFile(src, dest) {
61
+ if (!fs.existsSync(src)) {
62
+ console.log('⚠️ File not found:', src);
63
+ return false;
64
+ }
65
+
66
+ const destDir = path.dirname(dest);
67
+ if (!fs.existsSync(destDir)) {
68
+ fs.mkdirSync(destDir, { recursive: true });
69
+ }
70
+
71
+ fs.copyFileSync(src, dest);
72
+ return true;
73
+ }
74
+
75
+ console.log('📦 Copying impact-analyzer...');
76
+
77
+ if (!fs.existsSync(SOURCE)) {
78
+ console.log('⚠️ impact-analyzer not found. Skipping.');
79
+ process.exit(0);
80
+ }
81
+
82
+ // Clean destination
83
+ if (fs.existsSync(DEST)) {
84
+ fs.rmSync(DEST, { recursive: true });
85
+ }
86
+ fs.mkdirSync(DEST, { recursive: true });
87
+
88
+ let success = true;
89
+
90
+ for (const item of FILES_TO_COPY) {
91
+ const srcPath = path.join(SOURCE, item);
92
+ const destPath = path.join(DEST, item);
93
+
94
+ if (fs.existsSync(srcPath)) {
95
+ const stat = fs.statSync(srcPath);
96
+ if (stat.isDirectory()) {
97
+ if (!copyDir(srcPath, destPath)) {
98
+ success = false;
99
+ }
100
+ } else {
101
+ if (!copyFile(srcPath, destPath)) {
102
+ success = false;
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ if (success) {
109
+ const size = getTotalSize(DEST);
110
+ console.log(`✅ Copied to engines/impact (${formatSize(size)})`);
111
+ } else {
112
+ console.log('⚠️ Some files could not be copied');
113
+ }
114
+
115
+ function getTotalSize(dir) {
116
+ let size = 0;
117
+ if (!fs.existsSync(dir)) return size;
118
+
119
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
120
+ for (const entry of entries) {
121
+ const fullPath = path.join(dir, entry.name);
122
+ if (entry.isDirectory()) {
123
+ size += getTotalSize(fullPath);
124
+ } else {
125
+ size += fs.statSync(fullPath).size;
126
+ }
127
+ }
128
+ return size;
129
+ }
130
+
131
+ function formatSize(bytes) {
132
+ if (bytes < 1024) return bytes + ' B';
133
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
134
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
135
+ }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes