@specific.dev/spectest 0.91.2 → 0.92.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.
@@ -351,11 +351,6 @@ export interface WrapperRuleRun {
351
351
  durationMs: number;
352
352
  }
353
353
 
354
- /** `TypeFlags.Object | TypeFlags.Union` — the only shapes a carrier can wear.
355
- * Filtering on the flags the batch call already returned keeps the printed
356
- * name (one round trip each) off every ordinary `boolean` condition. */
357
- const OBJECT_OR_UNION = (1 << 19) | (1 << 20);
358
-
359
354
  /** Candidate positions, and what each one means if the operand is a carrier. */
360
355
  interface Candidate {
361
356
  node: TsNode;
@@ -431,6 +426,8 @@ export async function runWrapperRules(opts: {
431
426
  configFile: string;
432
427
  /** Only files under here produce diagnostics. */
433
428
  appDir: string;
429
+ /** Restrict eval findings to its submitted module. */
430
+ diagnosticFile?: string;
434
431
  readFile: (p: string) => Promise<string>;
435
432
  relative: (from: string, to: string) => string;
436
433
  join: (...parts: string[]) => string;
@@ -456,6 +453,13 @@ export async function runWrapperRules(opts: {
456
453
  const utils = (await import(opts.join(base, "ast", "utils.js"))) as {
457
454
  formatSyntaxKind(k: number): string;
458
455
  };
456
+ // Native TypeScript's flag values differ from the JavaScript compiler's.
457
+ // Read them from the compiler serving this API; hard-coded TS 5 flags
458
+ // silently miss wrapped boolean unions in TS 7.
459
+ const { TypeFlags } = await import(opts.join(base, "enums", "typeFlags.js")) as {
460
+ TypeFlags: { Object: number; Union: number };
461
+ };
462
+ const objectOrUnion = TypeFlags.Object | TypeFlags.Union;
459
463
  const visitor = (await import(opts.join(base, "ast", "visitor.js"))) as {
460
464
  visitEachChild(n: unknown, cb: (c: unknown) => unknown, ctx: unknown): unknown;
461
465
  };
@@ -505,7 +509,8 @@ export async function runWrapperRules(opts: {
505
509
  const names = await project.program.getSourceFileNames();
506
510
  const files = names.filter(
507
511
  (f) =>
508
- f.startsWith(`${opts.appDir}/`) && !f.includes("/node_modules/") && !f.endsWith(".d.ts"),
512
+ f.startsWith(`${opts.appDir}/`) && !f.includes("/node_modules/") && !f.endsWith(".d.ts") &&
513
+ (!opts.diagnosticFile || f === opts.diagnosticFile),
509
514
  );
510
515
 
511
516
  const diagnostics: WrapperDiagnostic[] = [];
@@ -522,7 +527,7 @@ export async function runWrapperRules(opts: {
522
527
  const printed = new Map<number, string>();
523
528
  for (let i = 0; i < nodes.length; i += 1) {
524
529
  const t = types[i];
525
- if (t && (t.flags & OBJECT_OR_UNION) !== 0) {
530
+ if (t && (t.flags & objectOrUnion) !== 0) {
526
531
  printed.set(i, await project.checker.typeToString(t));
527
532
  }
528
533
  }
package/src/index.ts CHANGED
@@ -796,13 +796,16 @@ export interface ServiceDefinition<
796
796
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
797
797
  export type ServicesMap = Record<string, ServiceDefinition<any>>;
798
798
 
799
- /** Awaited return type of a service's `helpers` factory, or `never` if
800
- * the service doesn't ship one. */
801
- type HelpersOf<D> = D extends {
802
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
803
- helpers: (...args: any) => infer R;
804
- }
805
- ? Awaited<R>
799
+ /** Awaited return type of a service's helpers factory. Check key presence
800
+ * before removing optionality: annotations keep `helpers?`, while plain
801
+ * service literals with no factory must stay out of ctx.svc. */
802
+ type HelpersOf<D> = "helpers" extends keyof D
803
+ ? [NonNullable<D["helpers"]>] extends [never]
804
+ ? never
805
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
806
+ : NonNullable<D["helpers"]> extends (...args: any[]) => infer R
807
+ ? Awaited<R>
808
+ : never
806
809
  : never;
807
810
 
808
811
  /**