candor-ts 0.9.0 → 0.9.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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/scan-core.mjs +12 -0
  3. package/scan.mjs +17 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "candor-ts",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "candor for TypeScript — per-function side effects, transitively, with a policy gate (candor-spec 0.9)",
5
5
  "type": "module",
6
6
  "dependencies": {
package/scan-core.mjs CHANGED
@@ -123,6 +123,18 @@ export const KAPPA_RULES = [
123
123
  [/^open$/, /^(open|openApp)$/, "Exec"],
124
124
  [/^(fs-extra|graceful-fs|rimraf|glob|chokidar)$/, null, "Fs"],
125
125
  [/^dotenv$/, null, "Env"],
126
+ // CLI-tool packages surfaced by the 0.9 dogfood on `zx` (read `invisible` before — a κ-coverage gap, not
127
+ // a cardinal sin; modeled against each package's SOURCE, not its name):
128
+ // - `which`: resolves an executable by stat-ing PATH candidates (via `isexe`) — Fs. Both the async default
129
+ // `which(cmd)` and `which.sync(cmd)` hit the filesystem; no pure member → whole-module Fs.
130
+ [/^which$/, null, "Fs"],
131
+ // - `@webpod/ps`: process listing/kill — kill/lookup/lookupSync/tree/treeSync ALL spawn the OS via
132
+ // `exec({...})` (zurk/spawn) — verified in ps.js. Uniform process surface, no pure member → Exec.
133
+ [/^@webpod\/ps$/, null, "Exec"],
134
+ // - `envapi` (a dotenv variant): MIXED — `parse`/`stringify` are pure string transforms; `load`/`loadSafe`/
135
+ // `config` READ the .env file (`fs.readFileSync`). Member-precise so `parse` never fabricates Fs (the
136
+ // argon2 curated-κ lesson: model the effectful member, never blanket-grant a mixed package).
137
+ [/^envapi$/, /^(load|loadSafe|config)$/, "Fs"],
126
138
  [/^(winston|pino|bunyan|npmlog)$/, null, "Log"],
127
139
  // nest-winston wraps winston; the injected logger's level verbs are the Log boundary (the
128
140
  // WinstonModule.createLogger/forRoot config is inert).
package/scan.mjs CHANGED
@@ -273,14 +273,25 @@ if (!wantJson) fs.mkdirSync(path.dirname(path.resolve(outPrefix)), { recursive:
273
273
  // would "succeed" with a near-total-Unknown report a fresh user could ship (CTA-dogfood finding).
274
274
  // Warn LOUDLY; the report is still written (it is sound), but the cause must be visible.
275
275
  {
276
- const pkg = path.join(rootDir, "package.json");
277
- if (fs.existsSync(pkg) && !fs.existsSync(path.join(rootDir, "node_modules"))) {
276
+ // Find the nearest package.json AT OR ABOVE the scan root: scanning a `src/` subdirectory must still see
277
+ // the project manifest one level up, else the warning stays silent and a deps-less scan reads as a
278
+ // codebase full of spurious `Unknown`s (the exact trap a 0.9 dogfood fell into — scanning `zx/src`).
279
+ let projDir = null;
280
+ for (let d = rootDir; ; d = path.dirname(d)) {
281
+ if (fs.existsSync(path.join(d, "package.json"))) { projDir = d; break; }
282
+ if (path.dirname(d) === d) break; // filesystem root
283
+ }
284
+ if (projDir && !fs.existsSync(path.join(projDir, "node_modules"))) {
278
285
  try {
279
- const deps = JSON.parse(fs.readFileSync(pkg, "utf8")).dependencies ?? {};
286
+ // BOTH dependency kinds: `npm install` installs devDependencies too, and a project can import a
287
+ // dev/vendored package in its source (zx imports `chalk` as a devDependency) — a `dependencies`-only
288
+ // check left exactly that case unwarned.
289
+ const pj = JSON.parse(fs.readFileSync(path.join(projDir, "package.json"), "utf8"));
290
+ const deps = { ...(pj.dependencies ?? {}), ...(pj.devDependencies ?? {}) };
280
291
  if (Object.keys(deps).length > 0)
281
- console.error("candor-ts: WARNING — the target declares dependencies but has no node_modules; " +
282
- "imports won't resolve, so calls into those packages read pure/invisible (not Unknown) " +
283
- "and effects through them are silently dropped. Run `npm install` in the target first.");
292
+ console.error("candor-ts: WARNING — the project declares dependencies but has no node_modules; " +
293
+ "imports won't resolve, so calls into those packages can't be analyzed (they read " +
294
+ "`Unknown`, and their types don't resolve). Run `npm install` in the project first.");
284
295
  } catch {}
285
296
  }
286
297
  // Prisma's client types are GENERATED — a project with the prisma dependency but no generated