flamerjs 0.1.6 → 1.0.0
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 +43 -18
- package/dist/cli.js +80 -2
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -52,12 +52,18 @@ can be used locally, in pull requests, or in CI.
|
|
|
52
52
|
C#, Zig, SQL, notebooks, and additional language profiles.
|
|
53
53
|
- **Stable JSON output:** suitable for CI annotations and other automation.
|
|
54
54
|
- **Single-pass scanning:** files are walked once and content is read once.
|
|
55
|
+
- **Optional native workers:** Rust and C++ workers for isolated file metrics,
|
|
56
|
+
with TypeScript remaining the default engine.
|
|
55
57
|
|
|
56
58
|
## Requirements
|
|
57
59
|
|
|
58
60
|
- Node.js 18 or newer
|
|
59
61
|
- npm
|
|
60
62
|
|
|
63
|
+
The default TypeScript engine needs only Node.js and npm. Native mode additionally
|
|
64
|
+
requires Rust/Cargo for the Rust worker or a C++17 compiler and CMake for the
|
|
65
|
+
C++ worker.
|
|
66
|
+
|
|
61
67
|
## Quick start
|
|
62
68
|
|
|
63
69
|
Run the published CLI without installing it permanently:
|
|
@@ -101,23 +107,24 @@ flamerjs /path/to/repository --format summary
|
|
|
101
107
|
flamerjs [path] [options]
|
|
102
108
|
```
|
|
103
109
|
|
|
104
|
-
| Option
|
|
105
|
-
|
|
|
106
|
-
| `--package, --scope <name>`
|
|
107
|
-
| `--path <dir>`
|
|
108
|
-
| `--format <json\|summary>`
|
|
109
|
-
| `--out <file>`
|
|
110
|
-
| `--fail-on <SEVERITY>`
|
|
111
|
-
| `--max-files <n>`
|
|
112
|
-
| `--commit-limit <n>`
|
|
113
|
-
| `--no-git`
|
|
114
|
-
| `--no-lockfile-warning`
|
|
115
|
-
| `--ignore-dir <name>`
|
|
116
|
-
| `--quiet`
|
|
117
|
-
| `--color`
|
|
118
|
-
| `--no-color`
|
|
119
|
-
| `--
|
|
120
|
-
| `--
|
|
110
|
+
| Option | Description |
|
|
111
|
+
| ------------------------------------- | ----------------------------------------------------------------------------- |
|
|
112
|
+
| `--package, --scope <name>` | Analyze only a named sub-project |
|
|
113
|
+
| `--path <dir>` | Set the repository root; defaults to the current directory |
|
|
114
|
+
| `--format <json\|summary>` | Select JSON or human-readable output; summary is the default |
|
|
115
|
+
| `--out <file>` | Also write the JSON report to a file |
|
|
116
|
+
| `--fail-on <SEVERITY>` | Exit with status 1 at or above `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, or `INFO` |
|
|
117
|
+
| `--max-files <n>` | Limit the number of files scanned |
|
|
118
|
+
| `--commit-limit <n>` | Limit commits inspected by Git checks |
|
|
119
|
+
| `--no-git` | Skip Git analysis |
|
|
120
|
+
| `--no-lockfile-warning` | Suppress the missing-lockfile suggestion |
|
|
121
|
+
| `--ignore-dir <name>` | Ignore an additional directory name; repeatable |
|
|
122
|
+
| `--quiet` | Suppress the human summary |
|
|
123
|
+
| `--color` | Force ANSI colors |
|
|
124
|
+
| `--no-color` | Disable ANSI colors |
|
|
125
|
+
| `--engine <typescript\|native\|auto>` | Select the scan engine; TypeScript is the default |
|
|
126
|
+
| `--list-languages` | List recognized language profiles |
|
|
127
|
+
| `--help` | Show command help |
|
|
121
128
|
|
|
122
129
|
Exit status `0` means the scan completed; findings may still exist. Status `1`
|
|
123
130
|
means `--fail-on` was reached, and status `2` indicates invalid usage or a
|
|
@@ -170,12 +177,30 @@ The project uses Node.js and npm as its supported development toolchain.
|
|
|
170
177
|
`package-lock.json` is the canonical dependency lockfile.
|
|
171
178
|
The current test suite contains **175 tests**.
|
|
172
179
|
|
|
180
|
+
### Optional native engine
|
|
181
|
+
|
|
182
|
+
Flamer includes an experimental Rust worker for native file metrics. It is
|
|
183
|
+
disabled by default and does not change findings:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npm run native:build
|
|
187
|
+
node dist/cli.js . --engine native
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Use `--engine auto` to fall back to TypeScript when the worker is unavailable.
|
|
191
|
+
The native protocol and worker details are documented in
|
|
192
|
+
[`native/core/README.md`](native/core/README.md).
|
|
193
|
+
|
|
194
|
+
See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the runtime layers,
|
|
195
|
+
worker protocol, engine selection, and native development workflow.
|
|
196
|
+
|
|
173
197
|
## How it works
|
|
174
198
|
|
|
175
199
|
1. Detect the repository layout, languages, and ecosystems.
|
|
176
200
|
2. Walk the tree once and collect file metadata and content-derived signals.
|
|
177
201
|
3. Run isolated analyzers against the collected records.
|
|
178
|
-
4.
|
|
202
|
+
4. Optionally collect native file metrics through the versioned worker protocol.
|
|
203
|
+
5. Sort findings and emit JSON or a concise summary.
|
|
179
204
|
|
|
180
205
|
Analyzers are intentionally factual and conservative. A finding should identify
|
|
181
206
|
something actionable rather than merely express a preference.
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { writeFileSync, existsSync as
|
|
4
|
+
import { writeFileSync, existsSync as existsSync4 } from "fs";
|
|
5
5
|
import { resolve, basename } from "path";
|
|
6
6
|
|
|
7
7
|
// src/util/fs.ts
|
|
@@ -2901,6 +2901,42 @@ var ANALYZERS = [
|
|
|
2901
2901
|
{ id: "systems", label: "Rust / Go / C / C++ / C# / Zig", fn: analyze6 }
|
|
2902
2902
|
];
|
|
2903
2903
|
|
|
2904
|
+
// src/native.ts
|
|
2905
|
+
import { spawnSync } from "child_process";
|
|
2906
|
+
import { existsSync as existsSync3 } from "fs";
|
|
2907
|
+
import { join as join6 } from "path";
|
|
2908
|
+
function nativeWorkerPath(root) {
|
|
2909
|
+
const configured = process.env.FLAMER_CORE;
|
|
2910
|
+
if (configured) return configured;
|
|
2911
|
+
return join6(root, "native", "core", "rust", "target", "release", "flamer-core");
|
|
2912
|
+
}
|
|
2913
|
+
function runNativeMetrics(root, files) {
|
|
2914
|
+
const worker = nativeWorkerPath(root);
|
|
2915
|
+
if (!existsSync3(worker)) {
|
|
2916
|
+
throw new Error(`native worker not found at ${worker}; run npm run native:build`);
|
|
2917
|
+
}
|
|
2918
|
+
const request = JSON.stringify({ protocol: 1, operation: "file_metrics", root, files });
|
|
2919
|
+
const result = spawnSync(worker, { input: `${request}
|
|
2920
|
+
`, encoding: "utf8", timeout: 3e4 });
|
|
2921
|
+
if (result.error) throw new Error(`native worker failed: ${result.error.message}`);
|
|
2922
|
+
if (result.status !== 0) {
|
|
2923
|
+
throw new Error(`native worker exited with status ${result.status}: ${result.stderr.trim()}`);
|
|
2924
|
+
}
|
|
2925
|
+
let response;
|
|
2926
|
+
try {
|
|
2927
|
+
response = JSON.parse(result.stdout);
|
|
2928
|
+
} catch {
|
|
2929
|
+
throw new Error("native worker returned invalid JSON");
|
|
2930
|
+
}
|
|
2931
|
+
if (response.protocol !== 1 || response.operation !== "file_metrics") {
|
|
2932
|
+
throw new Error("native worker returned an incompatible response");
|
|
2933
|
+
}
|
|
2934
|
+
if (!response.ok) {
|
|
2935
|
+
throw new Error(response.errors.map((error) => `${error.path}: ${error.message}`).join("; "));
|
|
2936
|
+
}
|
|
2937
|
+
return response;
|
|
2938
|
+
}
|
|
2939
|
+
|
|
2904
2940
|
// src/cli.ts
|
|
2905
2941
|
var SPEC_VERSION = 1;
|
|
2906
2942
|
function parseArgs(argv) {
|
|
@@ -2918,6 +2954,7 @@ function parseArgs(argv) {
|
|
|
2918
2954
|
listLanguages: false,
|
|
2919
2955
|
help: false,
|
|
2920
2956
|
color: null,
|
|
2957
|
+
engine: "typescript",
|
|
2921
2958
|
ignoreDirs: []
|
|
2922
2959
|
};
|
|
2923
2960
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -2963,6 +3000,14 @@ function parseArgs(argv) {
|
|
|
2963
3000
|
case "--no-color":
|
|
2964
3001
|
opts.color = false;
|
|
2965
3002
|
break;
|
|
3003
|
+
case "--engine":
|
|
3004
|
+
opts.engine = argv[++i] || "typescript";
|
|
3005
|
+
if (!["typescript", "native", "auto"].includes(opts.engine)) {
|
|
3006
|
+
process.stderr.write(`invalid engine: ${opts.engine}
|
|
3007
|
+
`);
|
|
3008
|
+
process.exit(2);
|
|
3009
|
+
}
|
|
3010
|
+
break;
|
|
2966
3011
|
case "--list-languages":
|
|
2967
3012
|
opts.listLanguages = true;
|
|
2968
3013
|
break;
|
|
@@ -3004,6 +3049,8 @@ Options:
|
|
|
3004
3049
|
--quiet suppress the human summary
|
|
3005
3050
|
--color force ANSI colors
|
|
3006
3051
|
--no-color disable ANSI colors
|
|
3052
|
+
--engine <typescript|native|auto>
|
|
3053
|
+
choose the scan engine (default: typescript)
|
|
3007
3054
|
--list-languages print the supported language table
|
|
3008
3055
|
-h, --help show this help
|
|
3009
3056
|
`);
|
|
@@ -3023,7 +3070,7 @@ ${allExtensions().length} file extensions recognized.
|
|
|
3023
3070
|
function run2(opts) {
|
|
3024
3071
|
const started = Date.now();
|
|
3025
3072
|
const root = opts.root;
|
|
3026
|
-
if (!
|
|
3073
|
+
if (!existsSync4(root) || !isDir(root)) {
|
|
3027
3074
|
const err = {
|
|
3028
3075
|
specVersion: SPEC_VERSION,
|
|
3029
3076
|
tool: "flamer",
|
|
@@ -3161,6 +3208,37 @@ function run2(opts) {
|
|
|
3161
3208
|
analyzers: analyzerResults
|
|
3162
3209
|
}
|
|
3163
3210
|
};
|
|
3211
|
+
if (opts.engine !== "typescript") {
|
|
3212
|
+
try {
|
|
3213
|
+
const native = runNativeMetrics(
|
|
3214
|
+
root,
|
|
3215
|
+
scopedFiles.map((file) => file.rel)
|
|
3216
|
+
);
|
|
3217
|
+
report.metadata.native = {
|
|
3218
|
+
engine: "rust",
|
|
3219
|
+
files: native.metrics.files,
|
|
3220
|
+
bytes: native.metrics.bytes,
|
|
3221
|
+
lines: native.metrics.lines,
|
|
3222
|
+
durationMs: native.duration_ms
|
|
3223
|
+
};
|
|
3224
|
+
} catch (error) {
|
|
3225
|
+
const message = error?.message || String(error);
|
|
3226
|
+
if (opts.engine === "native") {
|
|
3227
|
+
findings.push(
|
|
3228
|
+
finding({
|
|
3229
|
+
category: "error",
|
|
3230
|
+
severity: "CRITICAL",
|
|
3231
|
+
title: "Native engine failed",
|
|
3232
|
+
detail: message
|
|
3233
|
+
})
|
|
3234
|
+
);
|
|
3235
|
+
report.findings = sortFindings(findings);
|
|
3236
|
+
report.metadata.native = { engine: "rust", error: message };
|
|
3237
|
+
return { report, exitCode: 2 };
|
|
3238
|
+
}
|
|
3239
|
+
report.metadata.native = { engine: "typescript", fallback: message };
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3164
3242
|
let exitCode = 0;
|
|
3165
3243
|
if (opts.failOn && report.metadata.worst && rank(report.metadata.worst) <= rank(opts.failOn)) {
|
|
3166
3244
|
exitCode = 1;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flamerjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Language-agnostic code health auditor that walks a repository once and reports what is wrong with it",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "tsup",
|
|
27
27
|
"dev": "tsup --watch",
|
|
28
|
+
"native:build": "cargo build --release --manifest-path native/core/rust/Cargo.toml",
|
|
29
|
+
"native:test": "cargo test --manifest-path native/core/rust/Cargo.toml",
|
|
28
30
|
"prepublishOnly": "npm run lint && npm run build && npm test",
|
|
29
31
|
"lint": "eslint .",
|
|
30
32
|
"lint:fix": "eslint . --fix",
|