Land the six-file fix from upstream PR #1691 by danusha2345 (pr-1691 at 6d0e80d52ae953b22d615bd20c4a4c7758814e60), preserving wasm/native extraction parity and exclusive field-type resolution. Preserve coexistence with the #1566 Map/collection fix merged in #1790, including nested holder.values.get coverage and the unchanged #1566 Unreleased changelog bullet. EXTRACTION_VERSION remains unchanged. Align the existing chained-receiver regression with the fix: a declared service field calls its method, while an anonymous field type does not bind to unrelated same-named project functions. Verified on Linux with Node 22.19.0: - Rebuilt the native kernel and TypeScript/browser distribution. - Both backends change Outbox::send -> Outbox::send into Outbox::send -> Mailer::send, keep Relay::forward -> Mailer::send, and store no self-edges in the issue repro. - Wasm: 224 tests passed; native kernel: 255 tests passed, no skips. - All 10 #1566 resolution cases pass on each backend, plus all four nested-receiver extraction parity cases. Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
233 lines
5.9 KiB
TypeScript
233 lines
5.9 KiB
TypeScript
/**
|
|
* Torture fixture — exercises every TS/TSX extraction path the kernel ports.
|
|
*/
|
|
import React, { forwardRef, memo, useState as useStateAlias } from 'react';
|
|
import * as NS from './namespace-module';
|
|
import DefaultThing from './default-module';
|
|
import './side-effect';
|
|
import { helperFn, CONFIG_TABLE } from './helpers';
|
|
|
|
export { reExported, orig as aliased } from './barrel-source';
|
|
export * from './star-source';
|
|
|
|
// A documented constant table (value-ref target).
|
|
const RETRY_LIMITS = { a: 1, b: 2 };
|
|
export const API_BASE = 'https://example.test';
|
|
let plainLet = 42;
|
|
var oldVar = 'x';
|
|
|
|
/** Class docs.
|
|
* Multi-line.
|
|
*/
|
|
@Injectable()
|
|
@scoped.Registry<Config>('name')
|
|
export abstract class BaseService extends EventTarget implements Disposable, Serializable {
|
|
static instances = 0;
|
|
private readonly cache: Map<string, Config> = new Map();
|
|
public fonts: FontConfig;
|
|
count = 0;
|
|
onScroll = throttle((e: Event) => {
|
|
this.handleScroll(e);
|
|
}, 100);
|
|
handleClick = (ev: MouseEvent): void => {
|
|
emitTelemetry(ev);
|
|
new AbortController();
|
|
};
|
|
|
|
@Get('/list')
|
|
async list(query: QueryOpts): Promise<Result<Item>> {
|
|
const local: ItemMapper = makeMapper();
|
|
const limit = RETRY_LIMITS;
|
|
return this.cache.get(query.key) ?? helperFn(query);
|
|
}
|
|
|
|
private static compute(n: number): number {
|
|
return n * RETRY_LIMITS.a;
|
|
}
|
|
|
|
get size(): number {
|
|
return this.count;
|
|
}
|
|
|
|
protected dispose(): void {
|
|
listeners.forEach((l) => unregister(l));
|
|
}
|
|
}
|
|
|
|
class Plain {
|
|
constructor(private svc: BaseService) {
|
|
register(this.onEvent);
|
|
btn.on('click', this.handleClick);
|
|
}
|
|
onEvent() {}
|
|
handleClick() {}
|
|
}
|
|
|
|
export interface Shape extends Named, Sized {
|
|
area: number;
|
|
resize(f: number): Shape;
|
|
onchange: (s: Shape) => void;
|
|
}
|
|
|
|
export enum Direction {
|
|
Up,
|
|
Down = 2,
|
|
Left,
|
|
}
|
|
|
|
export type Handle = {
|
|
stop: () => void;
|
|
id: string;
|
|
refresh(force: boolean): Promise<void>;
|
|
};
|
|
|
|
export type ServiceList = [
|
|
Service<'query_apply_record', Req, Resp>,
|
|
Service<'apply_confirm', Req, Resp>,
|
|
];
|
|
|
|
export type MaybeShape = Shape | null;
|
|
|
|
export function topLevel(a: ShapeConfig): Shape {
|
|
const inner = () => reallyDeep();
|
|
function namedInner(): void {
|
|
chained(a).value;
|
|
}
|
|
namedInner();
|
|
return makeShape(a);
|
|
}
|
|
|
|
async function* generatorFn(items: Item[]) {
|
|
yield* items.map((i) => transform(i));
|
|
}
|
|
|
|
export const arrowConst = async (x: number) => {
|
|
return x + plainLet;
|
|
};
|
|
|
|
const AnonClassHolder = class {
|
|
method() {}
|
|
};
|
|
|
|
// React components (#841).
|
|
export const Button = forwardRef((props: ButtonProps, ref) => {
|
|
const [state, setState] = useStateAlias(0);
|
|
useEffect(() => {
|
|
trackRender();
|
|
});
|
|
return <BaseButton ref={ref} onClick={() => setState(state + 1)} {...props} />;
|
|
});
|
|
|
|
export const MemoRow = memo(function Row(props: RowProps) {
|
|
return <tr className={props.cls}>{props.children}</tr>;
|
|
});
|
|
|
|
export const Wrapped = React.memo(ImportedComponent);
|
|
export const Styled = styled.button`
|
|
color: red;
|
|
`;
|
|
const memoCache = memo(computeThing); // lowercase — stays a constant
|
|
|
|
export function App() {
|
|
const nodes: GraphNode[] = [];
|
|
return (
|
|
<div>
|
|
<Button label={CONFIG_TABLE.label} />
|
|
<NS.Panel />
|
|
{nodes.map((n) => (
|
|
<MemoRow key={n.id} cls={n.cls} />
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Object-of-functions (SvelteKit-style actions map).
|
|
export const actionsMap = {
|
|
create: async (input: CreateInput) => {
|
|
return persistNew(input);
|
|
},
|
|
update(input: UpdateInput) {
|
|
return persistExisting(input);
|
|
},
|
|
};
|
|
|
|
// Zustand-style store through middleware wrappers.
|
|
export const useStore = create(
|
|
persist(
|
|
(set, get) => ({
|
|
fetchUser: async (id: string) => {
|
|
const user = await api.load(id);
|
|
set({ user });
|
|
},
|
|
reset: () => set({ user: null }),
|
|
}),
|
|
{ name: 'store' }
|
|
)
|
|
);
|
|
|
|
// RTK Query.
|
|
export const widgetApi = createApi({
|
|
reducerPath: 'widgets',
|
|
endpoints: (build) => ({
|
|
getWidget: build.query({
|
|
query: (id: string) => fetchWidget(id),
|
|
}),
|
|
updateWidget: build.mutation({
|
|
queryFn: async (patch) => {
|
|
return applyPatch(patch);
|
|
},
|
|
}),
|
|
prebuilt: build.query(makeEndpointConfig()),
|
|
}),
|
|
});
|
|
|
|
export const { useGetWidgetQuery, useUpdateWidgetMutation } = widgetApi;
|
|
const { notAHook } = widgetApi;
|
|
|
|
// Value-ref shadowing: SHADOWED_LIMIT re-bound locally must be pruned.
|
|
const SHADOWED_LIMIT = 10;
|
|
export function readsShadowed() {
|
|
const SHADOWED_LIMIT = 20;
|
|
return SHADOWED_LIMIT;
|
|
}
|
|
export function readsTable() {
|
|
return RETRY_LIMITS.b + API_BASE.length;
|
|
}
|
|
|
|
// Fn-ref registrations.
|
|
registerHandler(helperFn);
|
|
queueMicrotask(topLevel);
|
|
const routeTable = { home: topLevel, missing: notDefinedAnywhere };
|
|
const handlerList = [helperFn, DefaultThing];
|
|
target.cb = topLevel;
|
|
const aliasFn = topLevel;
|
|
|
|
// Calls with interesting callees.
|
|
;(topLevel)(cfg);
|
|
NS.helper.deep(1);
|
|
"literal".includes('x');
|
|
[1, 2].map(String);
|
|
obj?.optMethod?.(3);
|
|
import('./dynamic-module');
|
|
new NS.Widget(makeArg());
|
|
new Map<string, number>();
|
|
super_weird?.();
|
|
|
|
// --- call through a field of the enclosing class (#1496) ---------------------
|
|
export class FieldDelegator {
|
|
constructor(private readonly mailer: { send(m: string): string }, private items: string[]) {}
|
|
send(msg: string): string { return this.mailer.send(msg); }
|
|
push(msg: string): void { this.items.push(msg); this.mailer.send(msg).trim(); }
|
|
direct(): void { this.send('x'); super.toString(); }
|
|
}
|
|
|
|
// --- const-bound functions inside a body (#1669) -----------------------------
|
|
export function NestedHandlers({ items, onPick }: { items: string[]; onPick: (a: unknown, b: unknown) => void }) {
|
|
const handleClear = () => { onPick(null, null); };
|
|
const describe = function (item: string) { return formatLabel(item); };
|
|
let later = (x: string) => parseLabel(x);
|
|
const count = items.length;
|
|
const [a, b] = [() => 1, () => 2];
|
|
return items.map((i) => <button onClick={handleClear} onDoubleClick={() => describe(i)}>{later(i)}{count}{a()}{b()}</button>);
|
|
}
|