Merge remote-tracking branch 'origin/master' into worktree-locale

# Conflicts:
#	packages/client/ui-slots/src/index.ts
This commit is contained in:
imccyu
2026-07-30 01:53:28 +08:00
100 changed files with 1438 additions and 560 deletions

View File

@@ -601,7 +601,7 @@ function backscanGoal(log: readonly SessionEvent[]): FxGoalProjection | null {
const source = event.data?.source
if (source?.kind !== 'goal' || source.round !== 0) continue
const change = source.change
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
// oxlint-disable-next-line typescript/no-unnecessary-condition
if (change === undefined || change.kind !== 'goal/change') continue
if (change.operation === 'clear') return null
return { goal: change.goal, roundsStarted: change.roundsStarted, createdAt: change.createdAt, updatedAt: change.updatedAt }

View File

@@ -32,7 +32,7 @@ const install: InvariantInstaller = (ctx, fail) => {
const baselines = new WeakMap<Fiber, number>()
// Async listener by design: emitPluginDisposed awaits-and-logs returned
// promises, so a violation surfaces loudly instead of unhandled.
// eslint-disable-next-line @typescript-eslint/no-misused-promises
// oxlint-disable-next-line typescript/no-misused-promises
ctx.on('internal/plugin', async (fiber) => {
if (fiber.name !== 'client-hmr') return
if (fiber.uid !== null) {

View File

@@ -4,7 +4,7 @@
* preference row into the settings General section — the locale feature owns
* its own settings surface.
*/
/* eslint-disable @typescript-eslint/no-redundant-type-constituents --
/* oxlint-disable typescript/no-redundant-type-constituents --
* `keyof LocaleNamespaceMap & string` is the declare-merge key pattern (see
* ui-slots): in THIS unit the map holds only this package's own merges, but
* consumers merge more namespaces in and the intersection keeps them

View File

@@ -9,7 +9,7 @@
* with the last holding entry, session instances cleared (with persisted
* state) on scope death.
*/
/* eslint-disable @typescript-eslint/no-redundant-type-constituents --
/* oxlint-disable typescript/no-redundant-type-constituents --
* `keyof SlotMap & string` is the declare-merge key pattern: SlotMap only
* holds this package's 'root' row in this compilation unit, but consumers
* merge keys in; the rule fires on the narrow-map view, not on real
@@ -270,7 +270,7 @@ export class SlotsService extends Service {
// on the locale plugin's own fiber lifetime, while this host object is
// built once — a captured value would strand renders on a dead face. The
// alias is required: `this` inside the getter is the host literal.
// eslint-disable-next-line @typescript-eslint/no-this-alias
// oxlint-disable-next-line typescript/no-this-alias
const service = this
this._host = {
subscribe: (key, fn) => this._core.subscribe(key, fn),
@@ -337,6 +337,6 @@ export class SlotsService extends Service {
// The core's overloads proved the shares; the implementation works on
// the erased view (same pattern as the core's own implementation arm).
const options = rawOptions as ErasedRegisterOptions
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
// oxlint-disable-next-line typescript/no-misused-promises -- synchronous cleanup; direct return preserves disposer identity
return this.ctx.effect(() => this['_register'](options, component), 'slots.register()')
}

View File

@@ -4,7 +4,7 @@
*/
/* jscpd:ignore-start */
/* eslint-disable @typescript-eslint/no-redundant-type-constituents --
/* oxlint-disable typescript/no-redundant-type-constituents --
* `keyof SlotMap & string` is the declare-merge key pattern: SlotMap is empty
* in this compilation unit (intersection reads `never`) but consumers merge
* keys in; the rule fires on the empty-map view, not on real redundancy. */

View File

@@ -10,7 +10,7 @@
* machinery — everything mounts the production implementations.
* @module @deepseek-ai/dsh-client-test-runtime
*/
/* eslint-disable @typescript-eslint/no-redundant-type-constituents --
/* oxlint-disable typescript/no-redundant-type-constituents --
* `keyof SlotMap & string` is the declare-merge key pattern (see ui-slots):
* this compilation unit sees only the runtime's 'root' row, but consumer
* programs merge their own keys in; the rule fires on the narrow-map view. */

View File

@@ -8,7 +8,7 @@
export async function writeClipboard(text: string): Promise<void> {
// lib.dom types clipboard non-optional, but insecure contexts omit it —
// that runtime gap is exactly what this guard detects.
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */
/* oxlint-disable-next-line typescript/no-unnecessary-condition */
if (navigator.clipboard?.writeText) {
try {
await navigator.clipboard.writeText(text)
@@ -19,7 +19,7 @@ export async function writeClipboard(text: string): Promise<void> {
}
// execCommand('copy') is the only clipboard fallback where the async API
// is missing (insecure contexts); deprecated but deliberately retained.
/* eslint-disable @typescript-eslint/no-deprecated */
/* oxlint-disable typescript/no-deprecated */
const exec = typeof document.execCommand === 'function'
? document.execCommand.bind(document)
: undefined
@@ -36,7 +36,7 @@ export async function writeClipboard(text: string): Promise<void> {
} catch {
// Clipboard unavailable; the button stays idle.
}
/* eslint-enable @typescript-eslint/no-deprecated */
/* oxlint-enable typescript/no-deprecated */
el.remove()
}

View File

@@ -105,7 +105,7 @@ export function InputBar({
// IME guard so a composition-closing Shift+Enter still breaks the line.
if (e.key === 'Enter' && e.shiftKey) return
// keyCode 229 is the legacy IME-composition signal engines emit without isComposing.
// eslint-disable-next-line @typescript-eslint/no-deprecated
// oxlint-disable-next-line typescript/no-deprecated
const composing = composingRef.current || e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
if (keyboard.arbitrate(e.key === 'ArrowUp' ? 'up' : 'down', composing) === 'consumed') e.preventDefault()
@@ -165,8 +165,8 @@ export function InputBar({
if (machineBusy) return // submitting is the read-only span; adjudicating holds the pending lock
const next = e.target.value
keyboard.setDraft(next)
// selectionStart is number|null in lib.dom; the eslint program narrows it.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
// selectionStart is number|null in lib.dom; the type-aware lint program narrows it.
// oxlint-disable-next-line typescript/no-unnecessary-condition
keyboard.track(next, e.target.selectionStart ?? next.length)
}
@@ -178,13 +178,13 @@ export function InputBar({
// too (one char = one step). Mouse selection of a chip is handled in the
// backdrop click handler below. Undo/redo must NOT reach the browser: the
// machine owns the transaction log.
// selectionStart/End are number|null in lib.dom; the eslint program narrows them.
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
// selectionStart/End are number|null in lib.dom; the type-aware lint program narrows them.
/* oxlint-disable typescript/no-unnecessary-condition */
const selectionOf = (el: HTMLTextAreaElement) => ({
start: el.selectionStart ?? 0,
end: el.selectionEnd ?? el.selectionStart ?? 0,
})
/* eslint-enable @typescript-eslint/no-unnecessary-condition */
/* oxlint-enable typescript/no-unnecessary-condition */
const onCopyOrCut = (e: React.ClipboardEvent<HTMLTextAreaElement>, cut: boolean): void => {
const el = e.currentTarget

View File

@@ -12,7 +12,7 @@
export async function writeClipboard(text: string): Promise<boolean> {
// lib.dom types clipboard non-optional, but insecure contexts omit it —
// that runtime gap is exactly what this guard detects.
/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */
/* oxlint-disable-next-line typescript/no-unnecessary-condition */
if (navigator.clipboard?.writeText) {
try {
await navigator.clipboard.writeText(text)
@@ -25,7 +25,7 @@ export async function writeClipboard(text: string): Promise<boolean> {
// jsdom and older hosts: best-effort execCommand path when present.
// execCommand('copy') is the only clipboard fallback where the async API
// is missing; deprecated but deliberately retained.
/* eslint-disable @typescript-eslint/no-deprecated */
/* oxlint-disable typescript/no-deprecated */
const exec = typeof document.execCommand === 'function'
? document.execCommand.bind(document)
: undefined
@@ -44,5 +44,5 @@ export async function writeClipboard(text: string): Promise<boolean> {
} finally {
el.remove()
}
/* eslint-enable @typescript-eslint/no-deprecated */
/* oxlint-enable typescript/no-deprecated */
}

View File

@@ -16,7 +16,7 @@ export function JsonBlock({ label, payload, defaultOpen = false }: {
let s: string
try {
// lib typing hides stringify's undefined arm (undefined/function/symbol payloads).
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
// oxlint-disable-next-line typescript/no-unnecessary-condition
s = JSON.stringify(payload, null, 2) ?? String(payload)
} catch {
s = String(payload)

View File

@@ -41,7 +41,7 @@ export function parseQuestionTitle(title: string): string {
/** Return whether a textarea key event belongs to an active IME composition. */
function isComposing(event: KeyboardEvent<HTMLTextAreaElement>): boolean {
// keyCode 229 is the legacy IME-composition signal engines emit without isComposing.
// eslint-disable-next-line @typescript-eslint/no-deprecated
// oxlint-disable-next-line typescript/no-deprecated
return event.nativeEvent.isComposing || event.nativeEvent.keyCode === 229
}
@@ -70,9 +70,9 @@ function QuestionFlow({ pending, t }: { pending: PendingQuestion } & Pick<Questi
// failure messages (finished strings from the wire) pass through verbatim.
const [error, setError] = useState<{ key: 'error.incomplete' | 'error.unanswered' } | { text: string } | null>(null)
// index stays in bounds (every setIndex site clamps) and drafts mirrors questions 1:1.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
// oxlint-disable-next-line typescript/no-non-null-assertion
const question = questions[index]!
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
// oxlint-disable-next-line typescript/no-non-null-assertion
const draft = drafts[index]!
const hasOptions = (question.options?.length ?? 0) > 0

View File

@@ -8,7 +8,7 @@
* consumer `declare module` augmentation merges with declarations lexically in
* the augmented module, not with re-exports.
*/
/* eslint-disable @typescript-eslint/no-redundant-type-constituents --
/* oxlint-disable typescript/no-redundant-type-constituents --
* `keyof SlotMap & string` is the declare-merge key pattern: SlotMap is empty
* in THIS compilation unit (so the intersection reads as `never`), but every
* consumer merges keys in and the intersection is what keeps them string-typed.
@@ -423,7 +423,7 @@ interface ErasedOptions {
children?: Record<string, SlotSpec<SlotEntryDef>> | undefined
store?: StoreDecl | undefined
locale?: string | undefined
/* eslint-disable-next-line @typescript-eslint/no-explicit-any --
/* oxlint-disable-next-line typescript/no-explicit-any --
* implementation-signature position only (both public overloads type inject
* exactly); `never[]` would fail overload-to-implementation compatibility
* against the per-declaration InjectParams tuples. */

View File

@@ -21,7 +21,7 @@ export type MaybeSnapshotSelectorHook<T> =
* declared as the store's complete write set (the audit face — components can
* only write through these).
*/
/* eslint-disable-next-line @typescript-eslint/no-explicit-any --
/* oxlint-disable-next-line typescript/no-explicit-any --
* any[] (not unknown[]): each action carries its own parameter list, and
* unknown[] would reject every concrete signature under strict parameter
* contravariance. Params are re-inferred per action by BakedActions. */
@@ -95,14 +95,14 @@ export interface StoreHandle<T, A extends ActionsDecl<T>> {
* Exclusive-store registration form: the registrant passes the factory itself
* and the framework calls it per entry x scope (no shared identity exists).
*/
/* eslint-disable-next-line @typescript-eslint/no-explicit-any --
/* oxlint-disable-next-line typescript/no-explicit-any --
* erased position accepting every StoreHandle instantiation; T/A are
* recovered per use site by conditional inference (HandleOf/BoundActions/
* PropsStore). */
export type StoreFactory = () => StoreHandle<any, any>
/** The register `store` option position: a shared handle or an exclusive factory. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- same erased-constraint position as StoreFactory (see above).
// oxlint-disable-next-line typescript/no-explicit-any -- same erased-constraint position as StoreFactory (see above).
export type StoreDecl = StoreHandle<any, any> | StoreFactory
/** Normalize a store declaration to its handle type (factories yield their return). */

View File

@@ -41,7 +41,7 @@ describe('tsdown client artifact', () => {
// Same execution form the loader uses (inline script eval, window scope) —
// the implied-eval ban targets accidental string execution, not this
// deliberate bundle-execution fixture.
// eslint-disable-next-line @typescript-eslint/no-implied-eval, @typescript-eslint/no-unsafe-call
// oxlint-disable-next-line typescript/no-implied-eval, typescript/no-unsafe-call
new Function(code!)()
expect(handoff).toBeDefined()
const modules = new Map<string, unknown>([