ngcompass 0.1.6-beta → 0.1.9-beta
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/README.md +61 -62
- package/dist/cli.cjs +13 -14
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +13 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +13 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +13 -14
- package/dist/index.js.map +1 -1
- package/package.json +27 -11
- package/schematics/collection.json +10 -0
- package/schematics/ng-add/index.cjs +15 -0
- package/schematics/ng-add/schema.json +6 -0
package/README.md
CHANGED
|
@@ -17,14 +17,14 @@ It is designed for teams that want a clearer view of Angular-specific risks: com
|
|
|
17
17
|
|
|
18
18
|
## Highlights
|
|
19
19
|
|
|
20
|
-
| Area
|
|
21
|
-
|
|
22
|
-
| Architecture | Circular dependencies, boundary violations, and fragile component relationships
|
|
23
|
-
| Performance
|
|
24
|
-
| SSR
|
|
25
|
-
| Security
|
|
26
|
-
| Reactivity
|
|
27
|
-
| Code quality | Deprecated patterns, focused tests, and modern Angular API improvements
|
|
20
|
+
| Area | What ngcompass helps find |
|
|
21
|
+
| ------------ | --------------------------------------------------------------------------------------------- |
|
|
22
|
+
| Architecture | Circular dependencies, boundary violations, and fragile component relationships |
|
|
23
|
+
| Performance | Missing `OnPush`, expensive template expressions, missing `trackBy`, and inefficient bindings |
|
|
24
|
+
| SSR | Browser-only APIs in universal code, hydration risks, and render lifecycle pitfalls |
|
|
25
|
+
| Security | Unsafe template bindings and sanitizer bypasses |
|
|
26
|
+
| Reactivity | RxJS subscription issues, Signals misuse, and migration opportunities |
|
|
27
|
+
| Code quality | Deprecated patterns, focused tests, and modern Angular API improvements |
|
|
28
28
|
|
|
29
29
|
## Installation
|
|
30
30
|
|
|
@@ -71,14 +71,14 @@ pnpm exec ngcompass analyze
|
|
|
71
71
|
|
|
72
72
|
## Output Formats
|
|
73
73
|
|
|
74
|
-
| Command
|
|
75
|
-
|
|
76
|
-
| `ngcompass analyze`
|
|
77
|
-
| `ngcompass analyze --format console --compact`
|
|
78
|
-
| `ngcompass analyze --format html --output report.html` | Self-contained HTML report
|
|
79
|
-
| `ngcompass analyze --format ui`
|
|
80
|
-
| `ngcompass analyze --format json > results.json`
|
|
81
|
-
| `ngcompass analyze --format sarif > results.sarif`
|
|
74
|
+
| Command | Output |
|
|
75
|
+
| ------------------------------------------------------ | ------------------------------ |
|
|
76
|
+
| `ngcompass analyze` | Default terminal report |
|
|
77
|
+
| `ngcompass analyze --format console --compact` | Compact one-line issue output |
|
|
78
|
+
| `ngcompass analyze --format html --output report.html` | Self-contained HTML report |
|
|
79
|
+
| `ngcompass analyze --format ui` | Interactive HTML report alias |
|
|
80
|
+
| `ngcompass analyze --format json > results.json` | Machine-readable JSON |
|
|
81
|
+
| `ngcompass analyze --format sarif > results.sarif` | SARIF for GitHub Code Scanning |
|
|
82
82
|
|
|
83
83
|
## Configuration
|
|
84
84
|
|
|
@@ -119,15 +119,15 @@ export default defineConfig({
|
|
|
119
119
|
|
|
120
120
|
### Presets
|
|
121
121
|
|
|
122
|
-
| Preset
|
|
123
|
-
|
|
124
|
-
| `ngcompass:recommended` | Balanced default for most Angular projects
|
|
125
|
-
| `ngcompass:strict`
|
|
126
|
-
| `ngcompass:performance` | Rendering and change-detection checks
|
|
127
|
-
| `ngcompass:reactivity`
|
|
128
|
-
| `ngcompass:security`
|
|
129
|
-
| `ngcompass:ssr`
|
|
130
|
-
| `ngcompass:all`
|
|
122
|
+
| Preset | Purpose |
|
|
123
|
+
| ----------------------- | ------------------------------------------- |
|
|
124
|
+
| `ngcompass:recommended` | Balanced default for most Angular projects |
|
|
125
|
+
| `ngcompass:strict` | Stronger enforcement for mature codebases |
|
|
126
|
+
| `ngcompass:performance` | Rendering and change-detection checks |
|
|
127
|
+
| `ngcompass:reactivity` | Signals and RxJS correctness |
|
|
128
|
+
| `ngcompass:security` | Security-focused Angular checks |
|
|
129
|
+
| `ngcompass:ssr` | Server rendering and hydration safety |
|
|
130
|
+
| `ngcompass:all` | Every built-in rule at its default severity |
|
|
131
131
|
|
|
132
132
|
Override individual rules in the same config:
|
|
133
133
|
|
|
@@ -143,32 +143,32 @@ export default defineConfig({
|
|
|
143
143
|
|
|
144
144
|
## Commands
|
|
145
145
|
|
|
146
|
-
| Command
|
|
147
|
-
|
|
148
|
-
| `ngcompass init`
|
|
149
|
-
| `ngcompass analyze`
|
|
150
|
-
| `ngcompass rules`
|
|
151
|
-
| `ngcompass rules <name>`
|
|
152
|
-
| `ngcompass config health` | Validate configuration
|
|
153
|
-
| `ngcompass cache info`
|
|
154
|
-
| `ngcompass cache clear`
|
|
155
|
-
| `ngcompass cache path`
|
|
146
|
+
| Command | Description |
|
|
147
|
+
| ------------------------- | ---------------------------- |
|
|
148
|
+
| `ngcompass init` | Create `ngcompass.config.ts` |
|
|
149
|
+
| `ngcompass analyze` | Run analysis |
|
|
150
|
+
| `ngcompass rules` | List available rules |
|
|
151
|
+
| `ngcompass rules <name>` | Inspect one rule |
|
|
152
|
+
| `ngcompass config health` | Validate configuration |
|
|
153
|
+
| `ngcompass cache info` | Show cache status |
|
|
154
|
+
| `ngcompass cache clear` | Clear cached analysis data |
|
|
155
|
+
| `ngcompass cache path` | Print the cache directory |
|
|
156
156
|
|
|
157
157
|
### Analyze Options
|
|
158
158
|
|
|
159
|
-
| Option
|
|
160
|
-
|
|
161
|
-
| `--format <fmt>`
|
|
162
|
-
| `--output <path>`
|
|
163
|
-
| `--compact`
|
|
164
|
-
| `-q, --quiet`
|
|
165
|
-
| `--no-recommendation`
|
|
166
|
-
| `--rule <id>`
|
|
167
|
-
| `--force`
|
|
168
|
-
| `-p, --profile <name>` | Run a named config profile
|
|
169
|
-
| `--mode <mode>`
|
|
170
|
-
| `--max-workers <n>`
|
|
171
|
-
| `--skip-type-check`
|
|
159
|
+
| Option | Description |
|
|
160
|
+
| ---------------------- | ------------------------------------------------ |
|
|
161
|
+
| `--format <fmt>` | `console`, `json`, `sarif`, `html`, or `ui` |
|
|
162
|
+
| `--output <path>` | Output path for HTML/UI reports |
|
|
163
|
+
| `--compact` | Use compact issue output |
|
|
164
|
+
| `-q, --quiet` | Show summary counts only |
|
|
165
|
+
| `--no-recommendation` | Hide fix recommendations |
|
|
166
|
+
| `--rule <id>` | Run one rule in isolation |
|
|
167
|
+
| `--force` | Ignore cached results |
|
|
168
|
+
| `-p, --profile <name>` | Run a named config profile |
|
|
169
|
+
| `--mode <mode>` | Performance mode: `eco`, `balanced`, or `turbo` |
|
|
170
|
+
| `--max-workers <n>` | Limit worker threads |
|
|
171
|
+
| `--skip-type-check` | Skip rules that require TypeScript type checking |
|
|
172
172
|
|
|
173
173
|
## CI
|
|
174
174
|
|
|
@@ -196,19 +196,19 @@ ngcompass analyze --force
|
|
|
196
196
|
|
|
197
197
|
## Monorepo
|
|
198
198
|
|
|
199
|
-
| Package
|
|
200
|
-
|
|
201
|
-
| [`ngcompass`](packages/cli)
|
|
202
|
-
| [`@ngcompass/config`](packages/config)
|
|
203
|
-
| [`@ngcompass/scanner`](packages/scanner)
|
|
204
|
-
| [`@ngcompass/rules`](packages/rules)
|
|
205
|
-
| [`@ngcompass/planner`](packages/planner)
|
|
206
|
-
| [`@ngcompass/engine`](packages/engine)
|
|
207
|
-
| [`@ngcompass/ast`](packages/ast)
|
|
208
|
-
| [`@ngcompass/cache`](packages/cache)
|
|
209
|
-
| [`@ngcompass/reporters`](packages/reporters) | Console, JSON, SARIF, and HTML reporters
|
|
210
|
-
| [`@ngcompass/common`](packages/common)
|
|
211
|
-
| [`@ngcompass/site`](packages/site)
|
|
199
|
+
| Package | Responsibility |
|
|
200
|
+
| -------------------------------------------- | ------------------------------------------------------- |
|
|
201
|
+
| [`ngcompass`](packages/cli) | CLI entry point |
|
|
202
|
+
| [`@ngcompass/config`](packages/config) | Config loading, validation, profiles, and health checks |
|
|
203
|
+
| [`@ngcompass/scanner`](packages/scanner) | File discovery and filtering |
|
|
204
|
+
| [`@ngcompass/rules`](packages/rules) | Built-in rules, presets, and rule registry |
|
|
205
|
+
| [`@ngcompass/planner`](packages/planner) | Incremental execution planning |
|
|
206
|
+
| [`@ngcompass/engine`](packages/engine) | Rule execution and analysis orchestration |
|
|
207
|
+
| [`@ngcompass/ast`](packages/ast) | TypeScript, template, and style parsing helpers |
|
|
208
|
+
| [`@ngcompass/cache`](packages/cache) | Memory and disk cache services |
|
|
209
|
+
| [`@ngcompass/reporters`](packages/reporters) | Console, JSON, SARIF, and HTML reporters |
|
|
210
|
+
| [`@ngcompass/common`](packages/common) | Shared types and utilities |
|
|
211
|
+
| [`@ngcompass/site`](packages/site) | Documentation site |
|
|
212
212
|
|
|
213
213
|
## Development
|
|
214
214
|
|
|
@@ -238,4 +238,3 @@ pnpm prerelease:check
|
|
|
238
238
|
- Rule names, messages, and report layout may change before `1.0`.
|
|
239
239
|
- Template analysis is best-effort for highly dynamic templates.
|
|
240
240
|
- Validate ngcompass against your project before making it a required CI gate.
|
|
241
|
-
|
package/dist/cli.cjs
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
'use strict';var commander=require('commander'),reporters=require('@ngcompass/reporters'),config=require('@ngcompass/config'),
|
|
2
|
+
'use strict';var commander=require('commander'),reporters=require('@ngcompass/reporters'),config=require('@ngcompass/config'),k=require('picocolors'),E=require('process'),cache=require('@ngcompass/cache'),N=require('path'),common=require('@ngcompass/common'),engine=require('@ngcompass/engine'),planner=require('@ngcompass/planner'),scanner=require('@ngcompass/scanner'),rules=require('@ngcompass/rules');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var k__default=/*#__PURE__*/_interopDefault(k);var E__default=/*#__PURE__*/_interopDefault(E);var N__default=/*#__PURE__*/_interopDefault(N);var $=()=>{process.stdout.isTTY&&process.stdout.write("\x1B[?25h");},f=(t=1)=>{$(),process.exit(t);},d=(t,r)=>{let e=r===void 0?"":`: ${r instanceof Error?r.message:String(r)}`;console.error(`${k__default.default.red(t)}${e}`);};function D(t,r){t.command("init").description("Create a starter ngcompass configuration in the current project").option("-f, --force","Overwrite an existing configuration file").option("--cwd <path>","Project directory where the configuration will be created",process.cwd()).action(async e=>{try{let n=await config.initConfig({cwd:e.cwd,force:e.force});await reporters.getConfigReporter().renderInitResult(n),n.success||n.alreadyExists||f();}catch(n){d("Error initializing configuration",n),f();}});}var M=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],R=class{stream;timer=null;frameIndex=0;message="";isTTY;constructor(r){this.stream=r,this.isTTY=!!r.isTTY;}start(r){this.message=r,this.frameIndex=0,this.isTTY?(this.stream.write("\x1B[?25l"),this.render(),this.timer=setInterval(()=>this.render(),80)):this.stream.write(`${k__default.default.cyan("\u276F")} ${k__default.default.dim(r)}
|
|
3
3
|
`);}update(r){this.message=r,this.isTTY&&this.timer&&this.render();}writeLine(r){this.isTTY&&this.timer?(this.stream.write("\r\x1B[K"),this.stream.write(`${r}
|
|
4
4
|
`),this.render()):this.stream.write(`${r}
|
|
5
|
-
`);}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),this.isTTY&&(this.stream.write("\r\x1B[K"),this.stream.write("\x1B[?25h"));}render(){let r=
|
|
6
|
-
`))),null}if(!
|
|
7
|
-
`));
|
|
8
|
-
`);});}async function
|
|
5
|
+
`);}stop(){this.timer&&(clearInterval(this.timer),this.timer=null),this.isTTY&&(this.stream.write("\r\x1B[K"),this.stream.write("\x1B[?25h"));}render(){let r=k__default.default.cyan(M[this.frameIndex%M.length]);this.frameIndex++,this.stream.write(`\r\x1B[K${r} ${k__default.default.dim(this.message)}`);}};var we={eco:{typeAwareConcurrency:1,typeAwareFileConcurrency:1,typeAwareChunkSize:100,typeAwareIsolation:"auto",typeAwareChunkStrategy:"dependency"},balanced:{typeAwareConcurrency:1,typeAwareFileConcurrency:1,typeAwareChunkSize:150,typeAwareIsolation:"auto",typeAwareChunkStrategy:"dependency"},turbo:{typeAwareConcurrency:2,typeAwareFileConcurrency:4,typeAwareChunkSize:500,typeAwareIsolation:"off",typeAwareChunkStrategy:"simple"}},j=["eco","balanced","turbo"],Ce=new Set(j);function xe(t,r){if(t===void 0)return;let e=Number(t);if(!Number.isInteger(e)||e<1)throw Error(`${r} must be a positive integer.`);return e}function _(t,r){let e=we[(function(n){let o=n??"balanced";if(!Ce.has(o))throw Error(`Invalid performance mode "${o}". Expected one of: ${j.join(", ")}.`);return o})(t.mode)];return {maxWorkers:xe(t.maxWorkers,"--max-workers")??r.maxWorkers,typeAwareChunkSize:e.typeAwareChunkSize,typeAwareConcurrency:e.typeAwareConcurrency,typeAwareFileConcurrency:e.typeAwareFileConcurrency,typeAwareIsolation:e.typeAwareIsolation,typeAwareChunkStrategy:e.typeAwareChunkStrategy}}function F(t){return t==="ui"?"html":t??"console"}function U(t,r){if(t)return F(t);switch(r){case "json":return "json";case "sarif":return "sarif";case "html":return "html";default:return "console"}}function B(t,r){let e=t.failOnSeverity??"error",n=t.maxWarnings??10;return r.totalErrors>0||e==="warn"&&r.totalWarnings>0||r.totalWarnings>n}function Y(t,r){if(!t?.project)return;let e=t.tsconfigRootDir?N__default.default.resolve(r,t.tsconfigRootDir):r;return N__default.default.resolve(e,t.project)}function q(t){return t instanceof Error?t:Error(String(t))}function G(t){return t.mode??"balanced"}function T(t,r,e){return `Running analysis in ${t} mode: ${r.toLocaleString()}/${e.toLocaleString()} checks complete...`}async function H(t,r,e){let n=performance.now();e.step("\u276F Loading configuration...");let o=await config.resolveConfig({profile:t.profile,cache:r,cwd:E__default.default.cwd()});if(!o.report.valid){let i=o.report.issues.map(u=>{let s=u.path?.join(".")||"root";return `[${u.severity.toUpperCase()}] ${s}: ${u.message}`});return e.error(Error(["Configuration validation failed",...i].join(`
|
|
6
|
+
`))),null}if(!o.config)return e.error(Error("No configuration found")),null;let a=o.config.plugins;if(a&&a.length>0){e.step(`\u276F Loading ${a.length} plugin(s)...`);let i=E__default.default.cwd();await config.loadPlugins(a,i,rules.getGlobalRegistry()),e.info(`Loaded ${a.length} plugin(s)`);}return e.debug(`Config resolve: ${(performance.now()-n).toFixed(2)}ms`),{config:o.config}}async function K(t,r,e,n){let o=performance.now();n.step("\u276F Discovering files...");let a=await scanner.scan({rootDir:E__default.default.cwd(),include:t.include??[...common.DEFAULT_INCLUDE_PATTERNS],exclude:t.exclude??[],ignorePatterns:t.ignorePatterns,tsConfigPath:Y(t.parserOptions,E__default.default.cwd()),respectGitignore:true,debug:r.debug,cache:e});return a.ok?(n.info(`\u276F Found ${a.data.files.length} files in ${(performance.now()-o).toFixed(0)}ms`),n.debug(`File discovery: ${(performance.now()-o).toFixed(2)}ms`),a.data.files):(n.error(Error(`File discovery failed: ${a.error.message}`)),null)}async function V(t,r,e){let n=performance.now();e.step("\u276F Loading rules...");let o=t;r.rule&&(e.info(`Filtering analysis to single rule: ${r.rule}`),o={...t,rules:{[r.rule]:"error"},extends:[]});let a=await rules.resolveRules(o,E__default.default.cwd());if(!a.ok)return e.error(Error(`Rule resolution failed: ${a.error.message}`)),null;let i=rules.getEnabledRules(a.data.rules);return e.info(`\u276F Loaded ${i.size} active rules in ${(performance.now()-n).toFixed(0)}ms`),e.debug(`Rule resolution: ${(performance.now()-n).toFixed(2)}ms`),i}async function Z(t,r,e,n,o,a,i){let u=performance.now();o.step("\u276F Planning analysis...");let s=await planner.buildExecutionPlan({files:t,rules:r,rootDir:E__default.default.cwd(),cache:e,debug:n.debug,incremental:n.force?{forceRerun:true}:void 0,workerCount:i,overrides:a.overrides});return s.ok?(s.data.precomputedAnalysis?o.info("\u276F Reused cached analysis plan"):o.info(`\u276F Prepared ${s.data.tasks.length.toLocaleString()} checks in ${(performance.now()-u).toFixed(0)}ms`),o.debug(`Plan build: ${(performance.now()-u).toFixed(2)}ms`),s.data):(o.error(Error(`Execution plan building failed: ${s.error.message}`)),null)}async function J(t,r,e,n,o,a,i,u,s){let C=performance.now();engine.configureRuleExecutor(rules.executeBatchedNewEngineRules,rules.isNewEngineRule);let p=await engine.runAnalysis(t,{rootDir:E__default.default.cwd(),cache:r,debug:n.debug,files:a,maxWorkers:e.maxWorkers,typeAwareChunkSize:e.typeAwareChunkSize,typeAwareConcurrency:e.typeAwareConcurrency,typeAwareFileConcurrency:e.typeAwareFileConcurrency,typeAwareIsolation:e.typeAwareIsolation,typeAwareChunkStrategy:e.typeAwareChunkStrategy,skipTypeCheck:n.skipTypeCheck,parserOptions:i?.parserOptions,onProgress:u,onFileProgress:s});return p.ok?(o.debug(`Execution: ${(performance.now()-C).toFixed(2)}ms`),p.data):(o.error(Error(`Analysis failed: ${p.error.message}`)),null)}async function Q(t,r,e,n){if(!r)return;let o=performance.now(),a=[];for(let i of t)i.taskId&&a.push([i.taskId,i]);a.length>0&&(await r.results.setMany(a),e.debug&&n.debug(`Saved ${a.length} results to cache (${(performance.now()-o).toFixed(2)}ms)`));}var We={taskCount:0,issueCount:0,errorCount:0,warningCount:0,duration:0};function ee(t,r){let e=new Map;for(let n of t.tasks){let o=n.filePath;typeof o=="string"&&o.length!==0&&(n.needsTypeChecker||n.needsProjectContext)===r&&e.set(o,(e.get(o)??0)+1);}return e}function I(t,r){let e=t??We;return {taskCount:e.taskCount+r.taskCount,issueCount:e.issueCount+r.issueCount,errorCount:e.errorCount+r.errorCount,warningCount:e.warningCount+r.warningCount,duration:e.duration+r.duration}}function re(t,r,e){let n=ee(t,false),o=ee(t,true),a=new Map,i=new Map,u=new Set,s=new Set,C=(p,c,g)=>{if(s.has(p))return;let m=g?s:u;m.has(p)||(m.add(p),r((function(y,l){let w=l.issueCount>0,v=w?k__default.default.red("\u276F"):k__default.default.green("\u276F"),A=w?k__default.default.red(common.formatDuration(l.duration)):k__default.default.green(common.formatDuration(l.duration));if(w){let h=`${l.issueCount.toLocaleString()} ${common.pluralise(l.issueCount,"issue")}`;return `${v} ${k__default.default.red(y)} ${A} ${k__default.default.red(h)}`}return `${v} ${k__default.default.dim(y)} ${A}`})(N__default.default.relative(e,p)||p,c)));};return p=>{let c=p.filePath;if(s.has(c))return;if(p.typeAware===false){let l=I(a.get(c),p);a.set(c,l);let w=n.get(c)??l.taskCount;if(l.taskCount<w)return;C(c,l,!o.has(c));return}if(p.typeAware===true){var g;let l=I(i.get(c),p);i.set(c,l);let w=o.get(c)??l.taskCount;if(l.taskCount<w)return;C(c,(g=a.get(c),g?{taskCount:g.taskCount+l.taskCount,issueCount:g.issueCount+l.issueCount,errorCount:g.errorCount+l.errorCount,warningCount:g.warningCount+l.warningCount,duration:g.duration+l.duration}:l),true);return}let m=(n.get(c)??0)+(o.get(c)??0),y=I(a.get(c),p);a.set(c,y),y.taskCount<(m||y.taskCount)||C(c,y,true);}}function oe(t,r){t.command("analyze").description("Analyze your project and report rule violations and architecture risks").option("-p, --profile <name>","Configuration profile to run").option("--force","Ignore cached results and re-run all checks").option("--format <fmt>","Reporter format: console | json | sarif | html | ui").option("--compact","Use compact, ESLint-style output").option("-q, --quiet","Show summary counts only, suppress violation details").option("--no-recommendation","Suppress fix recommendations from output").option("--output <path>","Output path for UI reports (default: ngcompass-report.html)").option("--rule <id>","Run only one rule (useful for debugging or focused checks)").option("--mode <mode>","Performance mode: eco | balanced | turbo (default: balanced)","balanced").option("--max-workers <n>","Cap the number of worker threads (lower = less memory, e.g. --max-workers 2)").option("--skip-type-check","Skip rules that require the TypeScript type checker (fastest, lowest memory)").action(async e=>{let n=performance.now(),o=reporters.getReporter(F(e.format),{compact:!!e.compact,outputPath:e.output,quiet:!!e.quiet,noRecommendation:e.recommendation===false}),a=r,i=0;try{let u=await H(e,r,o);if(!u){i=1;return}let{config:s}=u,C=_(e,s);a=cache.createRuntimeCache(s,E__default.default.cwd());let p=U(e.format,s.outputFormat);o=reporters.getReporter(p,{compact:!!e.compact,outputPath:e.output??s.outputPath,quiet:!!e.quiet,noRecommendation:e.recommendation===!1});let c=await K(s,e,a,o);if(!c){i=1;return}let g=await V(s,e,o);if(!g){i=1;return}let m=await Z(c,g,a,e,o,s,C.maxWorkers);if(!m){i=1;return}let y=p==="console"?E__default.default.stdout:E__default.default.stderr,l=new R(y),w=m.tasks.length+(m.skippedTasks?.length??0),v=G(e);l.start(T(v,0,w));let A=re(m,x=>l.writeLine(x),E__default.default.cwd()),h=await J(m,a,C,e,o,c,s,(x,fe)=>{l.update(T(v,x,fe));},A);if(l.stop(),!h){i=1;return}let de=performance.now()-n,O={scannedFiles:new Set([...m.tasks.map(x=>x.filePath),...(m.skippedTasks??[]).map(x=>x.filePath)]).size,discoveredFiles:c.length,totalFiles:h.stats.totalFiles,totalTasks:m.tasks.length+(m.skippedTasks?.length??0),cachedTasks:m.precomputedAnalysis?m.tasks.length:void 0,totalErrors:h.stats.totalErrors,totalWarnings:h.stats.totalWarnings,failOnSeverity:s.failOnSeverity,maxWarnings:s.maxWarnings,duration:de};p==="console"&&o.summary(O),o.parseErrors(h.parseErrors),o.report(h.results),p!=="console"&&(o.step("\u276F Writing report..."),o.summary(O)),m.precomputedAnalysis||await Q(h.results,a,e,o),B(s,h.stats)&&(i=1);}catch(u){o.error(q(u)),i=1;}finally{a&&a!==r&&await a.flush(),i!==0&&f(i);}});}function ne(t,r){t.command("config").description("Inspect and validate ngcompass configuration").command("health").description("Run semantic validation checks for the active configuration").option("-p, --profile <name>","Configuration profile to validate").action(async e=>{try{let n=await config.validateConfig({cwd:E__default.default.cwd(),cache:e.cache?r:void 0,profile:e.profile});await reporters.getConfigReporter().renderHealthReport(n.report),n.report.valid||f();}catch(n){d("Error",n),f();}});}var ie=["ast","config","results","all"],Be=new Set(ie);function se(t,r){let e=t.command("cache").description("Inspect and manage analysis cache data");e.command("clear").description("Clear cached data for one cache type or all cache types").option("-p, --profile <name>","Configuration profile used to resolve cache settings").option("--type <type>","Cache type to clear: ast | config | results | all","all").action(async n=>{var o;let a,i=(a=o=n.type,Be.has(a)?o:(d(`Invalid cache type: ${o}. Must be one of: ${ie.join(", ")}`),f())),u=reporters.getCacheReporter();E__default.default.stdout.write(k__default.default.dim(` \u203A Clearing cache...
|
|
7
|
+
`));try{let s=await z(r,{profile:n.profile,allowDisabled:!0});i==="all"?await s.clear():await s.clearType(i),u.renderClearResult(i);}catch(s){d("Error clearing cache",s),f();}}),e.command("info").description("Show cache status, size, and usage details").option("-p, --profile <name>","Configuration profile used to resolve cache settings").action(async n=>{let o=reporters.getCacheReporter();try{let a=await z(r,{profile:n.profile,allowDisabled:!0}),i=await a.getInfo();o.renderCacheInfo(i);}catch(a){d("Error getting cache info",a),f();}}),e.command("path").description("Print the resolved cache directory path").option("-p, --profile <name>","Configuration profile used to resolve cache settings").action(async n=>{let o=await z(r,{profile:n.profile,allowDisabled:true});E__default.default.stdout.write(`${o.getCachePath()}
|
|
8
|
+
`);});}async function z(t,r={}){let e=r.cwd??E__default.default.cwd();try{let n=await config.resolveConfig({profile:r.profile,cache:t,cwd:e});return !n.report.valid||!n.config?t:cache.createRuntimeCache(n.config,e,{allowDisabled:r.allowDisabled})??t}catch(n){return d("Unable to resolve cache configuration; using default cache",n),t}}function ce(t){t.command("rules [ruleName]").description("Browse available rules or inspect details for a specific rule").option("--preset <name>","Filter by preset: recommended, strict, performance, reactivity, or all").action((r,e)=>{e.preset&&!rules.isBuiltinPreset(e.preset)&&(d(`Unknown preset: "${e.preset}".`),process.stderr.write(k__default.default.dim(`Available presets: recommended, strict, all, performance, reactivity
|
|
9
|
+
`)),f());let n=rules.getRuleListEntries(),o=reporters.getRulesReporter({preset:e.preset});if(r){let a=n.find(i=>i.name===r);if(!a){d(`Rule "${r}" not found.`),process.stderr.write(k__default.default.dim("Run `ngcompass rules` to list available rules.\n")),f();return}o.renderSingleRule(a);}else o.render(n);});}function pe(t,r){D(t),oe(t,r),ne(t,r),se(t,r),ce(t);}var ue=false,P=async(t,r)=>{if(!ue){if(ue=true,$(),t)try{let e=new Promise(n=>setTimeout(n,1e4).unref());await Promise.race([t.flush(),e]);}catch(e){d("[ngcompass] Cache flush failed during shutdown",e);}process.exit(r);}},me=(t,r,e)=>{d(`[ngcompass] ${r}`,e),P(t,1);},Je=async t=>{let{default:r}=await import('picocolors'),e=process.cwd();process.stdout.write(`
|
|
10
|
+
${r.dim(">")} ${r.dim(`ngcompass@${common.PACKAGE_VERSION}`)} ${r.dim(t)} ${r.dim(e)}
|
|
11
|
+
${r.dim(">")} ${r.dim("ngcompass")} ${r.dim("run")}
|
|
12
|
+
|
|
13
|
+
${r.bgCyan(r.white(r.bold(` ${t.toUpperCase()} `)))} ${r.cyan(common.PACKAGE_VERSION)} ${r.dim(e)}
|
|
14
|
+
|
|
15
|
+
`);};async function Qe(){let t=new commander.Command;t.name("ngcompass").description("Static analysis and architecture insights for Angular codebases.").version(common.PACKAGE_VERSION,"-V, --version","Display ngcompass version").option("--debug","Enable detailed debug logs across all modules").addHelpText("after",`
|
|
9
16
|
Examples:
|
|
10
17
|
$ ngcompass init
|
|
11
18
|
$ ngcompass analyze --profile strict
|
|
12
19
|
$ ngcompass cache info
|
|
13
|
-
`).hook("preAction",async(e,
|
|
14
|
-
${n.dim(">")} ${n.dim(`ngcompass@${common.PACKAGE_VERSION}`)} ${n.dim(l)} ${n.dim(p)}
|
|
15
|
-
${n.dim(">")} ${n.dim("ngcompass")} ${n.dim("run")}
|
|
16
|
-
|
|
17
|
-
${n.bgCyan(n.white(n.bold(` ${l.toUpperCase()} `)))} ${n.cyan(common.PACKAGE_VERSION)} ${n.dim(p)}
|
|
18
|
-
|
|
19
|
-
`);}});let r=cache.createCacheContext();process.on("SIGINT",()=>{S(r,130);}),process.on("SIGTERM",()=>{S(r,143);}),process.on("uncaughtException",e=>{b(),console.error(`
|
|
20
|
-
[ngcompass] Unexpected error: ${e.message}`),S(r,1);}),process.on("unhandledRejection",e=>{b();let o=e instanceof Error?e.message:String(e);console.error(`
|
|
21
|
-
[ngcompass] Unhandled promise rejection: ${o}`),S(r,1);});try{if(rules.registerAllBuiltinRules(),Ae(t,r),!process.argv.slice(2).length)return void t.outputHelp();await t.parseAsync(process.argv),await r.flush(),process.exit(0);}catch(e){b();let o=e instanceof Error?e.message:String(e);console.error(`[ngcompass] Fatal error: ${o}`),await S(r,1);}}cr().catch(t=>{b();let r=t instanceof Error?t.message:String(t);console.error(`[ngcompass] Fatal error: ${r}`),process.exit(1);});exports.run=cr;//# sourceMappingURL=cli.cjs.map
|
|
20
|
+
`).hook("preAction",async(e,n)=>{let o;if(e.opts().debug&&common.enableDebug("debug","all"),(o=n.opts().format)!=="json"&&o!=="sarif"&&o!=="html"&&o!=="ui"){let a=n.parent,i=a&&a.name()!=="ngcompass"?a.name():n.name();await Je(i);}});let r=cache.createCacheContext();process.on("SIGINT",()=>{P(r,130);}),process.on("SIGTERM",()=>{P(r,143);}),process.on("uncaughtException",e=>{me(r,"Unexpected error",e);}),process.on("unhandledRejection",e=>{me(r,"Unhandled promise rejection",e);});try{if(rules.registerAllBuiltinRules(),pe(t,r),!process.argv.slice(2).length)return void t.outputHelp();await t.parseAsync(process.argv),await r.flush(),process.exit(0);}catch(e){d("[ngcompass] Fatal error",e),await P(r,1);}}Qe().catch(t=>{d("[ngcompass] Fatal error",t),$(),process.exit(1);});exports.run=Qe;//# sourceMappingURL=cli.cjs.map
|
|
22
21
|
//# sourceMappingURL=cli.cjs.map
|