@sun-asterisk/sunlint 1.0.7 → 1.1.4
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/.sunlint.json +35 -0
- package/CHANGELOG.md +30 -3
- package/CONTRIBUTING.md +235 -0
- package/PROJECT_STRUCTURE.md +60 -0
- package/README.md +146 -58
- package/cli.js +1 -0
- package/config/README.md +88 -0
- package/config/defaults/ai-rules-context.json +231 -0
- package/config/engines/engines.json +49 -0
- package/config/engines/eslint-rule-mapping.json +74 -0
- package/config/eslint-rule-mapping.json +126 -0
- package/config/integrations/eslint/base.config.js +125 -0
- package/config/integrations/eslint/simple.config.js +24 -0
- package/config/presets/strict.json +0 -1
- package/config/rule-analysis-strategies.js +74 -0
- package/config/{rules-registry.json → rules/rules-registry.json} +30 -7
- package/core/analysis-orchestrator.js +383 -591
- package/core/ast-modules/README.md +103 -0
- package/core/ast-modules/base-parser.js +90 -0
- package/core/ast-modules/index.js +97 -0
- package/core/ast-modules/package.json +37 -0
- package/core/ast-modules/parsers/eslint-js-parser.js +153 -0
- package/core/ast-modules/parsers/eslint-ts-parser.js +98 -0
- package/core/ast-modules/parsers/javascript-parser.js +187 -0
- package/core/ast-modules/parsers/typescript-parser.js +187 -0
- package/core/cli-action-handler.js +271 -255
- package/core/cli-program.js +18 -4
- package/core/config-manager.js +9 -3
- package/core/config-merger.js +40 -1
- package/core/config-validator.js +2 -2
- package/core/dependency-checker.js +125 -0
- package/core/enhanced-rules-registry.js +331 -0
- package/core/file-targeting-service.js +92 -23
- package/core/interfaces/analysis-engine.interface.js +100 -0
- package/core/multi-rule-runner.js +0 -221
- package/core/output-service.js +1 -1
- package/core/rule-mapping-service.js +1 -1
- package/core/rule-selection-service.js +10 -2
- package/core/smart-installer.js +164 -0
- package/docs/AI.md +163 -0
- package/docs/ARCHITECTURE.md +78 -0
- package/docs/CI-CD-GUIDE.md +315 -0
- package/docs/COMMAND-EXAMPLES.md +256 -0
- package/docs/CONFIGURATION.md +414 -0
- package/docs/DEBUG.md +86 -0
- package/docs/DEPENDENCIES.md +90 -0
- package/docs/DEPLOYMENT-STRATEGIES.md +270 -0
- package/docs/DISTRIBUTION.md +153 -0
- package/docs/ESLINT-INTEGRATION-STRATEGY.md +392 -0
- package/docs/ESLINT_INTEGRATION.md +238 -0
- package/docs/FOLDER_STRUCTURE.md +59 -0
- package/docs/FUTURE_PACKAGES.md +83 -0
- package/docs/HEURISTIC_VS_AI.md +113 -0
- package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +112 -0
- package/docs/PRODUCTION_SIZE_IMPACT.md +183 -0
- package/docs/README.md +32 -0
- package/docs/RELEASE_GUIDE.md +230 -0
- package/engines/eslint-engine.js +610 -0
- package/engines/heuristic-engine.js +864 -0
- package/engines/openai-engine.js +374 -0
- package/engines/tree-sitter-parser.js +0 -0
- package/engines/universal-ast-engine.js +0 -0
- package/integrations/eslint/README.md +99 -0
- package/integrations/eslint/configs/.eslintrc.js +98 -0
- package/integrations/eslint/configs/eslint.config.js +133 -0
- package/integrations/eslint/configs/eslint.config.simple.js +24 -0
- package/integrations/eslint/package.json +23 -0
- package/integrations/eslint/plugin/index.js +164 -0
- package/integrations/eslint/plugin/package.json +13 -0
- package/integrations/eslint/plugin/rules/common/c002-no-duplicate-code.js +204 -0
- package/integrations/eslint/plugin/rules/common/c003-no-vague-abbreviations.js +246 -0
- package/integrations/eslint/plugin/rules/common/c006-function-name-verb-noun.js +216 -0
- package/integrations/eslint/plugin/rules/common/c010-limit-block-nesting.js +90 -0
- package/integrations/eslint/plugin/rules/common/c013-no-dead-code.js +78 -0
- package/integrations/eslint/plugin/rules/common/c014-abstract-dependency-preferred.js +38 -0
- package/integrations/eslint/plugin/rules/common/c017-limit-constructor-logic.js +146 -0
- package/integrations/eslint/plugin/rules/common/c018-no-generic-throw.js +335 -0
- package/integrations/eslint/plugin/rules/common/c023-no-duplicate-variable-name-in-scope.js +142 -0
- package/integrations/eslint/plugin/rules/common/c029-catch-block-logging.js +115 -0
- package/integrations/eslint/plugin/rules/common/c030-use-custom-error-classes.js +294 -0
- package/integrations/eslint/plugin/rules/common/c035-no-empty-catch.js +162 -0
- package/integrations/eslint/plugin/rules/common/c041-no-config-inline.js +122 -0
- package/integrations/eslint/plugin/rules/common/c042-boolean-name-prefix.js +406 -0
- package/integrations/eslint/plugin/rules/common/c043-no-console-or-print.js +300 -0
- package/integrations/eslint/plugin/rules/common/c047-no-duplicate-retry-logic.js +239 -0
- package/integrations/eslint/plugin/rules/common/c072-one-assert-per-test.js +184 -0
- package/integrations/eslint/plugin/rules/common/c075-explicit-function-return-types.js +168 -0
- package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +254 -0
- package/integrations/eslint/plugin/rules/security/s001-fail-securely.js +381 -0
- package/integrations/eslint/plugin/rules/security/s002-idor-check.js +945 -0
- package/integrations/eslint/plugin/rules/security/s003-no-unvalidated-redirect.js +86 -0
- package/integrations/eslint/plugin/rules/security/s007-no-plaintext-otp.js +74 -0
- package/integrations/eslint/plugin/rules/security/s013-verify-tls-connection.js +47 -0
- package/integrations/eslint/plugin/rules/security/s047-secure-random-passwords.js +108 -0
- package/integrations/eslint/plugin/rules/security/s055-verification-rest-check-the-incoming-content-type.js +143 -0
- package/integrations/eslint/plugin/rules/typescript/t002-interface-prefix-i.js +42 -0
- package/integrations/eslint/plugin/rules/typescript/t003-ts-ignore-reason.js +48 -0
- package/integrations/eslint/plugin/rules/typescript/t004-no-empty-type.js +95 -0
- package/integrations/eslint/plugin/rules/typescript/t007-no-fn-in-constructor.js +52 -0
- package/integrations/eslint/plugin/rules/typescript/t010-no-nested-union-tuple.js +48 -0
- package/integrations/eslint/plugin/rules/typescript/t019-no-this-assign.js +81 -0
- package/integrations/eslint/plugin/rules/typescript/t020-no-default-multi-export.js +127 -0
- package/integrations/eslint/plugin/rules/typescript/t021-limit-nested-generics.js +150 -0
- package/integrations/eslint/tsconfig.json +27 -0
- package/package.json +61 -21
- package/rules/README.md +252 -0
- package/rules/common/C002_no_duplicate_code/analyzer.js +65 -0
- package/rules/common/C002_no_duplicate_code/config.json +23 -0
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +418 -0
- package/rules/common/C003_no_vague_abbreviations/config.json +35 -0
- package/rules/{C006_function_naming → common/C006_function_naming}/analyzer.js +13 -2
- package/rules/common/C010_limit_block_nesting/analyzer.js +389 -0
- package/rules/common/C013_no_dead_code/analyzer.js +206 -0
- package/rules/common/C014_dependency_injection/analyzer.js +338 -0
- package/rules/common/C017_constructor_logic/analyzer.js +314 -0
- package/rules/{C019_log_level_usage → common/C019_log_level_usage}/analyzer.js +5 -2
- package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/analyzer.js +49 -15
- package/rules/common/C041_no_sensitive_hardcode/analyzer.js +292 -0
- package/rules/common/C042_boolean_name_prefix/analyzer.js +300 -0
- package/rules/common/C043_no_console_or_print/analyzer.js +304 -0
- package/rules/common/C047_no_duplicate_retry_logic/analyzer.js +351 -0
- package/rules/common/C075_explicit_return_types/analyzer.js +103 -0
- package/rules/common/C076_single_test_behavior/analyzer.js +121 -0
- package/rules/docs/C002_no_duplicate_code.md +57 -0
- package/rules/index.js +149 -0
- package/rules/migration/converter.js +385 -0
- package/rules/migration/mapping.json +164 -0
- package/rules/security/S026_json_schema_validation/analyzer.js +251 -0
- package/rules/security/S026_json_schema_validation/config.json +27 -0
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +263 -0
- package/rules/security/S027_no_hardcoded_secrets/config.json +29 -0
- package/rules/security/S029_csrf_protection/analyzer.js +264 -0
- package/rules/tests/C002_no_duplicate_code.test.js +50 -0
- package/rules/universal/C010/generic.js +0 -0
- package/rules/universal/C010/tree-sitter-analyzer.js +0 -0
- package/rules/utils/ast-utils.js +191 -0
- package/rules/utils/base-analyzer.js +98 -0
- package/rules/utils/pattern-matchers.js +239 -0
- package/rules/utils/rule-helpers.js +264 -0
- package/rules/utils/severity-constants.js +93 -0
- package/scripts/build-release.sh +117 -0
- package/scripts/ci-report.js +179 -0
- package/scripts/install.sh +196 -0
- package/scripts/manual-release.sh +338 -0
- package/scripts/merge-reports.js +424 -0
- package/scripts/pre-release-test.sh +175 -0
- package/scripts/prepare-release.sh +202 -0
- package/scripts/setup-github-registry.sh +42 -0
- package/scripts/test-scripts/README.md +22 -0
- package/scripts/test-scripts/test-c041-comparison.js +114 -0
- package/scripts/test-scripts/test-c041-eslint.js +67 -0
- package/scripts/test-scripts/test-eslint-rules.js +146 -0
- package/scripts/test-scripts/test-real-world.js +44 -0
- package/scripts/test-scripts/test-rules-on-real-projects.js +86 -0
- package/scripts/trigger-release.sh +285 -0
- package/scripts/validate-rule-structure.js +148 -0
- package/scripts/verify-install.sh +82 -0
- package/config/sunlint-schema.json +0 -159
- package/config/typescript/custom-rules.js +0 -9
- package/config/typescript/package-lock.json +0 -1585
- package/config/typescript/package.json +0 -13
- package/config/typescript/security-rules/index.js +0 -90
- package/config/typescript/tsconfig.json +0 -29
- package/core/ai-analyzer.js +0 -169
- package/core/eslint-engine-service.js +0 -312
- package/core/eslint-instance-manager.js +0 -104
- package/core/eslint-integration-service.js +0 -363
- package/core/sunlint-engine-service.js +0 -23
- package/core/typescript-analyzer.js +0 -262
- package/core/typescript-engine.js +0 -313
- /package/config/{default.json → defaults/default.json} +0 -0
- /package/config/{typescript/eslint.config.js → integrations/eslint/typescript.config.js} +0 -0
- /package/config/{typescript/custom-rules-new.js → schemas/sunlint-schema.json} +0 -0
- /package/config/{typescript → testing}/test-s005-working.ts +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s005-no-origin-auth.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s006-activation-recovery-secret-not-plaintext.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s008-crypto-agility.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s009-no-insecure-crypto.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s010-no-insecure-random-in-sensitive-context.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s011-no-insecure-uuid.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s012-hardcode-secret.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s014-insecure-tls-version.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s015-insecure-tls-certificate.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s016-sensitive-query-parameter.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s017-no-sql-injection.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s018-positive-input-validation.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s019-no-raw-user-input-in-email.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s020-no-eval-dynamic-execution.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s022-output-encoding.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s023-no-json-injection.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s025-server-side-input-validation.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s026-json-schema-validation.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s027-no-hardcoded-secrets.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s029-require-csrf-protection.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s030-no-directory-browsing.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s033-require-samesite-cookie.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s034-require-host-cookie-prefix.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s035-cookie-specific-path.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s036-no-unsafe-file-include.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s037-require-anti-cache-headers.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s038-no-version-disclosure.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s039-no-session-token-in-url.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s041-require-session-invalidate-on-logout.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s042-require-periodic-reauthentication.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s043-terminate-sessions-on-password-change.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s044-require-full-session-for-sensitive-operations.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s045-anti-automation-controls.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s046-secure-notification-on-auth-change.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s048-password-credential-recovery.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s050-session-token-weak-hash.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s052-secure-random-authentication-code.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s054-verification-default-account.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s057-utc-logging.js +0 -0
- /package/{config/typescript/security-rules → integrations/eslint/plugin/rules/security}/s058-no-ssrf.js +0 -0
- /package/rules/{C006_function_naming → common/C006_function_naming}/config.json +0 -0
- /package/rules/{C019_log_level_usage → common/C019_log_level_usage}/config.json +0 -0
- /package/rules/{C029_catch_block_logging → common/C029_catch_block_logging}/config.json +0 -0
- /package/rules/{C031_validation_separation → common/C031_validation_separation}/analyzer.js +0 -0
- /package/rules/{C031_validation_separation/README.md → docs/C031_validation_separation.md} +0 -0
package/docs/DEBUG.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# 🐛 Debugging Sunlint
|
|
2
|
+
|
|
3
|
+
## Quick Start
|
|
4
|
+
|
|
5
|
+
### Debug Configurations Available
|
|
6
|
+
|
|
7
|
+
1. **Debug Sunlint CLI** - Debug the main CLI with quality rules
|
|
8
|
+
2. **Debug Sunlint - Single Rule** - Debug a specific rule (C006)
|
|
9
|
+
3. **Debug Sunlint - Multiple Rules** - Debug multiple rules with JSON output
|
|
10
|
+
4. **Debug Sunlint - Custom Input** - Debug with custom input path and format
|
|
11
|
+
5. **Debug Rule Analyzer - C006** - Debug the function naming analyzer
|
|
12
|
+
6. **Debug Rule Analyzer - C019** - Debug the log level analyzer
|
|
13
|
+
7. **Debug Rule Analyzer - C029** - Debug the catch block analyzer
|
|
14
|
+
|
|
15
|
+
### How to Debug
|
|
16
|
+
|
|
17
|
+
1. **Open VS Code** in the sunlint folder
|
|
18
|
+
2. **Press F5** or go to `Run and Debug` panel
|
|
19
|
+
3. **Select a configuration** from the dropdown
|
|
20
|
+
4. **Click Start Debugging** (green play button)
|
|
21
|
+
|
|
22
|
+
### Tasks Available
|
|
23
|
+
|
|
24
|
+
- **Sunlint: Run Quality Check** - Run quality analysis (Ctrl+Shift+P → Tasks: Run Task)
|
|
25
|
+
- **Sunlint: Run Single Rule** - Run a specific rule
|
|
26
|
+
- **Sunlint: Run All Rules** - Run all rules with JSON output
|
|
27
|
+
- **Sunlint: Demo Script** - Run the demo script
|
|
28
|
+
- **Sunlint: Install Dependencies** - Install npm dependencies
|
|
29
|
+
- **Sunlint: Validate Registry** - Validate the rules registry
|
|
30
|
+
|
|
31
|
+
### Breakpoints
|
|
32
|
+
|
|
33
|
+
Set breakpoints in:
|
|
34
|
+
- **cli.js** - Main CLI logic
|
|
35
|
+
- **core/multi-rule-runner.js** - Rule execution
|
|
36
|
+
- **core/config-manager.js** - Configuration loading
|
|
37
|
+
- **core/report-generator.js** - Report generation
|
|
38
|
+
- **rules/*/analyzer.js** - Individual rule analyzers
|
|
39
|
+
|
|
40
|
+
### Debug Environment
|
|
41
|
+
|
|
42
|
+
- **NODE_ENV** is set to `development`
|
|
43
|
+
- **Console** output goes to integrated terminal
|
|
44
|
+
- **Skip Files** configured to ignore Node.js internals
|
|
45
|
+
- **Problem Matcher** configured to parse sunlint output
|
|
46
|
+
|
|
47
|
+
### Configuration Files
|
|
48
|
+
|
|
49
|
+
- **launch.json** - Debug configurations
|
|
50
|
+
- **tasks.json** - Build and test tasks
|
|
51
|
+
- **settings.json** - VS Code workspace settings
|
|
52
|
+
- **extensions.json** - Recommended extensions
|
|
53
|
+
- **sunlint-schema.json** - JSON schema for .sunlint.json files
|
|
54
|
+
|
|
55
|
+
### Tips
|
|
56
|
+
|
|
57
|
+
1. **Use breakpoints** in analyzer files to debug rule logic
|
|
58
|
+
2. **Check Variables panel** to inspect rule results
|
|
59
|
+
3. **Use Debug Console** to test expressions
|
|
60
|
+
4. **Watch expressions** for complex debugging
|
|
61
|
+
5. **Step through code** to understand execution flow
|
|
62
|
+
|
|
63
|
+
### Common Debug Scenarios
|
|
64
|
+
|
|
65
|
+
#### Debug Rule Not Working
|
|
66
|
+
1. Set breakpoint in rule analyzer
|
|
67
|
+
2. Use "Debug Rule Analyzer - C006" configuration
|
|
68
|
+
3. Check if rule is properly detecting violations
|
|
69
|
+
|
|
70
|
+
#### Debug CLI Arguments
|
|
71
|
+
1. Set breakpoint in cli.js
|
|
72
|
+
2. Use "Debug Sunlint CLI" configuration
|
|
73
|
+
3. Check if arguments are parsed correctly
|
|
74
|
+
|
|
75
|
+
#### Debug Report Generation
|
|
76
|
+
1. Set breakpoint in report-generator.js
|
|
77
|
+
2. Use any CLI debug configuration
|
|
78
|
+
3. Check if violations are formatted correctly
|
|
79
|
+
|
|
80
|
+
### JSON Schema Support
|
|
81
|
+
|
|
82
|
+
The workspace includes JSON schema for `.sunlint.json` files, providing:
|
|
83
|
+
- **IntelliSense** for configuration options
|
|
84
|
+
- **Validation** of configuration values
|
|
85
|
+
- **Hover documentation** for properties
|
|
86
|
+
- **Auto-completion** for rule IDs and values
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Installing SunLint Dependencies
|
|
2
|
+
|
|
3
|
+
SunLint is designed to work immediately after installation with built-in JavaScript/TypeScript analysis capabilities. Additional dependencies are only needed for enhanced features.
|
|
4
|
+
|
|
5
|
+
## Core Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @sun-asterisk/sunlint --save-dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**✅ What you get immediately:**
|
|
12
|
+
- High-accuracy JavaScript analysis (AST-based)
|
|
13
|
+
- Basic TypeScript analysis (Babel parser)
|
|
14
|
+
- All 97+ quality and security rules
|
|
15
|
+
- Heuristic analysis for all supported languages
|
|
16
|
+
|
|
17
|
+
## Enhanced Features
|
|
18
|
+
|
|
19
|
+
### For ESLint Integration
|
|
20
|
+
|
|
21
|
+
If you want to combine SunLint with ESLint rules and ecosystem:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install eslint --save-dev
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### For Advanced TypeScript Analysis
|
|
28
|
+
|
|
29
|
+
For enhanced TypeScript parsing and ESLint TypeScript rules:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser --save-dev
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### For TypeScript Projects (Complete Setup)
|
|
36
|
+
|
|
37
|
+
For full TypeScript development support:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm install eslint typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser --save-dev
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Installation Examples
|
|
44
|
+
|
|
45
|
+
### Minimal Setup (JavaScript projects)
|
|
46
|
+
```bash
|
|
47
|
+
npm install @sun-asterisk/sunlint --save-dev
|
|
48
|
+
npx sunlint --all --input=src # ✅ Works immediately
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### TypeScript Projects
|
|
52
|
+
```bash
|
|
53
|
+
npm install @sun-asterisk/sunlint eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin typescript --save-dev
|
|
54
|
+
npx sunlint --all --input=src # ✅ Full TypeScript support
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### ESLint Integration
|
|
58
|
+
```bash
|
|
59
|
+
npm install @sun-asterisk/sunlint eslint --save-dev
|
|
60
|
+
npx sunlint --all --eslint-integration --input=src # ✅ Combined analysis
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## What happens without optional dependencies?
|
|
64
|
+
|
|
65
|
+
- **Without ESLint**: SunLint uses heuristic engine only (still very capable)
|
|
66
|
+
- **Without TypeScript parsers**: Falls back to Babel parser (good coverage)
|
|
67
|
+
- **Without TypeScript compiler**: Basic type checking only
|
|
68
|
+
|
|
69
|
+
**SunLint always provides analysis results** - dependencies only enhance capabilities.
|
|
70
|
+
|
|
71
|
+
## Built-in vs Optional Parsers
|
|
72
|
+
|
|
73
|
+
### ✅ Built-in (Always Available)
|
|
74
|
+
- **@babel/parser**: JavaScript + basic TypeScript support
|
|
75
|
+
- **espree**: ECMAScript parsing for compatibility
|
|
76
|
+
|
|
77
|
+
### 🔄 Optional (Install as needed)
|
|
78
|
+
- **@typescript-eslint/parser**: Advanced TypeScript features
|
|
79
|
+
- **@typescript-eslint/eslint-plugin**: TypeScript-specific rules
|
|
80
|
+
- **eslint**: ESLint engine integration
|
|
81
|
+
- **typescript**: TypeScript compiler integration
|
|
82
|
+
|
|
83
|
+
## Dependency Check
|
|
84
|
+
|
|
85
|
+
Run any SunLint command to see recommendations for your project:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx sunlint --help
|
|
89
|
+
# Automatically detects project type and suggests relevant dependencies
|
|
90
|
+
```
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# SunLint Deployment Strategies
|
|
2
|
+
|
|
3
|
+
This document outlines different deployment strategies for SunLint, demonstrating the modular approach that allows selective inclusion/exclusion of features.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
SunLint supports flexible deployment strategies through its modular architecture:
|
|
8
|
+
|
|
9
|
+
- **Core Features**: Always included (heuristic regex, ESLint integration)
|
|
10
|
+
- **AST Enhancement**: Optional Tree-sitter modules for improved accuracy
|
|
11
|
+
- **Language-Specific**: Can include/exclude language-specific parsers
|
|
12
|
+
- **AI Features**: Optional OpenAI integration
|
|
13
|
+
|
|
14
|
+
## Deployment Strategies
|
|
15
|
+
|
|
16
|
+
### 1. Full Distribution (Development/Enterprise)
|
|
17
|
+
|
|
18
|
+
**Target**: Development teams, enterprise installations
|
|
19
|
+
**Size**: Large (~50MB+ with all AST parsers)
|
|
20
|
+
**Accuracy**: Highest
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Include everything
|
|
24
|
+
npm install sunlint
|
|
25
|
+
|
|
26
|
+
# Available engines: eslint, heuristic (with AST), openai
|
|
27
|
+
sunlint --rule=C010 --engine=heuristic src/
|
|
28
|
+
# Uses AST when available, falls back to regex
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Files Included**:
|
|
32
|
+
```
|
|
33
|
+
sunlint/
|
|
34
|
+
├── engines/
|
|
35
|
+
│ ├── eslint-engine.js ✅ ESLint integration
|
|
36
|
+
│ ├── heuristic-engine.js ✅ Enhanced with AST
|
|
37
|
+
│ └── openai-engine.js ✅ AI-powered analysis
|
|
38
|
+
├── core/ast-modules/ ✅ Full AST support
|
|
39
|
+
│ ├── parsers/
|
|
40
|
+
│ │ ├── javascript-parser.js ✅ JS AST
|
|
41
|
+
│ │ ├── typescript-parser.js ✅ TS AST
|
|
42
|
+
│ │ ├── dart-parser.js ✅ Dart AST
|
|
43
|
+
│ │ ├── java-parser.js ✅ Java AST
|
|
44
|
+
│ │ └── ... ✅ All languages
|
|
45
|
+
│ └── package.json ✅ Tree-sitter deps
|
|
46
|
+
└── ...
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. TypeScript-Only Distribution
|
|
50
|
+
|
|
51
|
+
**Target**: TypeScript-only projects, Next.js, React
|
|
52
|
+
**Size**: Medium (~15MB)
|
|
53
|
+
**Accuracy**: High for TS/JS, regex for others
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Build script for TypeScript distribution
|
|
57
|
+
npm run build:typescript
|
|
58
|
+
|
|
59
|
+
# Available engines: eslint, heuristic (TS/JS AST only)
|
|
60
|
+
sunlint --rule=C010 --engine=heuristic src/
|
|
61
|
+
# Uses AST for .ts/.js files, regex for others
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Build Process**:
|
|
65
|
+
```bash
|
|
66
|
+
#!/bin/bash
|
|
67
|
+
# build-typescript.sh
|
|
68
|
+
|
|
69
|
+
# Copy base files
|
|
70
|
+
cp -r engines/ dist/
|
|
71
|
+
cp -r rules/ dist/
|
|
72
|
+
cp -r core/ dist/
|
|
73
|
+
|
|
74
|
+
# Keep only TypeScript/JavaScript AST parsers
|
|
75
|
+
mkdir -p dist/core/ast-modules/parsers/
|
|
76
|
+
cp core/ast-modules/index.js dist/core/ast-modules/
|
|
77
|
+
cp core/ast-modules/base-parser.js dist/core/ast-modules/
|
|
78
|
+
cp core/ast-modules/parsers/javascript-parser.js dist/core/ast-modules/parsers/
|
|
79
|
+
cp core/ast-modules/parsers/typescript-parser.js dist/core/ast-modules/parsers/
|
|
80
|
+
|
|
81
|
+
# Update package.json to include only JS/TS Tree-sitter deps
|
|
82
|
+
cat > dist/core/ast-modules/package.json << 'EOF'
|
|
83
|
+
{
|
|
84
|
+
"name": "@sunlint/ast-typescript",
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"tree-sitter": "^0.20.0",
|
|
87
|
+
"tree-sitter-javascript": "^0.20.0",
|
|
88
|
+
"tree-sitter-typescript": "^0.20.0"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
EOF
|
|
92
|
+
|
|
93
|
+
# Remove OpenAI engine for smaller bundle
|
|
94
|
+
rm dist/engines/openai-engine.js
|
|
95
|
+
|
|
96
|
+
npm pack dist/
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Minimal Distribution (Regex-Only)
|
|
100
|
+
|
|
101
|
+
**Target**: CI/CD, embedded systems, minimal installs
|
|
102
|
+
**Size**: Small (~2MB)
|
|
103
|
+
**Accuracy**: Basic regex patterns only
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Build script for minimal distribution
|
|
107
|
+
npm run build:minimal
|
|
108
|
+
|
|
109
|
+
# Available engines: eslint, heuristic (regex-only)
|
|
110
|
+
sunlint --rule=C010 --engine=heuristic src/
|
|
111
|
+
# Uses only regex patterns, no AST enhancement
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Build Process**:
|
|
115
|
+
```bash
|
|
116
|
+
#!/bin/bash
|
|
117
|
+
# build-minimal.sh
|
|
118
|
+
|
|
119
|
+
# Copy only essential files
|
|
120
|
+
cp -r engines/ dist/
|
|
121
|
+
cp -r rules/ dist/
|
|
122
|
+
cp -r core/ dist/
|
|
123
|
+
|
|
124
|
+
# Remove entire AST modules directory
|
|
125
|
+
rm -rf dist/core/ast-modules/
|
|
126
|
+
|
|
127
|
+
# Remove OpenAI engine
|
|
128
|
+
rm dist/engines/openai-engine.js
|
|
129
|
+
|
|
130
|
+
# Update heuristic engine to not reference AST modules
|
|
131
|
+
sed -i 's/const ASTModuleRegistry = require.*//g' dist/engines/heuristic-engine.js
|
|
132
|
+
sed -i 's/this.astRegistry = ASTModuleRegistry;//g' dist/engines/heuristic-engine.js
|
|
133
|
+
|
|
134
|
+
npm pack dist/
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 4. Language-Specific Distributions
|
|
138
|
+
|
|
139
|
+
**Example: Java-Only Distribution**
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
#!/bin/bash
|
|
143
|
+
# build-java.sh
|
|
144
|
+
|
|
145
|
+
# Base files
|
|
146
|
+
cp -r engines/ dist/
|
|
147
|
+
cp -r rules/ dist/
|
|
148
|
+
cp -r core/ dist/
|
|
149
|
+
|
|
150
|
+
# Keep only Java AST parser
|
|
151
|
+
mkdir -p dist/core/ast-modules/parsers/
|
|
152
|
+
cp core/ast-modules/index.js dist/core/ast-modules/
|
|
153
|
+
cp core/ast-modules/base-parser.js dist/core/ast-modules/
|
|
154
|
+
cp core/ast-modules/parsers/java-parser.js dist/core/ast-modules/parsers/
|
|
155
|
+
|
|
156
|
+
# Java-specific package.json
|
|
157
|
+
cat > dist/core/ast-modules/package.json << 'EOF'
|
|
158
|
+
{
|
|
159
|
+
"name": "@sunlint/ast-java",
|
|
160
|
+
"dependencies": {
|
|
161
|
+
"tree-sitter": "^0.20.0",
|
|
162
|
+
"tree-sitter-java": "^0.20.0"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
EOF
|
|
166
|
+
|
|
167
|
+
# Remove ESLint engine (Java doesn't need it)
|
|
168
|
+
rm dist/engines/eslint-engine.js
|
|
169
|
+
|
|
170
|
+
# Update engine registry
|
|
171
|
+
cat > dist/config/engines/engines.json << 'EOF'
|
|
172
|
+
{
|
|
173
|
+
"engines": {
|
|
174
|
+
"heuristic": {
|
|
175
|
+
"enabled": true,
|
|
176
|
+
"path": "./engines/heuristic-engine.js",
|
|
177
|
+
"version": "2.0",
|
|
178
|
+
"supportedLanguages": ["java"],
|
|
179
|
+
"priority": 1,
|
|
180
|
+
"description": "Enhanced Java analyzer with AST support"
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"defaultEngines": ["heuristic"],
|
|
184
|
+
"fallbackEngine": "heuristic"
|
|
185
|
+
}
|
|
186
|
+
EOF
|
|
187
|
+
|
|
188
|
+
npm pack dist/
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Runtime Behavior
|
|
192
|
+
|
|
193
|
+
### With AST Support Available
|
|
194
|
+
```bash
|
|
195
|
+
$ sunlint --rule=C010 --engine=heuristic --debug src/
|
|
196
|
+
🌳 [AST-Enhanced] Analyzing C010 for typescript with AST support
|
|
197
|
+
🌳 [AST-Enhanced] Found 12 violations via AST, 3 via regex
|
|
198
|
+
✅ heuristic: 15 violations found
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### AST Support Not Available (Fallback)
|
|
202
|
+
```bash
|
|
203
|
+
$ sunlint --rule=C010 --engine=heuristic --debug src/
|
|
204
|
+
⚠️ Tree-sitter TypeScript parser not available, falling back to regex
|
|
205
|
+
✅ heuristic: 8 violations found
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Minimal Installation
|
|
209
|
+
```bash
|
|
210
|
+
$ sunlint --rule=C010 --engine=heuristic --debug src/
|
|
211
|
+
# No AST warnings - AST modules not included
|
|
212
|
+
✅ heuristic: 8 violations found
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Package.json Configurations
|
|
216
|
+
|
|
217
|
+
### Full Distribution
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"name": "sunlint",
|
|
221
|
+
"dependencies": {
|
|
222
|
+
"minimatch": "^9.0.0",
|
|
223
|
+
"eslint": "^8.0.0"
|
|
224
|
+
},
|
|
225
|
+
"optionalDependencies": {
|
|
226
|
+
"tree-sitter": "^0.20.0",
|
|
227
|
+
"tree-sitter-javascript": "^0.20.0",
|
|
228
|
+
"tree-sitter-typescript": "^0.20.0",
|
|
229
|
+
"tree-sitter-dart": "^0.1.0",
|
|
230
|
+
"tree-sitter-java": "^0.20.0",
|
|
231
|
+
"tree-sitter-kotlin": "^0.3.0",
|
|
232
|
+
"tree-sitter-swift": "^0.4.0",
|
|
233
|
+
"tree-sitter-python": "^0.20.0",
|
|
234
|
+
"tree-sitter-go": "^0.20.0",
|
|
235
|
+
"tree-sitter-rust": "^0.20.0"
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### TypeScript-Only Distribution
|
|
241
|
+
```json
|
|
242
|
+
{
|
|
243
|
+
"name": "@sunlint/typescript",
|
|
244
|
+
"dependencies": {
|
|
245
|
+
"minimatch": "^9.0.0",
|
|
246
|
+
"eslint": "^8.0.0",
|
|
247
|
+
"tree-sitter": "^0.20.0",
|
|
248
|
+
"tree-sitter-javascript": "^0.20.0",
|
|
249
|
+
"tree-sitter-typescript": "^0.20.0"
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Minimal Distribution
|
|
255
|
+
```json
|
|
256
|
+
{
|
|
257
|
+
"name": "@sunlint/minimal",
|
|
258
|
+
"dependencies": {
|
|
259
|
+
"minimatch": "^9.0.0"
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Benefits
|
|
265
|
+
|
|
266
|
+
1. **Flexibility**: Choose the right distribution for your needs
|
|
267
|
+
2. **Performance**: Smaller bundles load faster, fewer dependencies to install
|
|
268
|
+
3. **Compatibility**: Minimal distribution works everywhere, enhanced versions provide better accuracy
|
|
269
|
+
4. **Gradual Adoption**: Start with minimal, upgrade to AST-enhanced when needed
|
|
270
|
+
5. **Deployment Options**: Different distributions for different environments (CI vs development)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# 🚀 SunLint Distribution & Installation Guide
|
|
2
|
+
|
|
3
|
+
## 🎯 **Problem:**
|
|
4
|
+
- Cần `cd extensions/sunlint` mỗi lần chạy
|
|
5
|
+
- Muốn cài đặt dễ dàng nhưng giữ tính bảo mật (private)
|
|
6
|
+
- Sử dụng từ bất kỳ directory nào
|
|
7
|
+
|
|
8
|
+
## ✅ **Solutions Ranking:**
|
|
9
|
+
|
|
10
|
+
### **🥇 Option 1: NPM Private Package (RECOMMENDED)**
|
|
11
|
+
|
|
12
|
+
#### **Setup (Company Admin - một lần):**
|
|
13
|
+
```bash
|
|
14
|
+
# 1. Setup package.json for global install
|
|
15
|
+
cd extensions/sunlint
|
|
16
|
+
npm pack # Tạo @sun-sunlint-1.0.0.tgz
|
|
17
|
+
|
|
18
|
+
# 2. Store trong internal file server hoặc private npm registry
|
|
19
|
+
# Hoặc upload lên GitHub Packages (private)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
#### **Installation (Dev - một lần):**
|
|
23
|
+
```bash
|
|
24
|
+
# Cách 1: Từ file
|
|
25
|
+
npm install -g /path/to/@sun-sunlint-1.0.0.tgz
|
|
26
|
+
|
|
27
|
+
# Cách 2: Từ private GitHub (yêu cầu GitHub token)
|
|
28
|
+
npm install -g git+https://github.com/your-company/sunlint.git
|
|
29
|
+
|
|
30
|
+
# Cách 3: Từ GitHub Packages (private npm registry)
|
|
31
|
+
npm login --registry=https://npm.pkg.github.com
|
|
32
|
+
npm install -g @your-company/sunlint --registry=https://npm.pkg.github.com
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
#### **Usage (Dev - hàng ngày):**
|
|
36
|
+
```bash
|
|
37
|
+
# Từ bất kỳ directory nào
|
|
38
|
+
sunlint --typescript --input src --all
|
|
39
|
+
sunlint --typescript --input src --rule C006
|
|
40
|
+
sunlint --typescript --input src --quality --format json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### **🥈 Option 2: Shell Script/Alias (SIMPLE)**
|
|
46
|
+
|
|
47
|
+
#### **Setup (Dev - một lần):**
|
|
48
|
+
```bash
|
|
49
|
+
# Tạo global command
|
|
50
|
+
sudo cat > /usr/local/bin/sunlint << 'EOF'
|
|
51
|
+
#!/bin/bash
|
|
52
|
+
SUNLINT_DIR="/Users/bach.ngoc.hoai/Docs/ee/coding-quality/extensions/sunlint"
|
|
53
|
+
cd "$SUNLINT_DIR" && node cli.js "$@"
|
|
54
|
+
EOF
|
|
55
|
+
|
|
56
|
+
sudo chmod +x /usr/local/bin/sunlint
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### **Usage (Dev - hàng ngày):**
|
|
60
|
+
```bash
|
|
61
|
+
# Từ bất kỳ directory nào
|
|
62
|
+
sunlint --typescript --input src --all
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### **🥉 Option 3: Project-Level NPM Scripts**
|
|
68
|
+
|
|
69
|
+
#### **Setup (Per Project):**
|
|
70
|
+
```json
|
|
71
|
+
// package.json của mỗi project
|
|
72
|
+
{
|
|
73
|
+
"scripts": {
|
|
74
|
+
"lint": "node /path/to/sunlint/cli.js --typescript --input src --all",
|
|
75
|
+
"lint:ci": "node /path/to/sunlint/cli.js --typescript --input src --all --format json",
|
|
76
|
+
"lint:single": "node /path/to/sunlint/cli.js --typescript --input",
|
|
77
|
+
"lint:quality": "node /path/to/sunlint/cli.js --typescript --input src --quality"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
#### **Usage:**
|
|
83
|
+
```bash
|
|
84
|
+
npm run lint
|
|
85
|
+
npm run lint:ci
|
|
86
|
+
npm run lint:single -- src/specific-file.ts
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 🏢 **Enterprise Recommendations:**
|
|
92
|
+
|
|
93
|
+
### **For CI/CD (Production):**
|
|
94
|
+
```yaml
|
|
95
|
+
# GitHub Actions
|
|
96
|
+
- name: Install SunLint
|
|
97
|
+
run: npm install -g /shared/tools/@sun-sunlint-1.0.0.tgz
|
|
98
|
+
|
|
99
|
+
- name: Run Code Quality Check
|
|
100
|
+
run: sunlint --typescript --input src --all --format json
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### **For Development (Local):**
|
|
104
|
+
```bash
|
|
105
|
+
# One-time setup script cho dev team
|
|
106
|
+
#!/bin/bash
|
|
107
|
+
echo "Installing SunLint..."
|
|
108
|
+
npm install -g /shared/tools/@sun-sunlint-1.0.0.tgz
|
|
109
|
+
echo "SunLint installed! Usage: sunlint --help"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### **For VS Code Integration (Future):**
|
|
113
|
+
```json
|
|
114
|
+
// .vscode/settings.json
|
|
115
|
+
{
|
|
116
|
+
"sunlint.executablePath": "sunlint",
|
|
117
|
+
"sunlint.autoRun": "onSave",
|
|
118
|
+
"sunlint.format": "eslint"
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 🎯 **Immediate Action Plan:**
|
|
125
|
+
|
|
126
|
+
### **Phase 1: Quick Fix (This Week)**
|
|
127
|
+
Implement **Option 2 (Shell Script)**:
|
|
128
|
+
1. Tạo shell script cho dev team
|
|
129
|
+
2. Add vào onboarding documentation
|
|
130
|
+
3. Test trên CI environment
|
|
131
|
+
|
|
132
|
+
### **Phase 2: Professional (Next Sprint)**
|
|
133
|
+
Implement **Option 1 (NPM Package)**:
|
|
134
|
+
1. Setup private npm registry hoặc GitHub Packages
|
|
135
|
+
2. Create installation documentation
|
|
136
|
+
3. Migrate existing projects
|
|
137
|
+
|
|
138
|
+
### **Phase 3: IDE Integration (Future)**
|
|
139
|
+
1. VS Code extension
|
|
140
|
+
2. IntelliJ plugin
|
|
141
|
+
3. Auto-formatting on save
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## ✅ **Benefits Matrix:**
|
|
146
|
+
|
|
147
|
+
| Solution | Setup Effort | Usage Simplicity | CI/CD Ready | Maintenance |
|
|
148
|
+
|----------|--------------|------------------|-------------|-------------|
|
|
149
|
+
| NPM Package | High | Excellent | Excellent | Low |
|
|
150
|
+
| Shell Script | Low | Good | Good | Medium |
|
|
151
|
+
| NPM Scripts | Medium | Good | Excellent | High |
|
|
152
|
+
|
|
153
|
+
**Recommendation: Start with Shell Script (quick), then migrate to NPM Package (professional).**
|