ng-health 0.1.0 → 0.2.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 +1 -0
- package/dist/{chunk-K5BPGSW7.js → chunk-T4EN6LCY.js} +179 -57
- package/dist/chunk-T4EN6LCY.js.map +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-K5BPGSW7.js.map +0 -1
package/README.md
CHANGED
|
@@ -155,6 +155,7 @@ All types are exported: `AuditResult`, `AuditOptions`, `Finding`, `Check`, `Chec
|
|
|
155
155
|
| `dependencies/outdated` | dependencies | Major / minor / patch gaps of direct dependencies; TypeScript and Angular-lockstep packages (`@ngrx/*`, `@angular-architects/*`, angular-eslint) are judged against your Angular version | |
|
|
156
156
|
| `dependencies/vulnerabilities` | dependencies | `npm`/`pnpm audit` results by severity, with the fix for each | |
|
|
157
157
|
| `dependencies/deprecated` | dependencies | Deprecated packages (npm registry plus a built-in list: tslint, protractor…) | |
|
|
158
|
+
| `dependencies/peer-conflicts` | dependencies | Direct dependencies whose peer dependencies are missing or out of range (the cause of npm `ERESOLVE` / `--legacy-peer-deps`), with the newest compatible version when online | |
|
|
158
159
|
| `bundle/size` | bundle | Initial/lazy sizes vs `angular.json` budgets, the 10 largest modules | `build`, `maxLazyChunkKb` (250), `project`, `outputPath` |
|
|
159
160
|
| `angular/onpush` | angular | Components without OnPush (or opting out with `Eager` on Angular 22+) | |
|
|
160
161
|
| `angular/template-calls` | angular | Method calls in template bindings (zero-argument signal reads are fine) | |
|
|
@@ -52,7 +52,7 @@ function errorMessage(err) {
|
|
|
52
52
|
// package.json
|
|
53
53
|
var package_default = {
|
|
54
54
|
name: "ng-health",
|
|
55
|
-
version: "0.
|
|
55
|
+
version: "0.2.0",
|
|
56
56
|
description: "Audit Angular codebases and produce a scored, actionable health report. CLI and library.",
|
|
57
57
|
keywords: [
|
|
58
58
|
"angular",
|
|
@@ -109,7 +109,7 @@ var package_default = {
|
|
|
109
109
|
prepublishOnly: "npm run build",
|
|
110
110
|
changeset: "changeset",
|
|
111
111
|
"version-packages": "changeset version",
|
|
112
|
-
release: "npm run build &&
|
|
112
|
+
release: "npm run build && node scripts/stage-release.mjs",
|
|
113
113
|
smoke: "node scripts/smoke.mjs"
|
|
114
114
|
},
|
|
115
115
|
dependencies: {
|
|
@@ -197,7 +197,7 @@ function buildReport(input) {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
// src/core/audit.ts
|
|
200
|
-
import
|
|
200
|
+
import path21 from "path";
|
|
201
201
|
|
|
202
202
|
// src/runtime/session.ts
|
|
203
203
|
import path3 from "path";
|
|
@@ -1838,6 +1838,127 @@ async function installedOrDeclared(ctx, name, pkg) {
|
|
|
1838
1838
|
return min?.version;
|
|
1839
1839
|
}
|
|
1840
1840
|
|
|
1841
|
+
// src/checks/dependencies/peer-conflicts.ts
|
|
1842
|
+
import { realpath } from "fs/promises";
|
|
1843
|
+
import path10 from "path";
|
|
1844
|
+
import semver3 from "semver";
|
|
1845
|
+
var satisfies = (version, range) => semver3.satisfies(version, range, { includePrerelease: true, loose: true });
|
|
1846
|
+
async function resolveInstalled(fromDir, name) {
|
|
1847
|
+
for (let dir = fromDir; ; dir = path10.dirname(dir)) {
|
|
1848
|
+
if (path10.basename(dir) !== "node_modules") {
|
|
1849
|
+
const manifest = await readJsonFile(
|
|
1850
|
+
path10.join(dir, "node_modules", name, "package.json")
|
|
1851
|
+
).catch(() => void 0);
|
|
1852
|
+
if (manifest?.version) return manifest;
|
|
1853
|
+
}
|
|
1854
|
+
if (path10.dirname(dir) === dir) return void 0;
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
async function findPeerConflicts(ctx) {
|
|
1858
|
+
const conflicts = [];
|
|
1859
|
+
for (const dep of directDependencies(await readPackageJson(ctx))) {
|
|
1860
|
+
const pkgDir = path10.join(ctx.root, "node_modules", dep.name);
|
|
1861
|
+
const manifest = await readJsonFile(path10.join(pkgDir, "package.json")).catch(
|
|
1862
|
+
() => void 0
|
|
1863
|
+
);
|
|
1864
|
+
if (!manifest?.version || !manifest.peerDependencies) continue;
|
|
1865
|
+
const realDir = await realpath(pkgDir).catch(() => pkgDir);
|
|
1866
|
+
for (const [peer, range] of Object.entries(manifest.peerDependencies)) {
|
|
1867
|
+
if (!semver3.validRange(range, { loose: true })) continue;
|
|
1868
|
+
const optional = manifest.peerDependenciesMeta?.[peer]?.optional === true;
|
|
1869
|
+
const installed = await resolveInstalled(realDir, peer);
|
|
1870
|
+
if (!installed?.version) {
|
|
1871
|
+
if (!optional)
|
|
1872
|
+
conflicts.push({
|
|
1873
|
+
name: dep.name,
|
|
1874
|
+
version: manifest.version,
|
|
1875
|
+
peer,
|
|
1876
|
+
range,
|
|
1877
|
+
installed: void 0,
|
|
1878
|
+
optional
|
|
1879
|
+
});
|
|
1880
|
+
continue;
|
|
1881
|
+
}
|
|
1882
|
+
if (!satisfies(installed.version, range)) {
|
|
1883
|
+
conflicts.push({
|
|
1884
|
+
name: dep.name,
|
|
1885
|
+
version: manifest.version,
|
|
1886
|
+
peer,
|
|
1887
|
+
range,
|
|
1888
|
+
installed: installed.version,
|
|
1889
|
+
optional
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
return conflicts.sort((a, b) => a.name.localeCompare(b.name) || a.peer.localeCompare(b.peer));
|
|
1895
|
+
}
|
|
1896
|
+
function compatibleVersion(versions, installedPeers) {
|
|
1897
|
+
return versions.filter((v) => semver3.valid(v.version) && !semver3.prerelease(v.version)).filter(
|
|
1898
|
+
(v) => Object.entries(v.peerDependencies ?? {}).every(([peer, range]) => {
|
|
1899
|
+
const have = installedPeers[peer];
|
|
1900
|
+
return have === void 0 || !semver3.validRange(range, { loose: true }) || satisfies(have, range);
|
|
1901
|
+
})
|
|
1902
|
+
).map((v) => v.version).sort(semver3.rcompare)[0];
|
|
1903
|
+
}
|
|
1904
|
+
async function suggestVersion(ctx, conflict, installedPeers) {
|
|
1905
|
+
if (ctx.offline) return void 0;
|
|
1906
|
+
try {
|
|
1907
|
+
const r = await ctx.exec("npm", [
|
|
1908
|
+
"view",
|
|
1909
|
+
`${conflict.name}@>=0.0.0`,
|
|
1910
|
+
"version",
|
|
1911
|
+
"peerDependencies",
|
|
1912
|
+
"--json"
|
|
1913
|
+
]);
|
|
1914
|
+
const parsed = r.exitCode === 0 ? parseJsonOutput(r.stdout) : void 0;
|
|
1915
|
+
const list = Array.isArray(parsed) ? parsed : parsed ? [parsed] : [];
|
|
1916
|
+
return compatibleVersion(
|
|
1917
|
+
list,
|
|
1918
|
+
installedPeers
|
|
1919
|
+
);
|
|
1920
|
+
} catch (err) {
|
|
1921
|
+
ctx.logger.debug(`npm view ${conflict.name} failed: ${String(err)}`);
|
|
1922
|
+
return void 0;
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
var severityFor = (c) => {
|
|
1926
|
+
if (c.optional) return "low";
|
|
1927
|
+
return /^(@angular\/|rxjs$|typescript$|zone\.js$)/.test(c.peer) ? "high" : "medium";
|
|
1928
|
+
};
|
|
1929
|
+
var peer_conflicts_default = defineCheck({
|
|
1930
|
+
id: "dependencies/peer-conflicts",
|
|
1931
|
+
name: "Peer dependency conflicts",
|
|
1932
|
+
category: "dependencies",
|
|
1933
|
+
description: "Direct dependencies whose peer dependencies are missing or outside the required range (the cause of npm ERESOLVE errors and --legacy-peer-deps installs).",
|
|
1934
|
+
timeoutMs: 12e4,
|
|
1935
|
+
async run(ctx) {
|
|
1936
|
+
if (!await pathExists(path10.join(ctx.root, "node_modules"))) {
|
|
1937
|
+
skipCheck(
|
|
1938
|
+
"Dependencies are not installed (run npm install first): peer ranges are read from node_modules"
|
|
1939
|
+
);
|
|
1940
|
+
}
|
|
1941
|
+
const conflicts = await findPeerConflicts(ctx);
|
|
1942
|
+
const installedPeers = {};
|
|
1943
|
+
for (const c of conflicts) if (c.installed) installedPeers[c.peer] = c.installed;
|
|
1944
|
+
const findings = [];
|
|
1945
|
+
for (const c of conflicts) {
|
|
1946
|
+
const suggestion = await suggestVersion(ctx, c, installedPeers);
|
|
1947
|
+
const problem = c.installed ? `${c.name} ${c.version} requires ${c.peer} ${c.range}, but ${c.installed} is installed.` : `${c.name} ${c.version} requires ${c.peer} ${c.range}, which is not installed.`;
|
|
1948
|
+
const fix = suggestion ? suggestion === c.version ? `Reinstall to fix the tree, or align ${c.peer} with ${c.range}.` : `Install a compatible version: npm install ${c.name}@${suggestion} (or upgrade ${c.peer} to ${c.range}).` : c.installed ? `Install a ${c.name} version whose peer range accepts ${c.peer} ${c.installed}, or upgrade ${c.peer} to match ${c.range}.` : `Install ${c.peer} (${c.range}) or remove ${c.name}.`;
|
|
1949
|
+
findings.push({
|
|
1950
|
+
severity: severityFor(c),
|
|
1951
|
+
ruleId: c.installed ? "peer-version-mismatch" : "peer-missing",
|
|
1952
|
+
message: problem,
|
|
1953
|
+
fixHint: `${fix} Mismatched peers make npm install fail with ERESOLVE and are often hidden with --legacy-peer-deps.`,
|
|
1954
|
+
file: "package.json",
|
|
1955
|
+
docsUrl: "https://docs.npmjs.com/cli/configuring-npm/package-json#peerdependencies"
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
return { findings, meta: { conflicts } };
|
|
1959
|
+
}
|
|
1960
|
+
});
|
|
1961
|
+
|
|
1841
1962
|
// src/checks/dependencies/vulnerabilities.ts
|
|
1842
1963
|
var SEVERITY = {
|
|
1843
1964
|
critical: "critical",
|
|
@@ -1915,7 +2036,7 @@ var vulnerabilities_default = defineCheck({
|
|
|
1915
2036
|
});
|
|
1916
2037
|
|
|
1917
2038
|
// src/checks/hygiene/coverage.ts
|
|
1918
|
-
import
|
|
2039
|
+
import path11 from "path";
|
|
1919
2040
|
import fg from "fast-glob";
|
|
1920
2041
|
function lcovLinePct(text) {
|
|
1921
2042
|
let found = 0;
|
|
@@ -1942,7 +2063,7 @@ var coverage_default = defineCheck({
|
|
|
1942
2063
|
let pct2;
|
|
1943
2064
|
let source;
|
|
1944
2065
|
if (summaryFile) {
|
|
1945
|
-
const raw = (await readJsonFile(
|
|
2066
|
+
const raw = (await readJsonFile(path11.join(ctx.root, summaryFile)))?.total?.lines?.pct;
|
|
1946
2067
|
pct2 = typeof raw === "number" ? raw : raw !== void 0 && !Number.isNaN(Number(raw)) ? Number(raw) : void 0;
|
|
1947
2068
|
source = summaryFile;
|
|
1948
2069
|
}
|
|
@@ -2012,7 +2133,7 @@ var tests_default = defineCheck({
|
|
|
2012
2133
|
});
|
|
2013
2134
|
|
|
2014
2135
|
// src/checks/hygiene/tooling.ts
|
|
2015
|
-
import
|
|
2136
|
+
import path12 from "path";
|
|
2016
2137
|
var ESLINT_FILES = [
|
|
2017
2138
|
"eslint.config.js",
|
|
2018
2139
|
"eslint.config.mjs",
|
|
@@ -2041,7 +2162,7 @@ var PRETTIER_FILES = [
|
|
|
2041
2162
|
"prettier.config.ts"
|
|
2042
2163
|
];
|
|
2043
2164
|
async function firstExisting(root, files) {
|
|
2044
|
-
for (const f of files) if (await pathExists(
|
|
2165
|
+
for (const f of files) if (await pathExists(path12.join(root, f))) return f;
|
|
2045
2166
|
return void 0;
|
|
2046
2167
|
}
|
|
2047
2168
|
var tooling_default = defineCheck({
|
|
@@ -2050,12 +2171,12 @@ var tooling_default = defineCheck({
|
|
|
2050
2171
|
category: "hygiene",
|
|
2051
2172
|
description: "ESLint (with angular-eslint) and Prettier are configured.",
|
|
2052
2173
|
async run(ctx) {
|
|
2053
|
-
const pkg = await readJsonFile(
|
|
2174
|
+
const pkg = await readJsonFile(path12.join(ctx.root, "package.json")) ?? {};
|
|
2054
2175
|
const deps = await readPackageJson(ctx);
|
|
2055
2176
|
const all = { ...deps.dependencies, ...deps.devDependencies };
|
|
2056
2177
|
const eslint = await firstExisting(ctx.root, ESLINT_FILES) ?? ("eslintConfig" in pkg ? "package.json" : void 0);
|
|
2057
2178
|
const prettier = await firstExisting(ctx.root, PRETTIER_FILES) ?? ("prettier" in pkg ? "package.json" : void 0);
|
|
2058
|
-
const tslint = await pathExists(
|
|
2179
|
+
const tslint = await pathExists(path12.join(ctx.root, "tslint.json"));
|
|
2059
2180
|
const angularEslint = Object.keys(all).some(
|
|
2060
2181
|
(d) => d === "angular-eslint" || d.startsWith("@angular-eslint/")
|
|
2061
2182
|
);
|
|
@@ -2104,8 +2225,8 @@ var tooling_default = defineCheck({
|
|
|
2104
2225
|
});
|
|
2105
2226
|
|
|
2106
2227
|
// src/checks/hygiene/typescript-strict.ts
|
|
2107
|
-
import
|
|
2108
|
-
import
|
|
2228
|
+
import path13 from "path";
|
|
2229
|
+
import semver4 from "semver";
|
|
2109
2230
|
var STRICT_FAMILY = [
|
|
2110
2231
|
"noImplicitAny",
|
|
2111
2232
|
"strictNullChecks",
|
|
@@ -2122,7 +2243,7 @@ async function loadTsConfig(file, depth = 0) {
|
|
|
2122
2243
|
const parents = (Array.isArray(config.extends) ? config.extends : config.extends ? [config.extends] : []).filter((e) => e.startsWith("."));
|
|
2123
2244
|
let merged = {};
|
|
2124
2245
|
for (const parent of parents) {
|
|
2125
|
-
const base2 = await loadTsConfig(
|
|
2246
|
+
const base2 = await loadTsConfig(path13.resolve(path13.dirname(file), parent), depth + 1);
|
|
2126
2247
|
if (base2) {
|
|
2127
2248
|
merged = {
|
|
2128
2249
|
compilerOptions: { ...merged.compilerOptions, ...base2.compilerOptions },
|
|
@@ -2140,10 +2261,10 @@ async function loadTsConfig(file, depth = 0) {
|
|
|
2140
2261
|
}
|
|
2141
2262
|
async function typescriptMajor(root, declared) {
|
|
2142
2263
|
const installed = (await readJsonFile(
|
|
2143
|
-
|
|
2264
|
+
path13.join(root, "node_modules/typescript/package.json")
|
|
2144
2265
|
))?.version;
|
|
2145
|
-
if (installed &&
|
|
2146
|
-
const min = declared &&
|
|
2266
|
+
if (installed && semver4.valid(installed)) return semver4.major(installed);
|
|
2267
|
+
const min = declared && semver4.validRange(declared) ? semver4.minVersion(declared) : null;
|
|
2147
2268
|
return min?.major;
|
|
2148
2269
|
}
|
|
2149
2270
|
var typescript_strict_default = defineCheck({
|
|
@@ -2156,7 +2277,7 @@ var typescript_strict_default = defineCheck({
|
|
|
2156
2277
|
let file;
|
|
2157
2278
|
let config;
|
|
2158
2279
|
for (const f of appTsconfig) {
|
|
2159
|
-
config = await loadTsConfig(
|
|
2280
|
+
config = await loadTsConfig(path13.join(ctx.root, f));
|
|
2160
2281
|
if (config) {
|
|
2161
2282
|
file = f;
|
|
2162
2283
|
break;
|
|
@@ -2394,6 +2515,7 @@ var builtinChecks = [
|
|
|
2394
2515
|
outdated_default,
|
|
2395
2516
|
vulnerabilities_default,
|
|
2396
2517
|
deprecated_default,
|
|
2518
|
+
peer_conflicts_default,
|
|
2397
2519
|
size_default,
|
|
2398
2520
|
onpush_default,
|
|
2399
2521
|
template_calls_default,
|
|
@@ -2413,10 +2535,10 @@ var builtinChecks = [
|
|
|
2413
2535
|
];
|
|
2414
2536
|
|
|
2415
2537
|
// src/core/baseline.ts
|
|
2416
|
-
import
|
|
2538
|
+
import path14 from "path";
|
|
2417
2539
|
var delta = (before, after) => before === void 0 || after === void 0 ? void 0 : after - before;
|
|
2418
2540
|
async function loadBaseline(file) {
|
|
2419
|
-
const abs =
|
|
2541
|
+
const abs = path14.resolve(file);
|
|
2420
2542
|
const raw = await readJsonFile(abs);
|
|
2421
2543
|
if (!raw) throw new ConfigError(`Baseline report not found: ${abs}`);
|
|
2422
2544
|
if (typeof raw.schemaVersion !== "string" || !raw.schemaVersion.startsWith("1.")) {
|
|
@@ -2467,7 +2589,7 @@ function computeTrend(baseline, current) {
|
|
|
2467
2589
|
}
|
|
2468
2590
|
|
|
2469
2591
|
// src/core/config/loader.ts
|
|
2470
|
-
import
|
|
2592
|
+
import path15 from "path";
|
|
2471
2593
|
function formatZodIssues(error) {
|
|
2472
2594
|
return error.issues.map((issue) => {
|
|
2473
2595
|
const where = issue.path.length ? issue.path.join(".") : "(root)";
|
|
@@ -2500,7 +2622,7 @@ async function readConfigFile(file) {
|
|
|
2500
2622
|
try {
|
|
2501
2623
|
mod = await importModule(file, { default: true });
|
|
2502
2624
|
} catch (err) {
|
|
2503
|
-
throw new ConfigError(`Could not load ${
|
|
2625
|
+
throw new ConfigError(`Could not load ${path15.basename(file)}: ${errorMessage(err)}`, {
|
|
2504
2626
|
cause: err
|
|
2505
2627
|
});
|
|
2506
2628
|
}
|
|
@@ -2512,12 +2634,12 @@ async function loadConfig(projectRoot, source) {
|
|
|
2512
2634
|
}
|
|
2513
2635
|
let file;
|
|
2514
2636
|
if (source) {
|
|
2515
|
-
file =
|
|
2637
|
+
file = path15.resolve(source);
|
|
2516
2638
|
if (!await pathExists(file)) throw new ConfigError(`Config file not found: ${file}`);
|
|
2517
2639
|
} else {
|
|
2518
2640
|
const found = [];
|
|
2519
2641
|
for (const name of CONFIG_FILE_NAMES) {
|
|
2520
|
-
if (await pathExists(
|
|
2642
|
+
if (await pathExists(path15.join(projectRoot, name))) found.push(name);
|
|
2521
2643
|
}
|
|
2522
2644
|
if (found.length > 1) {
|
|
2523
2645
|
throw new ConfigError(`Found several config files: ${found.join(", ")}`, {
|
|
@@ -2525,19 +2647,19 @@ async function loadConfig(projectRoot, source) {
|
|
|
2525
2647
|
});
|
|
2526
2648
|
}
|
|
2527
2649
|
if (!found[0]) return { config: parseConfig({}), file: void 0 };
|
|
2528
|
-
file =
|
|
2650
|
+
file = path15.join(projectRoot, found[0]);
|
|
2529
2651
|
}
|
|
2530
|
-
return { config: parseConfig(await readConfigFile(file),
|
|
2652
|
+
return { config: parseConfig(await readConfigFile(file), path15.basename(file)), file };
|
|
2531
2653
|
}
|
|
2532
2654
|
|
|
2533
2655
|
// src/core/context.ts
|
|
2534
2656
|
import { readFile as readFile3 } from "fs/promises";
|
|
2535
|
-
import
|
|
2657
|
+
import path17 from "path";
|
|
2536
2658
|
import fg2 from "fast-glob";
|
|
2537
2659
|
|
|
2538
2660
|
// src/core/exec.ts
|
|
2539
2661
|
import { spawn } from "child_process";
|
|
2540
|
-
import
|
|
2662
|
+
import path16 from "path";
|
|
2541
2663
|
var exec = (command, args, opts = {}) => new Promise((resolve, reject) => {
|
|
2542
2664
|
const maxBuffer = opts.maxBuffer ?? 64 * 1024 * 1024;
|
|
2543
2665
|
const shell = needsShell(command);
|
|
@@ -2565,7 +2687,7 @@ var exec = (command, args, opts = {}) => new Promise((resolve, reject) => {
|
|
|
2565
2687
|
});
|
|
2566
2688
|
function needsShell(command) {
|
|
2567
2689
|
if (process.platform !== "win32") return false;
|
|
2568
|
-
return /\.(cmd|bat)$/i.test(command) || !
|
|
2690
|
+
return /\.(cmd|bat)$/i.test(command) || !path16.isAbsolute(command);
|
|
2569
2691
|
}
|
|
2570
2692
|
function quoteForCmd(arg) {
|
|
2571
2693
|
return /[\s^&|<>()%!"]/.test(arg) ? `"${arg.replace(/"/g, '""')}"` : arg;
|
|
@@ -2587,12 +2709,12 @@ function createBaseContext(project, config, logger, overrides = {}) {
|
|
|
2587
2709
|
runtime: config.runtime,
|
|
2588
2710
|
onCleanup: (fn) => void cleanups.push(fn),
|
|
2589
2711
|
glob: (patterns, opts) => fg2(patterns, {
|
|
2590
|
-
cwd: opts?.cwd ?
|
|
2712
|
+
cwd: opts?.cwd ? path17.resolve(project.root, opts.cwd) : project.root,
|
|
2591
2713
|
ignore: config.ignore,
|
|
2592
2714
|
onlyFiles: true,
|
|
2593
2715
|
dot: false
|
|
2594
2716
|
}).then((files) => files.sort()),
|
|
2595
|
-
readText: (rel) => readFile3(
|
|
2717
|
+
readText: (rel) => readFile3(path17.resolve(project.root, rel), "utf8"),
|
|
2596
2718
|
shared: (key, factory) => {
|
|
2597
2719
|
let value = cache.get(key);
|
|
2598
2720
|
if (!value) {
|
|
@@ -2615,8 +2737,8 @@ function createBaseContext(project, config, logger, overrides = {}) {
|
|
|
2615
2737
|
}
|
|
2616
2738
|
|
|
2617
2739
|
// src/core/detect/index.ts
|
|
2618
|
-
import
|
|
2619
|
-
import
|
|
2740
|
+
import path18 from "path";
|
|
2741
|
+
import semver5 from "semver";
|
|
2620
2742
|
var LOCKFILES = [
|
|
2621
2743
|
["pnpm-lock.yaml", "pnpm"],
|
|
2622
2744
|
["yarn.lock", "yarn"],
|
|
@@ -2631,22 +2753,22 @@ async function detectPackageManager(dir, pkg) {
|
|
|
2631
2753
|
if (declared === "npm" || declared === "pnpm" || declared === "yarn" || declared === "bun") {
|
|
2632
2754
|
return declared;
|
|
2633
2755
|
}
|
|
2634
|
-
let current =
|
|
2756
|
+
let current = path18.resolve(dir);
|
|
2635
2757
|
for (; ; ) {
|
|
2636
2758
|
for (const [file, pm] of LOCKFILES) {
|
|
2637
|
-
if (await pathExists(
|
|
2759
|
+
if (await pathExists(path18.join(current, file))) return pm;
|
|
2638
2760
|
}
|
|
2639
|
-
if (await pathExists(
|
|
2640
|
-
const parent =
|
|
2761
|
+
if (await pathExists(path18.join(current, ".git"))) break;
|
|
2762
|
+
const parent = path18.dirname(current);
|
|
2641
2763
|
if (parent === current) break;
|
|
2642
2764
|
current = parent;
|
|
2643
2765
|
}
|
|
2644
2766
|
return "npm";
|
|
2645
2767
|
}
|
|
2646
2768
|
function majorOf(installed, declared) {
|
|
2647
|
-
if (installed &&
|
|
2648
|
-
if (declared &&
|
|
2649
|
-
const min =
|
|
2769
|
+
if (installed && semver5.valid(installed)) return semver5.major(installed);
|
|
2770
|
+
if (declared && semver5.validRange(declared)) {
|
|
2771
|
+
const min = semver5.minVersion(declared);
|
|
2650
2772
|
if (min) return min.major;
|
|
2651
2773
|
}
|
|
2652
2774
|
return void 0;
|
|
@@ -2667,7 +2789,7 @@ function toProjects(ws) {
|
|
|
2667
2789
|
name,
|
|
2668
2790
|
type: p.projectType === "library" ? "library" : "application",
|
|
2669
2791
|
root,
|
|
2670
|
-
sourceRoot: p.sourceRoot ??
|
|
2792
|
+
sourceRoot: p.sourceRoot ?? path18.posix.join(root, "src"),
|
|
2671
2793
|
builder: build2?.builder ?? build2?.executor,
|
|
2672
2794
|
outputPath: typeof outputPath === "string" ? outputPath : typeof outputPath === "object" && outputPath && "base" in outputPath ? String(outputPath.base) : void 0,
|
|
2673
2795
|
ssr: isSsrTarget(targets)
|
|
@@ -2675,13 +2797,13 @@ function toProjects(ws) {
|
|
|
2675
2797
|
});
|
|
2676
2798
|
}
|
|
2677
2799
|
async function detectProject(root) {
|
|
2678
|
-
const absRoot =
|
|
2679
|
-
const pkg = await readJsonFile(
|
|
2800
|
+
const absRoot = path18.resolve(root);
|
|
2801
|
+
const pkg = await readJsonFile(path18.join(absRoot, "package.json"));
|
|
2680
2802
|
const deps = { ...pkg?.devDependencies, ...pkg?.dependencies };
|
|
2681
2803
|
let workspaceFile;
|
|
2682
2804
|
let ws;
|
|
2683
2805
|
for (const candidate of ["angular.json", ".angular-cli.json", "workspace.json"]) {
|
|
2684
|
-
const file =
|
|
2806
|
+
const file = path18.join(absRoot, candidate);
|
|
2685
2807
|
ws = await readJsonFile(file);
|
|
2686
2808
|
if (ws) {
|
|
2687
2809
|
workspaceFile = file;
|
|
@@ -2695,20 +2817,20 @@ async function detectProject(root) {
|
|
|
2695
2817
|
});
|
|
2696
2818
|
}
|
|
2697
2819
|
const installedPkg = await readJsonFile(
|
|
2698
|
-
|
|
2820
|
+
path18.join(absRoot, "node_modules", "@angular", "core", "package.json")
|
|
2699
2821
|
);
|
|
2700
2822
|
const installed = installedPkg?.version;
|
|
2701
2823
|
const projects = ws ? toProjects(ws) : [];
|
|
2702
2824
|
const hasSsrPackage = SSR_PACKAGES.some((p) => p in deps);
|
|
2703
|
-
const hasServerTs = await pathExists(
|
|
2825
|
+
const hasServerTs = await pathExists(path18.join(absRoot, "server.ts"));
|
|
2704
2826
|
return {
|
|
2705
2827
|
root: absRoot,
|
|
2706
|
-
name: pkg?.name ??
|
|
2828
|
+
name: pkg?.name ?? path18.basename(absRoot),
|
|
2707
2829
|
packageManager: await detectPackageManager(absRoot, pkg),
|
|
2708
2830
|
angular: { declared, installed, major: majorOf(installed, declared) },
|
|
2709
2831
|
kind: projects.length > 1 ? "workspace" : "single-app",
|
|
2710
2832
|
workspaceFile,
|
|
2711
|
-
nx: await pathExists(
|
|
2833
|
+
nx: await pathExists(path18.join(absRoot, "nx.json")),
|
|
2712
2834
|
projects,
|
|
2713
2835
|
defaultProject: ws?.defaultProject ?? projects.find((p) => p.type === "application")?.name ?? projects[0]?.name,
|
|
2714
2836
|
ssr: projects.some((p) => p.ssr) || hasSsrPackage || hasServerTs
|
|
@@ -2749,10 +2871,10 @@ var silentLogger = {
|
|
|
2749
2871
|
};
|
|
2750
2872
|
|
|
2751
2873
|
// src/core/options.ts
|
|
2752
|
-
import
|
|
2874
|
+
import path19 from "path";
|
|
2753
2875
|
function resolveOptions(projectPath, options, config, configFile, cwd = process.cwd()) {
|
|
2754
2876
|
return {
|
|
2755
|
-
projectPath:
|
|
2877
|
+
projectPath: path19.resolve(cwd, projectPath),
|
|
2756
2878
|
only: options.only?.length ? options.only : config.only,
|
|
2757
2879
|
skip: [.../* @__PURE__ */ new Set([...config.skip, ...options.skip ?? []])],
|
|
2758
2880
|
build: options.build !== false,
|
|
@@ -2772,8 +2894,8 @@ function resolveRuntime(options, config, configFile, cwd) {
|
|
|
2772
2894
|
throw new ConfigError(`Invalid url: ${options.url}`);
|
|
2773
2895
|
}
|
|
2774
2896
|
}
|
|
2775
|
-
const configDir = configFile ?
|
|
2776
|
-
const loginScript = options.loginScript ?
|
|
2897
|
+
const configDir = configFile ? path19.dirname(configFile) : cwd;
|
|
2898
|
+
const loginScript = options.loginScript ? path19.resolve(cwd, options.loginScript) : config.runtime.loginScript ? path19.resolve(configDir, config.runtime.loginScript) : void 0;
|
|
2777
2899
|
return {
|
|
2778
2900
|
...config.runtime,
|
|
2779
2901
|
...options.url ? { url: options.url } : {},
|
|
@@ -2784,7 +2906,7 @@ function resolveRuntime(options, config, configFile, cwd) {
|
|
|
2784
2906
|
|
|
2785
2907
|
// src/core/plugins.ts
|
|
2786
2908
|
import { createRequire } from "module";
|
|
2787
|
-
import
|
|
2909
|
+
import path20 from "path";
|
|
2788
2910
|
import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
|
|
2789
2911
|
var OPTIONAL_FIELDS = [
|
|
2790
2912
|
["description", "string"],
|
|
@@ -2834,11 +2956,11 @@ function checksFromModule(mod, spec) {
|
|
|
2834
2956
|
}
|
|
2835
2957
|
var TS_EXTENSIONS = /\.(c|m)?ts$/;
|
|
2836
2958
|
function resolvePluginSpecifier(spec, baseDir, projectRoot) {
|
|
2837
|
-
if (spec.startsWith(".") ||
|
|
2838
|
-
return pathToFileURL2(
|
|
2959
|
+
if (spec.startsWith(".") || path20.isAbsolute(spec)) {
|
|
2960
|
+
return pathToFileURL2(path20.resolve(baseDir, spec)).href;
|
|
2839
2961
|
}
|
|
2840
2962
|
try {
|
|
2841
|
-
return pathToFileURL2(createRequire(
|
|
2963
|
+
return pathToFileURL2(createRequire(path20.join(projectRoot, "package.json")).resolve(spec)).href;
|
|
2842
2964
|
} catch {
|
|
2843
2965
|
return spec;
|
|
2844
2966
|
}
|
|
@@ -3214,7 +3336,7 @@ async function runAudit(projectPath, options = {}, deps = {}) {
|
|
|
3214
3336
|
const logger = options.logger ?? silentLogger;
|
|
3215
3337
|
const signal = options.signal;
|
|
3216
3338
|
signal?.throwIfAborted();
|
|
3217
|
-
const absPath =
|
|
3339
|
+
const absPath = path21.resolve(projectPath);
|
|
3218
3340
|
if (!await isDirectory(absPath)) {
|
|
3219
3341
|
throw new ProjectError(`Project path does not exist or is not a directory: ${absPath}`);
|
|
3220
3342
|
}
|
|
@@ -3225,7 +3347,7 @@ async function runAudit(projectPath, options = {}, deps = {}) {
|
|
|
3225
3347
|
const baseline = typeof options.baseline === "string" ? await loadBaseline(options.baseline) : options.baseline;
|
|
3226
3348
|
const project = await detectProject(absPath);
|
|
3227
3349
|
options.onProgress?.({ type: "project-detected", project });
|
|
3228
|
-
const plugins = await loadPlugins(config.plugins, file ?
|
|
3350
|
+
const plugins = await loadPlugins(config.plugins, file ? path21.dirname(file) : absPath, absPath);
|
|
3229
3351
|
const allChecks = [...deps.checks ?? builtinChecks, ...plugins];
|
|
3230
3352
|
validateRegistry(allChecks);
|
|
3231
3353
|
const selection = selectChecks(allChecks, config, resolved);
|
|
@@ -3766,4 +3888,4 @@ export {
|
|
|
3766
3888
|
renderJson,
|
|
3767
3889
|
renderMarkdown
|
|
3768
3890
|
};
|
|
3769
|
-
//# sourceMappingURL=chunk-
|
|
3891
|
+
//# sourceMappingURL=chunk-T4EN6LCY.js.map
|