flaglint 0.2.1 → 0.2.2
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/CHANGELOG.md +9 -0
- package/dist/bin/flaglint.js +33 -30
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.2] - 2026-05-23
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **Config mutation**: `--exclude-tests` no longer mutates the loaded config object in both `scan` and `migrate` commands — uses spread instead of `push()` so the original config is never modified.
|
|
13
|
+
- **Typed scan warnings**: `ScanResult.warnings` is now a typed `ScanWarning` union (`read-failure` | `parse-failure`) instead of opaque strings, preserving structured data at the domain boundary.
|
|
14
|
+
- **StalenessEvaluator wired**: The `StalenessEvaluator` interface now has a call site in `scan()` — pass an `evaluator` to inject API-based staleness signals without touching core scanner logic.
|
|
15
|
+
- **ScanConfig boundary**: `scan()` now accepts `ScanConfig` (scan-relevant fields only) rather than the full `FlagLintConfig`, decoupling the scanner from CLI output concerns (`reportTitle`, `outputDir`).
|
|
16
|
+
|
|
8
17
|
## [0.2.1] - 2026-05-23
|
|
9
18
|
|
|
10
19
|
### Fixed
|
package/dist/bin/flaglint.js
CHANGED
|
@@ -188,7 +188,7 @@ function detectUsages(ast, filePath, wrappers) {
|
|
|
188
188
|
});
|
|
189
189
|
return usages;
|
|
190
190
|
}
|
|
191
|
-
async function scan(source, config, onProgress) {
|
|
191
|
+
async function scan(source, config, onProgress, evaluator) {
|
|
192
192
|
const start = Date.now();
|
|
193
193
|
for (const pattern of config.include) {
|
|
194
194
|
if (pattern.startsWith("/") || pattern.startsWith("..")) {
|
|
@@ -207,7 +207,7 @@ async function scan(source, config, onProgress) {
|
|
|
207
207
|
code = await source.readFile(file);
|
|
208
208
|
} catch (err) {
|
|
209
209
|
const fsCode = err.code ?? "UNKNOWN";
|
|
210
|
-
return { usages: [], warning:
|
|
210
|
+
return { usages: [], warning: { kind: "read-failure", file, fsCode } };
|
|
211
211
|
}
|
|
212
212
|
let ast;
|
|
213
213
|
try {
|
|
@@ -220,7 +220,7 @@ async function scan(source, config, onProgress) {
|
|
|
220
220
|
filePath: file
|
|
221
221
|
});
|
|
222
222
|
} catch {
|
|
223
|
-
return { usages: [], warning:
|
|
223
|
+
return { usages: [], warning: { kind: "parse-failure", file } };
|
|
224
224
|
}
|
|
225
225
|
return { usages: detectUsages(ast, file, config.wrappers), warning: null };
|
|
226
226
|
}
|
|
@@ -261,6 +261,9 @@ async function scan(source, config, onProgress) {
|
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
|
+
if (evaluator) {
|
|
265
|
+
await evaluator.evaluate(allUsages, config);
|
|
266
|
+
}
|
|
264
267
|
const uniqueFlags = [
|
|
265
268
|
...new Set(
|
|
266
269
|
allUsages.filter((u) => !u.isDynamic && u.flagKey !== "*").map((u) => u.flagKey)
|
|
@@ -404,7 +407,7 @@ function formatHTML(result, options) {
|
|
|
404
407
|
return `<tr class="${cls}"><td><code>${esc(key)}</code></td><td>${data.usages.length}</td><td>${fileList}</td><td>${[...data.callTypes].map(esc).join(", ")}</td><td>${status}</td></tr>`;
|
|
405
408
|
}).join("\n ");
|
|
406
409
|
const title = options.title ? esc(options.title) : "FlagLint Scan Report";
|
|
407
|
-
const version = true ? "0.2.
|
|
410
|
+
const version = true ? "0.2.2" : "0.1.0";
|
|
408
411
|
return `<!DOCTYPE html>
|
|
409
412
|
<html lang="en">
|
|
410
413
|
<head>
|
|
@@ -585,16 +588,15 @@ Examples:
|
|
|
585
588
|
process.stderr.write(chalk.red(String(err instanceof Error ? err.message : err)) + "\n");
|
|
586
589
|
process.exit(1);
|
|
587
590
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
}
|
|
591
|
+
const TEST_PATTERNS = [
|
|
592
|
+
"**/*.test.ts",
|
|
593
|
+
"**/*.test.tsx",
|
|
594
|
+
"**/*.spec.ts",
|
|
595
|
+
"**/*.spec.tsx",
|
|
596
|
+
"**/__tests__/**",
|
|
597
|
+
"**/tests/**"
|
|
598
|
+
];
|
|
599
|
+
const scanConfig = options.excludeTests ? { ...config, exclude: [...config.exclude, ...TEST_PATTERNS] } : config;
|
|
598
600
|
const format = options.format;
|
|
599
601
|
const spinner = ora(`Scanning ${dir}...`).start();
|
|
600
602
|
process.once("SIGINT", () => {
|
|
@@ -604,7 +606,7 @@ Examples:
|
|
|
604
606
|
let lastSpinnerUpdate = 0;
|
|
605
607
|
let result;
|
|
606
608
|
try {
|
|
607
|
-
result = await scan(new LocalFileSource(dir),
|
|
609
|
+
result = await scan(new LocalFileSource(dir), scanConfig, (filesScanned) => {
|
|
608
610
|
if (filesScanned - lastSpinnerUpdate >= 50) {
|
|
609
611
|
spinner.text = `Scanning... (${filesScanned} files)`;
|
|
610
612
|
lastSpinnerUpdate = filesScanned;
|
|
@@ -617,7 +619,8 @@ Examples:
|
|
|
617
619
|
process.exit(1);
|
|
618
620
|
}
|
|
619
621
|
for (const w of result.warnings) {
|
|
620
|
-
|
|
622
|
+
const msg = w.kind === "read-failure" ? `warn: could not read ${w.file} (${w.fsCode})` : `warn: failed to parse ${w.file}`;
|
|
623
|
+
process.stderr.write(chalk.yellow(msg + "\n"));
|
|
621
624
|
}
|
|
622
625
|
if (result.scannedFiles === 0) {
|
|
623
626
|
process.stderr.write(
|
|
@@ -824,7 +827,7 @@ function analyze(result) {
|
|
|
824
827
|
function formatMigrationReport(analysis) {
|
|
825
828
|
const { readinessScore, requiredPackages, items, manualReviewCount, autoMigrateCount } = analysis;
|
|
826
829
|
const date = (/* @__PURE__ */ new Date()).toLocaleDateString();
|
|
827
|
-
const version = true ? "0.2.
|
|
830
|
+
const version = true ? "0.2.2" : "0.1.0";
|
|
828
831
|
let scoreLabel;
|
|
829
832
|
if (readinessScore >= 80) scoreLabel = "\u2713 Your codebase is ready for migration";
|
|
830
833
|
else if (readinessScore >= 50) scoreLabel = "\u26A0 Some manual work required before migration";
|
|
@@ -937,16 +940,15 @@ Examples:
|
|
|
937
940
|
process.stderr.write(chalk2.red(String(err instanceof Error ? err.message : err)) + "\n");
|
|
938
941
|
process.exit(1);
|
|
939
942
|
}
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
}
|
|
943
|
+
const TEST_PATTERNS = [
|
|
944
|
+
"**/*.test.ts",
|
|
945
|
+
"**/*.test.tsx",
|
|
946
|
+
"**/*.spec.ts",
|
|
947
|
+
"**/*.spec.tsx",
|
|
948
|
+
"**/__tests__/**",
|
|
949
|
+
"**/tests/**"
|
|
950
|
+
];
|
|
951
|
+
const scanConfig = options.excludeTests ? { ...config, exclude: [...config.exclude, ...TEST_PATTERNS] } : config;
|
|
950
952
|
const spinner = ora2(`Scanning ${dir}...`).start();
|
|
951
953
|
process.once("SIGINT", () => {
|
|
952
954
|
spinner.stop();
|
|
@@ -954,7 +956,7 @@ Examples:
|
|
|
954
956
|
});
|
|
955
957
|
let scanResult;
|
|
956
958
|
try {
|
|
957
|
-
scanResult = await scan(new LocalFileSource(dir),
|
|
959
|
+
scanResult = await scan(new LocalFileSource(dir), scanConfig, (filesScanned) => {
|
|
958
960
|
spinner.text = `Scanning files... ${filesScanned}`;
|
|
959
961
|
});
|
|
960
962
|
spinner.text = "Analyzing migration readiness...";
|
|
@@ -983,7 +985,8 @@ Examples:
|
|
|
983
985
|
const analysis = analyze(scanResult);
|
|
984
986
|
spinner.stop();
|
|
985
987
|
for (const w of scanResult.warnings) {
|
|
986
|
-
|
|
988
|
+
const msg = w.kind === "read-failure" ? `warn: could not read ${w.file} (${w.fsCode})` : `warn: failed to parse ${w.file}`;
|
|
989
|
+
process.stderr.write(chalk2.yellow(msg + "\n"));
|
|
987
990
|
}
|
|
988
991
|
const { readinessScore } = analysis;
|
|
989
992
|
const scoreColor = readinessScore >= 80 ? chalk2.green : readinessScore >= 50 ? chalk2.yellow : chalk2.red;
|
|
@@ -1022,7 +1025,7 @@ Examples:
|
|
|
1022
1025
|
// src/cli.ts
|
|
1023
1026
|
function createCLI() {
|
|
1024
1027
|
const program2 = new Command();
|
|
1025
|
-
program2.name("flaglint").description("Find stale feature flags. Detect flag debt. Plan your OpenFeature migration.").version("0.2.
|
|
1028
|
+
program2.name("flaglint").description("Find stale feature flags. Detect flag debt. Plan your OpenFeature migration.").version("0.2.2", "-v, --version", "output the current version").addHelpText(
|
|
1026
1029
|
"after",
|
|
1027
1030
|
`
|
|
1028
1031
|
Examples:
|