Output and exit codes
Markdown for agentsEach example on this page comes from one repository. Its JSON config has one table. The file
src/shared/label.ts imports a file of the feature cart, and the table refuses it:
{ "$schema": "./node_modules/@enhance-eng/archangel/archangel.schema.json", "parts": { "feature": "src/features/{feature}/**", "shared": "src/shared/**" }, "rules": [ { "kind": "mayImport", "name": "app", "rows": { "feature": ["shared"], "shared": [] }, "because": "Shared code never depends on a feature." } ]}The default format, for people. Each problem shows its code, its message, the line of source code with a mark under the import, what to do, the rule and your reason.
$ npx archangel checkerror[may-import]: shared may not import feature, through "../features/cart/total": shared may import only itself --> src/shared/label.ts:1:23 |1 | import { total } from '../features/cart/total'; | ^^^^^^^^^^^^^^^^^^^^^^^^ shared may import only itself | = help: remove the import, or move the code to a file whose row permits the import = note: rule: app.shared = note: because: Shared code never depends on a feature.
checked 2 files and 1 imports: 1 problemFor what a code means, run `archangel docs may-import`.| Line | What it is |
|---|---|
error[may-import]: ... |
The diagnostic code and the message. archangel docs <code> explains the code. |
--> src/shared/label.ts:1:23 |
The file, the line and the column. |
= help: ... |
What to do. |
= note: rule: ... |
The name of the rule, for off, an exception or the baseline. |
= note: because: ... |
Your reason, from because. |
= note: see: ... |
Your link, from link. |
There are no warnings. Each problem is an error.
One JSON document, for programs. check, test, rules, explain and why write JSON.
$ npx archangel check --format json{ "schemaVersion": 1, "diagnostics": [ { "code": "may-import", "severity": "error", "rule": "app.shared", "file": "src/shared/label.ts", "line": 1, "column": 23, "span": [ 22, 46 ], "specifier": "../features/cart/total", "message": "shared may not import feature, through \"../features/cart/total\": shared may import only itself", "help": "shared may import only itself", "reason": "Shared code never depends on a feature.", "link": null, "id": { "rule": "app.shared", "file": "src/shared/label.ts", "specifier": "../features/cart/total", "occurrence": 0 }, "cycle": [], "group": [], "chain": [], "fix": null } ], "summary": { "files": 2, "imports": 1, "warnings": 0, "exceptions": {}, "baselined": {}, "permittedUnresolved": 0, "unfollowed": 0, "unfollowedImports": [], "linksNotFollowed": [], "nestedRepositories": [], "presetNamesMatchingNothing": [], "work": { "filesFound": 2, "filesRead": 2, "bytesRead": 113, "filesParsed": 2, "importsFound": 1, "resolutions": 1, "filesClassified": 4, "patternPasses": 4, "ruleEvaluations": 1, "cycleFilesVisited": 0, "transitiveFilesVisited": 0, "structureEvaluations": 0, "folderEvaluations": 0, "exportEvaluations": 0, "examplesChecked": 0, "filesWritten": 0, "pluginRecordsSent": 0, "pluginChecks": 0, "packageModulesParsed": 0 }, "rowsWithNoFile": [] }}schemaVersionis the version of the document.- Each diagnostic has
id, the identity of the problem: the rule, the file, the specifier and the occurrence. It does not hold the line, so it stays the same when the line moves. cycle,groupandchainhold the files of a cycle or of a chain of imports.fixholds a fix that archangel checked, when it has one.severityiserror, orwarningfor a rule withseverity: 'warn'.summary.warningscounts the warnings.summary.unfollowedImportslists each import whose specifier is computed, byfileandline. The text output lists them under the count.summary.workholds the work counts.test --format jsonlists each failed example and each unproven rule underdiagnosticstoo.- When the config stops a command, the JSON document goes to standard output, as each other document does.
explain with a line writes each rule and its verdict:
$ npx archangel explain src/shared/label.ts:1 --format json{ "schemaVersion": 1, "file": "src/shared/label.ts", "line": 1, "imports": [ { "specifier": "../features/cart/total", "line": 1, "target": { "file": "src/features/cart/total.ts" }, "from": { "part": "shared", "instance": [], "kinds": [] }, "to": { "part": "feature", "instance": [ "cart" ], "kinds": [] }, "rules": [ { "rule": "app.feature", "verdict": "skips", "reason": "the file is not in feature", "permittedBy": null }, { "rule": "app.shared", "verdict": "refuses", "reason": "feature is not in its row (shared may import only itself)", "permittedBy": null }, { "rule": "app.every-file-has-a-kind", "verdict": "skips", "reason": "this rule checks files, not imports", "permittedBy": null } ] } ]}why writes the chain:
$ npx archangel why src/shared/label.ts src/features/cart/total.ts --format json{ "schemaVersion": 1, "from": "src/shared/label.ts", "to": "src/features/cart/total.ts", "chain": [ { "file": "src/shared/label.ts", "line": 1, "specifier": "../features/cart/total" } ]}watch --format json writes one line of JSON for each check. Read
Commands.
github
Section titled “github”Writes each problem as a GitHub Actions annotation. GitHub shows it on its line in the pull request.
$ npx archangel check --format github::error file=src/shared/label.ts,line=1,col=23,endColumn=47,title=archangel app.shared::shared may not import feature, through "../features/cart/total": shared may import only itself%0Ahelp: shared may import only itself%0Areason: Shared code never depends on a feature.checked 2 files and 1 imports: 1 problemUse it in a workflow:
- run: npx archangel check --format github- run: npx archangel test --format githubRead Use archangel in CI.
Writes a SARIF 2.1.0 log, for GitHub code scanning or another tool that reads SARIF. The log lists
each diagnostic code as a rule, with the text of archangel docs. Each result has the identity of
its problem, so an alert stays the same when its line moves.
npx archangel check --format sarif > archangel.sarif--stats
Section titled “--stats”Adds the work that archangel did, and the time of each stage. The work counts are:
| Count | What it counts |
|---|---|
| files found, files read, bytes read, files parsed | the source files |
| imports found, resolutions | the imports, and the imports that archangel resolved |
| files classified, pattern passes | the work to find the parts and groups of each file |
| rule evaluations | the times that archangel applied a rule |
| cycle files visited, transitive files visited | the files that the search for cycles and chains visited |
| structure evaluations, folder evaluations, export evaluations | the work of structure, folder and export rules |
| examples checked, files written | the examples of test. files written is always 0. |
| plugin records sent, plugin checks | the work of plugins |
| package modules parsed | the package files that archangel read for the names that a namespace or dynamic import brings in |
The JSON output holds the same counts in summary.work. The times are only in --stats, because a
time changes from run to run.
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 |
The command succeeded, and found no problem, or only warnings. |
1 |
Archangel found a problem, or the answer is no. |
2 |
Archangel could not run: the config, the baseline or the command line has an error. |
A warning does not change the exit code, unless check --max-warnings <count> is given and there
are more warnings than the count: then the check exits with 1.
A config error stops the check before archangel reads the code. It exits with 2:
$ npx archangel checkerror[rule-unknown-element]: rules[0].files: the config declares no part or group "shraed"; did you mean "shared"? the declared names are shared; a kind has a meaning only in its table, and a path pattern has a `/` or a `*`--> archangel.config.json:6:37