Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .changeset/runner-typecheck-2917.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
"@object-ui/runner": patch
---

fix(runner): type-check the package at all, and fix the `DataSource` contract violation that hid behind a broken import (#2917)

`@object-ui/runner` was the worst-covered package in the repo: `build` is
`vite build` (transpile only), it had no `type-check` script, and — uniquely —
**no `tsconfig.json` at all**. Nothing had ever type-checked it, despite it being
a published package.

**It was not broken at runtime.** The two bad imports were `import type`, so they
were erased before they could fail, and the one value import
(`emulateBatchTransaction`) does exist. `MockDataSource` is also unreferenced
anywhere in the repo. So this is a correctness and reference-quality fix, not an
outage.

**What the missing check actually hid.** `DataSource` and
`BatchTransactionOperation` were imported from `@object-ui/core`, which does not
export them — they live in `@object-ui/types`. Because that import never
resolved, `class MockDataSource implements DataSource` was silently a no-op, and
three separate commits maintained the class *as if* it were being verified
(`62b9ab510` added `batchTransaction`, `09d9669c7` made `getObjectSchema`
required, `5527388b0` added input validation). With the `implements` clause
inert, a real contract violation survived all three:

```ts
async find(resource: string, params?: any): Promise<any[]> { return []; }
```

`DataSource.find` returns a `QueryResult` envelope, not a bare array. Anyone
copying this mock as the starting point for their own adapter — which is exactly
what its doc comment invites — would hand every consumer an array where `.data`
and `.total` are `undefined`. Now typed as `Promise<QueryResult>` and returning
`{ data: [], total: 0 }`.

Also in this change:

- `packages/runner/tsconfig.json` added, mirroring `apps/console` rather than the
library packages: `runner` is a Vite app, so it wants `bundler` resolution,
`allowImportingTsExtensions` (for `./App.tsx`) and `types: ["vite/client"]`
(for `import.meta.glob` in `MetadataLoader` and the `./index.css` side-effect
import). Keeping it standalone instead of extending the root config also means
it never inherits the root `paths`, so workspace deps resolve through built
`.d.ts` and the TS6059 `rootDir` class of error cannot appear.
- unused parameters prefixed with `_` (6x in `mockDataSource`), and an unused
`Circle` icon import dropped from `LayoutRenderer`.
- `"type-check": "tsc --noEmit"` added, and the package's `DEBT` entry deleted
from `scripts/check-type-check-coverage.mjs`. Coverage goes 35 -> 36 of 45 and
outstanding errors 46 -> 32.

Verified the gate genuinely covers the package now, rather than trusting the
green: injecting a type error into `runner/src/App.tsx` makes `pnpm type-check`
fail with `Failed: @object-ui/runner#type-check`, which was impossible before
this change.
1 change: 1 addition & 0 deletions packages/runner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"scripts": {
"dev": "vite",
"build": "vite build",
"type-check": "tsc --noEmit",
"preview": "vite preview",
"test": "vitest run"
},
Expand Down
1 change: 0 additions & 1 deletion packages/runner/src/LayoutRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
Bell,
Box,
ChevronDown,
Circle,
Menu,
Moon,
Search,
Expand Down
20 changes: 14 additions & 6 deletions packages/runner/src/lib/mockDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,28 @@
* LICENSE file in the root directory of this source tree.
*/

import type { DataSource, BatchTransactionOperation } from '@object-ui/core';
import type {
DataSource,
BatchTransactionOperation,
QueryParams,
QueryResult,
} from '@object-ui/types';
import { emulateBatchTransaction } from '@object-ui/core';

/**
* 模拟数据源 (Mock Adapter)
* 在真实项目中,你会在这里使用 fetch/axios 调用你的 API。
*/
export class MockDataSource implements DataSource {
async find(resource: string, params?: any): Promise<any[]> {
async find(resource: string, params?: QueryParams): Promise<QueryResult> {
console.log(`[DataSource] Querying ${resource}`, params);
return [];
// `find` returns an envelope, not a bare array — consumers read `.data`
// and `.total` (see QueryResult). Returning `[]` here would leave every
// caller with `undefined` data.
return { data: [], total: 0 };
}

async findOne(resource: string, id: string): Promise<any> {
async findOne(_resource: string, _id: string): Promise<any> {
return null;
}

Expand All @@ -33,11 +41,11 @@ export class MockDataSource implements DataSource {
return { id: Math.random().toString(), ...data };
}

async update(resource: string, id: string, data: any): Promise<any> {
async update(_resource: string, _id: string, data: any): Promise<any> {
return data;
}

async delete(resource: string, id: string): Promise<any> {
async delete(_resource: string, _id: string): Promise<any> {
return true;
}

Expand Down
32 changes: 32 additions & 0 deletions packages/runner/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
// Standalone rather than extending the root config: `runner` is a Vite app,
// so it wants the same shape as apps/console — and not inheriting the root
// `paths` keeps `@object-ui/*` resolving through each dependency's built
// `.d.ts` instead of pulling sibling sources in as program inputs.
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,

/* `import.meta.glob` in MetadataLoader, and CSS side-effect imports. */
"types": ["vite/client"]
},
"include": ["src"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"]
}
1 change: 0 additions & 1 deletion scripts/check-type-check-coverage.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
// #2911 sweep (bare `tsc --noEmit` with the `paths` override its type-checked
// peers already carry, so the TS6059 rootDir noise is excluded).
const DEBT = {
"@object-ui/runner": { errors: 14, issue: 2917, note: "no tsconfig.json at all; also imports two exports @object-ui/core does not have" },
"@object-ui/plugin-form": { errors: 10, issue: 2919, note: "6x t() fallback-signature mismatch, 2x undefined index, 2x string|number" },
"@object-ui/site": { errors: 7, issue: 2919, note: "TS2304 on Next's generated LayoutProps/PageProps; needs .next/types from a prior next build" },
"@object-ui/plugin-grid": { errors: 4, issue: 2919, note: "2x t() call signature + 2x TS2367 that are closure-mutation narrowing artifacts, NOT a logic bug" },
Expand Down
Loading