@@ -610,7 +610,8 @@ func TestTscDeclarationEmit(t *testing.T) {
610610 "type": "module"
611611 }` ),
612612 "/home/src/workspaces/project/node_modules/ky/distribution/index.d.ts" : stringtestutil .Dedent (`
613- type KyInstance = {
613+ declare class KyInstance {
614+ private brand;
614615 extend(options: Record<string,unknown>): KyInstance;
615616 }
616617 declare const ky: KyInstance;
@@ -2481,6 +2482,185 @@ func TestTscIncremental(t *testing.T) {
24812482 noChange ,
24822483 },
24832484 },
2485+ {
2486+ subScenario : "recursive function declaration consumption" ,
2487+ files : FileMap {
2488+ "/home/src/workspaces/project/producer/tsconfig.json" : `{
2489+ "compilerOptions": { "strict": true, "composite": true, "outDir": "dist" }
2490+ }` ,
2491+ "/home/src/workspaces/project/producer/index.ts" : stringtestutil .Dedent (`
2492+ export const arrow = () => arrow;
2493+ export const expression = function self() { return self; };
2494+ export const first = () => second;
2495+ export const second = () => first;
2496+ export const generic = <T>(value: T) => generic;
2497+ export const objectReturn = () => ({ call: objectReturn });
2498+ export const tupleReturn = () => [tupleReturn] as const;
2499+ export const shadowed = function self(shadowed: number) { return self; };
2500+ export const object = { value: 1, next: () => object };
2501+ export const method = { value: 1, next() { return method; } };
2502+ export const accessor = { value: 1, get next() { return accessor; } };
2503+ export const tuple = [() => tuple] as const;
2504+ export const array = [() => array];
2505+ export const nested = { inner: { next() { return nested.inner; } } };
2506+ export const memberTuple = [function self() { return self; }] as const;
2507+ export const memberArray = [function self() { return self; }];
2508+ export const quoted = { "a-b": function self() { return self; } };
2509+ export const numeric = { 0: function self() { return self; } };
2510+ export const key = Symbol();
2511+ export const computed = { [key]: function self() { return self; } };
2512+ export const union = true as boolean ? { next: () => union } : undefined;
2513+ function create<T>(value: T) {
2514+ const result = { value, next: () => result };
2515+ return result;
2516+ }
2517+ export const specialized = create("text");
2518+ function createIndexed() {
2519+ const value: { [key: string]: typeof value } = {};
2520+ return value;
2521+ }
2522+ export const indexed = createIndexed();
2523+ function createMapped<T>() {
2524+ const value: { [K in keyof T]: typeof value } = null!;
2525+ return value;
2526+ }
2527+ export const mapped = createMapped<{ next: unknown }>();
2528+ function createAnnotated<T>(value: T) {
2529+ const node: { value: T; next: () => typeof node } = { value, next: () => node };
2530+ return node;
2531+ }
2532+ export const viaAnnotation = createAnnotated("text");
2533+ export type Link<T> = { value: T; next: Link<T> };
2534+ export type Callable<T> = { (value: T): Callable<T>; link: Link<T> };
2535+ export declare const link: Link<string>;
2536+ export declare const callable: Callable<number>;
2537+ export const nextLink = link.next;
2538+ export const nextCallable = callable(1);
2539+ function createHidden<T>(value: T) {
2540+ type Hidden = { value: T; next: Hidden };
2541+ return null! as Hidden;
2542+ }
2543+ export const hiddenAlias = createHidden("text");
2544+ export const siblingHiddenAliases = { first: hiddenAlias, second: hiddenAlias };
2545+ export const parenthesized = (function self() { return self; });
2546+ export const asserted = (function self() { return self; }) satisfies () => unknown;
2547+ export class Methods {
2548+ static recur() { return Methods.recur; }
2549+ static "a-b"() { return Methods["a-b"]; }
2550+ static [key]() { return Methods[key]; }
2551+ recur() { return this.recur; }
2552+ }
2553+ export function overloaded(value: string): typeof overloaded;
2554+ export function overloaded(value: number): typeof overloaded;
2555+ export function overloaded(value: string | number) { return overloaded; }
2556+ export const nestedOwner = {
2557+ make<T>(outer: T) {
2558+ return {
2559+ nested<U>(inner: U) { return { outer, inner, owner: nestedOwner }; },
2560+ constrained<U extends T = T>(inner: U) { return { outer, inner, owner: nestedOwner }; },
2561+ copied<U>(inner: U): { outer: T; inner: U; owner: typeof nestedOwner } {
2562+ return { outer, inner, owner: nestedOwner };
2563+ },
2564+ rest<U>(...values: [U]) { return { outer, inner: values[0], owner: nestedOwner }; },
2565+ };
2566+ },
2567+ };
2568+ export const nestedNumber = nestedOwner.make(1);
2569+ ` ),
2570+ "/home/src/workspaces/project/consumer/tsconfig.json" : `{
2571+ "compilerOptions": { "strict": true, "noEmit": true },
2572+ "references": [{ "path": "../producer" }]
2573+ }` ,
2574+ "/home/src/workspaces/project/consumer/index.ts" : stringtestutil .Dedent (`
2575+ import { arrow, expression, first, generic, objectReturn, tupleReturn, shadowed } from "../producer/dist/index.js";
2576+ import { object, method, accessor, tuple, array, nested } from "../producer/dist/index.js";
2577+ import { memberTuple, memberArray, quoted, numeric, key, computed, union, specialized } from "../producer/dist/index.js";
2578+ import { indexed, mapped, viaAnnotation } from "../producer/dist/index.js";
2579+ import { nextLink, nextCallable, parenthesized, asserted, Methods, overloaded } from "../producer/dist/index.js";
2580+ import { hiddenAlias, siblingHiddenAliases } from "../producer/dist/index.js";
2581+ import { nestedNumber } from "../producer/dist/index.js";
2582+ const a: typeof arrow = arrow()()();
2583+ const b: typeof expression = expression()()();
2584+ const c: typeof first = first()()();
2585+ const d: typeof generic = generic(1)("text")(true);
2586+ const objectCall: typeof objectReturn = objectReturn().call().call;
2587+ const tupleCall: typeof tupleReturn = tupleReturn()[0]()[0];
2588+ const shadowedCall: typeof shadowed = shadowed(1)(2);
2589+ const objectValue: number = object.next().next().value;
2590+ const methodValue: number = method.next().next().value;
2591+ const accessorValue: number = accessor.next.next.value;
2592+ const tupleValue: typeof tuple = tuple[0]()[0]();
2593+ const arrayValue: typeof array = array[0]()[0]();
2594+ const nestedValue: typeof nested.inner = nested.inner.next().next();
2595+ const memberTupleValue: typeof memberTuple[0] = memberTuple[0]()();
2596+ const memberArrayValue: typeof memberArray[0] = memberArray[0]()();
2597+ const quotedValue: typeof quoted["a-b"] = quoted["a-b"]()();
2598+ const numericValue: typeof numeric[0] = numeric[0]()();
2599+ const computedValue: typeof computed[typeof key] = computed[key]()();
2600+ const unionValue: typeof union = union?.next()?.next();
2601+ const specializedValue: string = specialized.next().next().value;
2602+ const indexedValue: typeof indexed = indexed["next"]["next"];
2603+ const mappedValue: typeof mapped = mapped.next.next;
2604+ const annotationValue: string = viaAnnotation.next().next().value;
2605+ const linkValue: string = nextLink.next.next.value;
2606+ const callableValue: number = nextCallable(1)(2).link.next.value;
2607+ const parenthesizedValue: typeof parenthesized = parenthesized()()();
2608+ const assertedValue: typeof asserted = asserted()()();
2609+ const methodReference: typeof Methods.recur = Methods.recur()()();
2610+ const quotedMethodReference: typeof Methods["a-b"] = Methods["a-b"]()()();
2611+ const computedMethodReference: typeof Methods[typeof key] = Methods[key]()()();
2612+ const instance = new Methods();
2613+ const instanceMethodReference: typeof instance.recur = instance.recur()()();
2614+ const overloadReference: typeof overloaded = overloaded(1)("text")(2);
2615+ const hiddenValue: string = hiddenAlias.next.next.value;
2616+ const siblingHiddenValue: string = siblingHiddenAliases.second.next.next.value;
2617+ const nestedString = nestedNumber.nested(true).owner.make("text").nested(2);
2618+ const nestedBoolean = nestedString.owner.make(true).nested("inner");
2619+ const nestedStringOuter: string = nestedString.outer;
2620+ const nestedStringInner: number = nestedString.inner;
2621+ const nestedBooleanOuter: boolean = nestedBoolean.outer;
2622+ const nestedBooleanInner: string = nestedBoolean.inner;
2623+ const constrainedOuter: number = nestedNumber.constrained(2).outer;
2624+ const constrainedInner: number = nestedNumber.constrained(2).inner;
2625+ const copiedOuter: number = nestedNumber.copied("inner").outer;
2626+ const copiedInner: string = nestedNumber.copied("inner").inner;
2627+ const restOuter: number = nestedNumber.rest(true).outer;
2628+ const restInner: boolean = nestedNumber.rest(true).inner;
2629+ type IsAny<T> = 0 extends (1 & T) ? true : false;
2630+ const result = arrow()()();
2631+ const notAny: false = null as unknown as IsAny<typeof result>;
2632+ const invalid: number = arrow()()();
2633+ const invalidExpression: number = expression()()();
2634+ const invalidObject: number = objectReturn().call;
2635+ const invalidTuple: number = tupleReturn()[0];
2636+ const invalidShadowed: number = shadowed(1);
2637+ const invalidObjectValue: string = object.next().value;
2638+ const invalidTupleValue: number = tuple[0]();
2639+ const invalidSpecialized: number = specialized.next().value;
2640+ const invalidMapped: number = mapped.next;
2641+ const invalidAnnotation: number = viaAnnotation.next().value;
2642+ const invalidLink: number = nextLink.next.value;
2643+ const invalidCallable: string = nextCallable(1).link.value;
2644+ const invalidHiddenValue: number = hiddenAlias.next.next.value;
2645+ const invalidMethod: number = Methods.recur()();
2646+ const invalidComputedMethod: number = Methods[key]()();
2647+ const invalidNestedOuter: boolean = nestedString.outer;
2648+ const invalidNestedInner: string = nestedString.inner;
2649+ nestedNumber.constrained("wrong");
2650+ ` ),
2651+ },
2652+ commandLineArgs : []string {"--build" , "consumer" },
2653+ edits : []* tscEdit {
2654+ noChange ,
2655+ {
2656+ caption : "add a comment to the producer" ,
2657+ edit : func (sys * TestSys ) {
2658+ sys .appendFile ("/home/src/workspaces/project/producer/index.ts" , "\n // comment-only edit\n " )
2659+ },
2660+ },
2661+ noChange ,
2662+ },
2663+ },
24842664 {
24852665 subScenario : "json module diagnostics are cleared after fixing the json file" ,
24862666 files : FileMap {
0 commit comments