@suss/adapter-typescript 0.38.0 → 0.38.1

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/dist/index.cjs CHANGED
@@ -213,7 +213,7 @@ function printedType(type, reader, enclosing, format) {
213
213
  );
214
214
  }
215
215
  const file = enclosing?.getSourceFile().compilerNode ?? NO_FILE;
216
- const ordered = containsUnion(typeNode) ? withUnionMembersOrdered(typeNode, file) : typeNode;
216
+ const ordered = containsReordered(typeNode) ? withMembersOrdered(typeNode, file) : typeNode;
217
217
  return withoutImportQualifiers(printed(ordered, file));
218
218
  }
219
219
  var IMPORT_QUALIFIER = /import\("[^"]*"\)\./g;
@@ -224,24 +224,31 @@ function printed(node, file) {
224
224
  ""
225
225
  );
226
226
  }
227
- function containsUnion(node) {
228
- if (import_ts_morph.ts.isUnionTypeNode(node)) {
227
+ var isReordered = (node) => import_ts_morph.ts.isUnionTypeNode(node) || import_ts_morph.ts.isTypeLiteralNode(node);
228
+ function containsReordered(node) {
229
+ if (isReordered(node)) {
229
230
  return true;
230
231
  }
231
- return import_ts_morph.ts.forEachChild(node, (child) => containsUnion(child) || void 0) === true;
232
+ return import_ts_morph.ts.forEachChild(node, (child) => containsReordered(child) || void 0) === true;
232
233
  }
233
- function withUnionMembersOrdered(root, file) {
234
+ function withMembersOrdered(root, file) {
234
235
  const result = import_ts_morph.ts.transform(root, [
235
236
  (context) => {
236
237
  const visit = (node) => {
237
238
  const visited = import_ts_morph.ts.visitEachChild(node, visit, context);
238
- if (!import_ts_morph.ts.isUnionTypeNode(visited)) {
239
- return visited;
239
+ if (import_ts_morph.ts.isUnionTypeNode(visited)) {
240
+ return context.factory.updateUnionTypeNode(
241
+ visited,
242
+ context.factory.createNodeArray(inStableOrder(visited.types, file))
243
+ );
240
244
  }
241
- return context.factory.updateUnionTypeNode(
242
- visited,
243
- context.factory.createNodeArray(inStableOrder(visited.types, file))
244
- );
245
+ if (import_ts_morph.ts.isTypeLiteralNode(visited)) {
246
+ return context.factory.updateTypeLiteralNode(
247
+ visited,
248
+ context.factory.createNodeArray(inNameOrder(visited.members, file))
249
+ );
250
+ }
251
+ return visited;
245
252
  };
246
253
  return (node) => visit(node);
247
254
  }
@@ -250,6 +257,12 @@ function withUnionMembersOrdered(root, file) {
250
257
  result.dispose();
251
258
  return ordered;
252
259
  }
260
+ function inNameOrder(members, file) {
261
+ return members.map((member) => ({
262
+ member,
263
+ name: member.name === void 0 ? "" : printed(member.name, file)
264
+ })).sort((a, b) => compareText(a.name, b.name)).map(({ member }) => member);
265
+ }
253
266
  function inStableOrder(members, file) {
254
267
  return members.map((member) => ({
255
268
  member,
@@ -4175,6 +4188,7 @@ var DERIVED_RELATIONS = /* @__PURE__ */ new Set([
4175
4188
  ...(0, import_resolution5.resolutionUnderProgram)().rules.map((r) => r.head.relation)
4176
4189
  ]);
4177
4190
  var QUERY_FACTS = (0, import_resolution5.queryFacts)(RESOLUTION_PROGRAM);
4191
+ var DERIVED_AGAIN = new Set(QUERY_FACTS);
4178
4192
  var MODULE_DEMANDS = RESOLUTION_PROGRAM.demands.filter(
4179
4193
  (one) => (one.relation === "moduleExport" || one.relation === "moduleForwards") && one.bound[0] === true
4180
4194
  ).map((one) => one.demand);
@@ -4342,25 +4356,45 @@ var ResolutionStore = class _ResolutionStore {
4342
4356
  );
4343
4357
  }
4344
4358
  /**
4345
- * A question asked again over the same facts reads the same files and
4346
- * derives the same answer, so the store gives back the one it found
4347
- * before. The files that answer read still count as read.
4359
+ * A question asked again, when no fact its derivation looked up has
4360
+ * arrived since, reads the same files and derives the same answer, so
4361
+ * the store gives back the one it found before. The files that answer
4362
+ * read still count as read.
4363
+ *
4364
+ * Noting the lookups costs the question a share of its time, and most
4365
+ * questions are asked once, so a question notes them only once it has
4366
+ * had to be asked again. Until then, as without demand, only an
4367
+ * unchanged fact count says the answer is the same. Without demand the
4368
+ * rules keep every conclusion between questions, so a question's own
4369
+ * lookups miss what earlier questions derived for it. A question that
4370
+ * started on another question's leftovers gets the count too.
4348
4371
  */
4349
4372
  remembered(key, ask) {
4350
4373
  const known = this.answers.get(key);
4351
- if (known !== void 0 && known.facts === this.sourceFactCount()) {
4374
+ if (known !== void 0 && this.stillDerives(known.check)) {
4352
4375
  for (const walkedPath of known.walked) {
4353
4376
  recordFileDependency(walkedPath);
4354
4377
  }
4355
4378
  return known.answer;
4356
4379
  }
4357
- const answer = ask();
4380
+ const { value, reads } = known === void 0 || QUERY_FACTS.length === 0 ? { value: ask(), reads: null } : (0, import_datalog2.noteReads)(this.db, DERIVED_AGAIN, ask);
4358
4381
  this.answers.set(key, {
4359
- answer,
4382
+ answer: value,
4360
4383
  walked: [...this.lastQueryWalked],
4361
- facts: this.sourceFactCount()
4384
+ check: reads ?? this.sourceFactCount()
4362
4385
  });
4363
- return answer;
4386
+ return value;
4387
+ }
4388
+ /**
4389
+ * Facts added since the last derivation have not reached the relations
4390
+ * the rules keep between questions, so the reads cannot say yet what
4391
+ * those facts change.
4392
+ */
4393
+ stillDerives(check) {
4394
+ if (typeof check === "number") {
4395
+ return check === this.sourceFactCount();
4396
+ }
4397
+ return !this.stale && check.unchangedIn(this.db);
4364
4398
  }
4365
4399
  /**
4366
4400
  * How many facts the store has read from source. They are only ever
@@ -6871,7 +6905,8 @@ function importedCallOrigins(sourceFile, resolution, module2) {
6871
6905
  const candidates = [];
6872
6906
  forEachDescendantWhere(sourceFile, callsANamedCallee, (node) => {
6873
6907
  const call = node;
6874
- if (!declaredLocally(call.getExpression())) {
6908
+ const callee = call.getExpression();
6909
+ if (!declaredLocally(callee) && !importedFromAnotherPackage(callee, module2)) {
6875
6910
  candidates.push(call);
6876
6911
  }
6877
6912
  return false;
@@ -6901,6 +6936,26 @@ function callsNamed(found, names) {
6901
6936
  function callsANamedCallee(raw) {
6902
6937
  return (import_ts_morph19.ts.isCallExpression(raw) || import_ts_morph19.ts.isNewExpression(raw)) && import_ts_morph19.ts.isIdentifier(raw.expression);
6903
6938
  }
6939
+ var samePackage = (specifier, module2) => specifier === module2 || specifier.startsWith(`${module2}/`) || module2.startsWith(`${specifier}/`);
6940
+ function importOf(declaration) {
6941
+ if (import_ts_morph19.Node.isImportSpecifier(declaration)) {
6942
+ return declaration.getImportDeclaration();
6943
+ }
6944
+ const parent = import_ts_morph19.Node.isImportClause(declaration) ? declaration.getParent() : void 0;
6945
+ return parent !== void 0 && import_ts_morph19.Node.isImportDeclaration(parent) ? parent : void 0;
6946
+ }
6947
+ function importedFromAnotherPackage(callee, module2) {
6948
+ const declarations = callee.getSymbol()?.getDeclarations() ?? [];
6949
+ return declarations.length > 0 && declarations.every((declaration) => {
6950
+ const from = importOf(declaration);
6951
+ if (from === void 0) {
6952
+ return false;
6953
+ }
6954
+ const resolved = from.getModuleSpecifierSourceFile();
6955
+ const specifier = from.getModuleSpecifierValue();
6956
+ return (resolved === void 0 || resolved.isInNodeModules()) && !specifier.startsWith(".") && !samePackage(specifier, module2);
6957
+ });
6958
+ }
6904
6959
  function declaredLocally(callee) {
6905
6960
  const declarations = callee.getSymbol()?.getDeclarations() ?? [];
6906
6961
  return declarations.length > 0 && declarations.every(
package/dist/index.d.cts CHANGED
@@ -202,11 +202,26 @@ declare class ResolutionStore {
202
202
  explainCallable(value: Node, options?: ExplainCallableOptions): ExplainedResolution | null;
203
203
  resolveObject(value: Node): Node | null;
204
204
  /**
205
- * A question asked again over the same facts reads the same files and
206
- * derives the same answer, so the store gives back the one it found
207
- * before. The files that answer read still count as read.
205
+ * A question asked again, when no fact its derivation looked up has
206
+ * arrived since, reads the same files and derives the same answer, so
207
+ * the store gives back the one it found before. The files that answer
208
+ * read still count as read.
209
+ *
210
+ * Noting the lookups costs the question a share of its time, and most
211
+ * questions are asked once, so a question notes them only once it has
212
+ * had to be asked again. Until then, as without demand, only an
213
+ * unchanged fact count says the answer is the same. Without demand the
214
+ * rules keep every conclusion between questions, so a question's own
215
+ * lookups miss what earlier questions derived for it. A question that
216
+ * started on another question's leftovers gets the count too.
208
217
  */
209
218
  private remembered;
219
+ /**
220
+ * Facts added since the last derivation have not reached the relations
221
+ * the rules keep between questions, so the reads cannot say yet what
222
+ * those facts change.
223
+ */
224
+ private stillDerives;
210
225
  /**
211
226
  * How many facts the store has read from source. They are only ever
212
227
  * added, so work that asked the store questions and found this number
package/dist/index.d.ts CHANGED
@@ -202,11 +202,26 @@ declare class ResolutionStore {
202
202
  explainCallable(value: Node, options?: ExplainCallableOptions): ExplainedResolution | null;
203
203
  resolveObject(value: Node): Node | null;
204
204
  /**
205
- * A question asked again over the same facts reads the same files and
206
- * derives the same answer, so the store gives back the one it found
207
- * before. The files that answer read still count as read.
205
+ * A question asked again, when no fact its derivation looked up has
206
+ * arrived since, reads the same files and derives the same answer, so
207
+ * the store gives back the one it found before. The files that answer
208
+ * read still count as read.
209
+ *
210
+ * Noting the lookups costs the question a share of its time, and most
211
+ * questions are asked once, so a question notes them only once it has
212
+ * had to be asked again. Until then, as without demand, only an
213
+ * unchanged fact count says the answer is the same. Without demand the
214
+ * rules keep every conclusion between questions, so a question's own
215
+ * lookups miss what earlier questions derived for it. A question that
216
+ * started on another question's leftovers gets the count too.
208
217
  */
209
218
  private remembered;
219
+ /**
220
+ * Facts added since the last derivation have not reached the relations
221
+ * the rules keep between questions, so the reads cannot say yet what
222
+ * those facts change.
223
+ */
224
+ private stillDerives;
210
225
  /**
211
226
  * How many facts the store has read from source. They are only ever
212
227
  * added, so work that asked the store questions and found this number
package/dist/index.js CHANGED
@@ -133,7 +133,7 @@ function printedType(type, reader, enclosing, format) {
133
133
  );
134
134
  }
135
135
  const file = enclosing?.getSourceFile().compilerNode ?? NO_FILE;
136
- const ordered = containsUnion(typeNode) ? withUnionMembersOrdered(typeNode, file) : typeNode;
136
+ const ordered = containsReordered(typeNode) ? withMembersOrdered(typeNode, file) : typeNode;
137
137
  return withoutImportQualifiers(printed(ordered, file));
138
138
  }
139
139
  var IMPORT_QUALIFIER = /import\("[^"]*"\)\./g;
@@ -144,24 +144,31 @@ function printed(node, file) {
144
144
  ""
145
145
  );
146
146
  }
147
- function containsUnion(node) {
148
- if (ts.isUnionTypeNode(node)) {
147
+ var isReordered = (node) => ts.isUnionTypeNode(node) || ts.isTypeLiteralNode(node);
148
+ function containsReordered(node) {
149
+ if (isReordered(node)) {
149
150
  return true;
150
151
  }
151
- return ts.forEachChild(node, (child) => containsUnion(child) || void 0) === true;
152
+ return ts.forEachChild(node, (child) => containsReordered(child) || void 0) === true;
152
153
  }
153
- function withUnionMembersOrdered(root, file) {
154
+ function withMembersOrdered(root, file) {
154
155
  const result = ts.transform(root, [
155
156
  (context) => {
156
157
  const visit = (node) => {
157
158
  const visited = ts.visitEachChild(node, visit, context);
158
- if (!ts.isUnionTypeNode(visited)) {
159
- return visited;
159
+ if (ts.isUnionTypeNode(visited)) {
160
+ return context.factory.updateUnionTypeNode(
161
+ visited,
162
+ context.factory.createNodeArray(inStableOrder(visited.types, file))
163
+ );
160
164
  }
161
- return context.factory.updateUnionTypeNode(
162
- visited,
163
- context.factory.createNodeArray(inStableOrder(visited.types, file))
164
- );
165
+ if (ts.isTypeLiteralNode(visited)) {
166
+ return context.factory.updateTypeLiteralNode(
167
+ visited,
168
+ context.factory.createNodeArray(inNameOrder(visited.members, file))
169
+ );
170
+ }
171
+ return visited;
165
172
  };
166
173
  return (node) => visit(node);
167
174
  }
@@ -170,6 +177,12 @@ function withUnionMembersOrdered(root, file) {
170
177
  result.dispose();
171
178
  return ordered;
172
179
  }
180
+ function inNameOrder(members, file) {
181
+ return members.map((member) => ({
182
+ member,
183
+ name: member.name === void 0 ? "" : printed(member.name, file)
184
+ })).sort((a, b) => compareText(a.name, b.name)).map(({ member }) => member);
185
+ }
173
186
  function inStableOrder(members, file) {
174
187
  return members.map((member) => ({
175
188
  member,
@@ -539,6 +552,7 @@ import {
539
552
  clearRelations,
540
553
  Database as Database2,
541
554
  evaluate as evaluate2,
555
+ noteReads,
542
556
  proofOf,
543
557
  tupleKey,
544
558
  tupleKeyParts,
@@ -4146,6 +4160,7 @@ var DERIVED_RELATIONS = /* @__PURE__ */ new Set([
4146
4160
  ...resolutionUnderProgram().rules.map((r) => r.head.relation)
4147
4161
  ]);
4148
4162
  var QUERY_FACTS = queryFacts(RESOLUTION_PROGRAM);
4163
+ var DERIVED_AGAIN = new Set(QUERY_FACTS);
4149
4164
  var MODULE_DEMANDS = RESOLUTION_PROGRAM.demands.filter(
4150
4165
  (one) => (one.relation === "moduleExport" || one.relation === "moduleForwards") && one.bound[0] === true
4151
4166
  ).map((one) => one.demand);
@@ -4313,25 +4328,45 @@ var ResolutionStore = class _ResolutionStore {
4313
4328
  );
4314
4329
  }
4315
4330
  /**
4316
- * A question asked again over the same facts reads the same files and
4317
- * derives the same answer, so the store gives back the one it found
4318
- * before. The files that answer read still count as read.
4331
+ * A question asked again, when no fact its derivation looked up has
4332
+ * arrived since, reads the same files and derives the same answer, so
4333
+ * the store gives back the one it found before. The files that answer
4334
+ * read still count as read.
4335
+ *
4336
+ * Noting the lookups costs the question a share of its time, and most
4337
+ * questions are asked once, so a question notes them only once it has
4338
+ * had to be asked again. Until then, as without demand, only an
4339
+ * unchanged fact count says the answer is the same. Without demand the
4340
+ * rules keep every conclusion between questions, so a question's own
4341
+ * lookups miss what earlier questions derived for it. A question that
4342
+ * started on another question's leftovers gets the count too.
4319
4343
  */
4320
4344
  remembered(key, ask) {
4321
4345
  const known = this.answers.get(key);
4322
- if (known !== void 0 && known.facts === this.sourceFactCount()) {
4346
+ if (known !== void 0 && this.stillDerives(known.check)) {
4323
4347
  for (const walkedPath of known.walked) {
4324
4348
  recordFileDependency(walkedPath);
4325
4349
  }
4326
4350
  return known.answer;
4327
4351
  }
4328
- const answer = ask();
4352
+ const { value, reads } = known === void 0 || QUERY_FACTS.length === 0 ? { value: ask(), reads: null } : noteReads(this.db, DERIVED_AGAIN, ask);
4329
4353
  this.answers.set(key, {
4330
- answer,
4354
+ answer: value,
4331
4355
  walked: [...this.lastQueryWalked],
4332
- facts: this.sourceFactCount()
4356
+ check: reads ?? this.sourceFactCount()
4333
4357
  });
4334
- return answer;
4358
+ return value;
4359
+ }
4360
+ /**
4361
+ * Facts added since the last derivation have not reached the relations
4362
+ * the rules keep between questions, so the reads cannot say yet what
4363
+ * those facts change.
4364
+ */
4365
+ stillDerives(check) {
4366
+ if (typeof check === "number") {
4367
+ return check === this.sourceFactCount();
4368
+ }
4369
+ return !this.stale && check.unchangedIn(this.db);
4335
4370
  }
4336
4371
  /**
4337
4372
  * How many facts the store has read from source. They are only ever
@@ -6872,7 +6907,8 @@ function importedCallOrigins(sourceFile, resolution, module) {
6872
6907
  const candidates = [];
6873
6908
  forEachDescendantWhere(sourceFile, callsANamedCallee, (node) => {
6874
6909
  const call = node;
6875
- if (!declaredLocally(call.getExpression())) {
6910
+ const callee = call.getExpression();
6911
+ if (!declaredLocally(callee) && !importedFromAnotherPackage(callee, module)) {
6876
6912
  candidates.push(call);
6877
6913
  }
6878
6914
  return false;
@@ -6902,6 +6938,26 @@ function callsNamed(found, names) {
6902
6938
  function callsANamedCallee(raw) {
6903
6939
  return (ts6.isCallExpression(raw) || ts6.isNewExpression(raw)) && ts6.isIdentifier(raw.expression);
6904
6940
  }
6941
+ var samePackage = (specifier, module) => specifier === module || specifier.startsWith(`${module}/`) || module.startsWith(`${specifier}/`);
6942
+ function importOf(declaration) {
6943
+ if (Node14.isImportSpecifier(declaration)) {
6944
+ return declaration.getImportDeclaration();
6945
+ }
6946
+ const parent = Node14.isImportClause(declaration) ? declaration.getParent() : void 0;
6947
+ return parent !== void 0 && Node14.isImportDeclaration(parent) ? parent : void 0;
6948
+ }
6949
+ function importedFromAnotherPackage(callee, module) {
6950
+ const declarations = callee.getSymbol()?.getDeclarations() ?? [];
6951
+ return declarations.length > 0 && declarations.every((declaration) => {
6952
+ const from = importOf(declaration);
6953
+ if (from === void 0) {
6954
+ return false;
6955
+ }
6956
+ const resolved = from.getModuleSpecifierSourceFile();
6957
+ const specifier = from.getModuleSpecifierValue();
6958
+ return (resolved === void 0 || resolved.isInNodeModules()) && !specifier.startsWith(".") && !samePackage(specifier, module);
6959
+ });
6960
+ }
6905
6961
  function declaredLocally(callee) {
6906
6962
  const declarations = callee.getSymbol()?.getDeclarations() ?? [];
6907
6963
  return declarations.length > 0 && declarations.every(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/adapter-typescript",
3
- "version": "0.38.0",
3
+ "version": "0.38.1",
4
4
  "type": "module",
5
5
  "description": "Read a TypeScript or JavaScript codebase with suss and check what each handler returns against every caller, spec and template it can see.",
6
6
  "keywords": [
@@ -48,11 +48,11 @@
48
48
  "typecheck": "tsc --noEmit"
49
49
  },
50
50
  "dependencies": {
51
- "@suss/behavioral-ir": "0.38.0",
52
- "@suss/datalog": "0.38.0",
53
- "@suss/extractor": "0.38.0",
54
- "@suss/resolution": "0.38.0",
55
- "@suss/values": "0.38.0",
51
+ "@suss/behavioral-ir": "0.38.1",
52
+ "@suss/datalog": "0.38.1",
53
+ "@suss/extractor": "0.38.1",
54
+ "@suss/resolution": "0.38.1",
55
+ "@suss/values": "0.38.1",
56
56
  "graphql": "^16.8.0",
57
57
  "picomatch": "^4.0.4",
58
58
  "ts-morph": "^23.0.0",