@suss/packs 0.31.1 → 0.32.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.
Files changed (2) hide show
  1. package/dist/node.js +37 -60
  2. package/package.json +10 -10
package/dist/node.js CHANGED
@@ -162,22 +162,38 @@ function envReadsAt(node, resolution) {
162
162
  return isProcessEnv(node) ? readsThroughEnvObject(node, resolution) : dottedRead(node);
163
163
  }
164
164
  function readsThroughHelperCall(call, resolution) {
165
- const reads = [];
166
165
  const callee = functionBehindCallee(call.getExpression());
167
166
  if (callee === null) {
168
- return reads;
167
+ return [];
169
168
  }
169
+ const sitesNaming = namesReadAtSites(callee, resolution);
170
+ const parameters = callee.getParameters();
171
+ const defaultedByName = /* @__PURE__ */ new Map();
170
172
  call.getArguments().forEach((passed, at) => {
171
- const literal = stringValueOf(passed, resolution);
172
- if (literal === null || literal.length === 0) {
173
+ const parameter = parameters[at];
174
+ if (parameter === void 0) {
173
175
  return;
174
176
  }
175
- const read = parameterReachesEnvRead(callee, at, resolution);
176
- if (read !== null) {
177
- reads.push({ name: literal, defaulted: read.defaulted, node: call });
177
+ const sites = sitesNaming(parameter) ?? directEnvReads(callee, parameter);
178
+ if (sites.length === 0) {
179
+ return;
178
180
  }
181
+ const literal = stringValueOf(passed, resolution);
182
+ if (!namesSomething(literal)) {
183
+ return;
184
+ }
185
+ const everywhere = sites.every(isDefaultedAt);
186
+ defaultedByName.set(
187
+ literal,
188
+ (defaultedByName.get(literal) ?? true) && everywhere
189
+ );
179
190
  });
180
- return reads;
191
+ const wrapped = isDefaultedAt(call);
192
+ return [...defaultedByName].map(([name, atSites]) => ({
193
+ name,
194
+ defaulted: atSites || wrapped,
195
+ node: call
196
+ }));
181
197
  }
182
198
  function functionBehindCallee(callee) {
183
199
  const nameNode = N.isPropertyAccessExpression(callee) ? callee.getNameNode() : callee;
@@ -186,53 +202,19 @@ function functionBehindCallee(callee) {
186
202
  }
187
203
  return functionTargetOf(nameNode)?.func ?? null;
188
204
  }
189
- var PARAM_ENV_READS = /* @__PURE__ */ new WeakMap();
190
- function parameterReachesEnvRead(fn, at, resolution) {
191
- const byParameter = PARAM_ENV_READS.get(fn.compilerNode) ?? /* @__PURE__ */ new Map();
192
- PARAM_ENV_READS.set(fn.compilerNode, byParameter);
193
- const remembered = byParameter.get(at);
194
- if (remembered !== void 0) {
195
- return remembered;
196
- }
197
- const found = reachesEnvRead(fn, at, resolution);
198
- byParameter.set(at, found);
199
- return found;
205
+ function namesSomething(value) {
206
+ return value !== null && value.length > 0;
200
207
  }
201
- function reachesEnvRead(fn, at, resolution) {
202
- const pending = [{ fn, at }];
203
- const taken = /* @__PURE__ */ new Set();
204
- while (pending.length > 0) {
205
- const wanted = pending.pop();
206
- const key = `${wanted.fn.getPos()}:${wanted.at}`;
207
- if (taken.has(key)) {
208
- continue;
209
- }
210
- taken.add(key);
211
- const parameter = wanted.fn.getParameters()[wanted.at];
212
- if (parameter === void 0) {
213
- continue;
214
- }
215
- const direct = directEnvRead(wanted.fn, parameter);
216
- if (direct !== null) {
217
- return direct;
218
- }
219
- if (resolution === void 0) {
220
- continue;
221
- }
222
- for (const passed of resolution.callsPassing(parameter)) {
223
- if (!N.isCallExpression(passed.call)) {
224
- continue;
225
- }
226
- const position = passed.call.getArguments().indexOf(passed.argument);
227
- const next = functionLikeOf(
228
- resolution.resolveCallable(passed.call.getExpression())
229
- );
230
- if (position >= 0 && next !== null && next !== wanted.fn) {
231
- pending.push({ fn: next, at: position });
232
- }
233
- }
208
+ function namesReadAtSites(fn, resolution) {
209
+ if (resolution === void 0) {
210
+ return () => null;
234
211
  }
235
- return null;
212
+ const namers = resolution.envNamers(fn.getSourceFile());
213
+ return (parameter) => namers.sitesNaming(parameter);
214
+ }
215
+ function directEnvReads(fn, parameter) {
216
+ const direct = directEnvRead(fn, parameter);
217
+ return direct === null ? [] : [direct];
236
218
  }
237
219
  function directEnvRead(fn, parameter) {
238
220
  for (const access of fn.getDescendantsOfKind(
@@ -243,17 +225,11 @@ function directEnvRead(fn, parameter) {
243
225
  }
244
226
  const argument = access.getArgumentExpression();
245
227
  if (argument !== void 0 && N.isIdentifier(argument) && symbolBehind(argument)?.getValueDeclaration() === parameter) {
246
- return { defaulted: isDefaultedAt(access) };
228
+ return access;
247
229
  }
248
230
  }
249
231
  return null;
250
232
  }
251
- function functionLikeOf(node) {
252
- if (node === null) {
253
- return null;
254
- }
255
- return N.isFunctionDeclaration(node) || N.isArrowFunction(node) || N.isFunctionExpression(node) || N.isMethodDeclaration(node) ? node : null;
256
- }
257
233
  function configReadEffect(read, deploymentTarget, instanceName) {
258
234
  return {
259
235
  type: "interaction",
@@ -611,6 +587,7 @@ function nodeRuntimePack(options = {}) {
611
587
  terminals: [],
612
588
  inputMapping: { type: "positionalParams", params: [] },
613
589
  invocationRecognizers: [schedulingRecognizer],
590
+ environmentObjects: ["process.env"],
614
591
  accessRecognizers: [
615
592
  // `envRecognizer` owns `process.env.X`; `processRecognizer`
616
593
  // owns the rest of the process surface and skips env reads,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/packs",
3
- "version": "0.31.1",
3
+ "version": "0.32.0",
4
4
  "type": "module",
5
5
  "description": "Every pack suss ships in one install, so it can read Express, Hono, NestJS, FastAPI, Rails, Prisma, OpenAPI and the rest.",
6
6
  "keywords": [
@@ -218,15 +218,15 @@
218
218
  "ts-morph": "^23.0.0"
219
219
  },
220
220
  "dependencies": {
221
- "@suss/adapter-python": "0.31.1",
222
- "@suss/adapter-ruby": "0.31.1",
223
- "@suss/adapter-typescript": "0.31.1",
224
- "@suss/behavioral-ir": "0.31.1",
225
- "@suss/contract-graphql": "0.31.1",
226
- "@suss/extractor": "0.31.1",
227
- "@suss/manifest-aws": "0.31.1",
228
- "@suss/recognize": "0.31.1",
229
- "@suss/sql": "0.31.1",
221
+ "@suss/adapter-python": "0.32.0",
222
+ "@suss/adapter-ruby": "0.32.0",
223
+ "@suss/adapter-typescript": "0.32.0",
224
+ "@suss/behavioral-ir": "0.32.0",
225
+ "@suss/contract-graphql": "0.32.0",
226
+ "@suss/extractor": "0.32.0",
227
+ "@suss/manifest-aws": "0.32.0",
228
+ "@suss/recognize": "0.32.0",
229
+ "@suss/sql": "0.32.0",
230
230
  "zod": "^4.0.0"
231
231
  },
232
232
  "devDependencies": {