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
31 changes: 25 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,16 @@ npm install @object-ui/app-shell @object-ui/plugin-view @object-ui/providers

Then build your own console in ~100 lines:
```tsx
import type { FC } from 'react';
import { AppShell } from '@object-ui/app-shell';
import { ObjectView } from '@object-ui/plugin-view';
import { ThemeProvider, DataSourceProvider, useDataSource } from '@object-ui/providers';
import type { DataSource } from '@object-ui/types';

// The two pieces you bring: the backend adapter you implement (see "Custom
// Data Sources" below) and your own sidebar component.
declare const myAPI: DataSource;
declare const MySidebar: FC;

function MyConsole() {
return (
Expand Down Expand Up @@ -135,13 +142,15 @@ See [examples/byo-backend-console](examples/byo-backend-console) for a complete

**Stop Writing Repetitive UI Code**
```tsx
import type { ObjectFormSchema } from '@object-ui/types';

// Traditional React: 200+ lines
function UserForm() {
// ... useState, validation, handlers, JSX
}

// Object UI: 20 lines
const schema = {
const schema: ObjectFormSchema = {
type: "object-form",
objectName: "user",
mode: "create",
Expand Down Expand Up @@ -381,6 +390,11 @@ npm install @object-ui/data-objectstack

```typescript
import { createObjectStackAdapter } from '@object-ui/data-objectstack';
import { SchemaRenderer } from '@object-ui/react';
import type { BaseSchema } from '@object-ui/types';

// Your page schema — "Basic Usage" above writes one out in full.
declare const schema: BaseSchema;

const dataSource = createObjectStackAdapter({
baseUrl: 'https://api.example.com',
Expand All @@ -398,11 +412,16 @@ You can create adapters for any backend (REST, GraphQL, Firebase, etc.) by imple
```typescript
import type { DataSource, QueryParams, QueryResult } from '@object-ui/types';

class MyCustomDataSource implements DataSource {
async find(resource: string, params?: QueryParams): Promise<QueryResult> {
// Your implementation
}
// ... other methods
// The members `DataSource` REQUIRES — declared here without bodies, so the
// contract is complete instead of elided. Every other member of the interface
// is optional: implement the ones your backend supports.
declare class MyCustomDataSource<T = unknown> implements DataSource<T> {
find(resource: string, params?: QueryParams): Promise<QueryResult<T>>;
findOne(resource: string, id: string | number, params?: QueryParams): Promise<T | null>;
create(resource: string, data: Partial<T>): Promise<T>;
update(resource: string, id: string | number, data: Partial<T>, opts?: { ifMatch?: string }): Promise<T>;
delete(resource: string, id: string | number, opts?: { ifMatch?: string }): Promise<boolean>;
getObjectSchema(objectName: string): Promise<unknown>;
}
```

Expand Down
32 changes: 23 additions & 9 deletions scripts/__tests__/check-doc-snippet-types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -584,21 +584,35 @@ describe('this repository', () => {
* `check-doc-component-types.mjs` walked `content/docs`, and the repository's
* landing page fell between them.
*
* ⚠️ Read the second assertion carefully. Being ON the ungated ledger is NOT a
* claim that this file compiles — it does not; objectui#7417 carries its nine
* measured diagnostics. It is the objectui#5174 distinction, which this script's
* own header states: a document outside the walk is "neither covered NOR
* declared ungated", invisible to the gate's own accounting, while a ledgered
* one is named, counted, re-derived every run and shrink-only.
* ⚠️ Read the second assertion carefully — and read what it USED to say, because
* the flip is the point. It pinned this page as DECLARED debt: on the ungated
* ledger, with a reason naming objectui#7417. That was never a claim the page
* compiled; it was the objectui#5174 distinction this script's own header states
* — a document outside the walk is "neither covered NOR declared ungated",
* invisible to the gate's own accounting, while a ledgered one is named,
* counted, re-derived every run and shrink-only.
*
* objectui#5174's last batch paid the debt down: the page's five ts/tsx blocks
* compile against the built `dist/*.d.ts`, so the row came off and the ledger
* reached ZERO. The assertion therefore pins the far end of that walk — NOT on
* the ledger, and actually contributing blocks to the compiled tier. Both halves
* are load-bearing: a page can leave the ledger by having no ts/tsx block left
* at all, which is coverage of nothing, and only the second half tells the two
* apart.
*/
describe('objectui#7115 — the root README is in the scan set', () => {
it('listDocuments reaches it', () => {
expect(listDocuments(repoRoot)).toContain('README.md');
});

it('is DECLARED debt rather than absent, and its reason names the card that carries it', () => {
expect(Object.keys(UNGATED_DOCS as Record<string, string>)).toContain('README.md');
expect((UNGATED_DOCS as Record<string, string>)['README.md']).toContain('objectui#7417');
it('is COVERED and actually judged — off the ledger, with blocks in the compiled tier', () => {
expect(Object.keys(UNGATED_DOCS as Record<string, string>)).not.toContain('README.md');
const state = analyze({});
expect(state.covered as string[]).toContain('README.md');
expect(
(state.compiled as Array<{ doc: string }>).filter((b) => b.doc === 'README.md').length,
'off the ledger with no block left would be coverage of nothing',
).toBeGreaterThan(0);
});

it('root pages are collected BY NAME, not by the packages walk', () => {
Expand Down
61 changes: 17 additions & 44 deletions scripts/check-doc-snippet-types.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -615,18 +615,22 @@ const TS_FENCE_LANGUAGES = new Set(['ts', 'tsx', 'typescript']);
* Documents whose snippets are NOT compiled, each with the reason. The default
* is covered; this list is the debt, by name, and it can only shrink.
*
* ⚠️ ZERO of these entries are now `.md` pages under `content/docs`. There were 19
* when objectui#5174 made them visible — the collector reads `.md`, and an entry
* with a measured reason is what a page that cannot pass yet is owed — and that
* card then walked every one of them back OFF this list rather than re-wording its
* reason. The direction on that card was entries LEAVING, and it finished: what
* remains here is `.mdx` pages under `content/docs` plus package READMEs, and the
* ENTRIES BELOW are that list — re-derived every run and shrink-only, so the names
* in it are the count. This sentence carried the literal `12 .mdx pages and 32
* package READMEs` until objectui#5174's batch 7, by which point BOTH halves had
* drifted: the README count has been 31 since objectui#5259, and the `.mdx` count
* moves with every batch. Nothing fails on a stale number written here, which is
* why it is a pointer to the list now rather than a copy of its length.
* ⚠️ The ledger is EMPTY, and that is objectui#5174's finished state rather than a
* gap: every document the collector reaches is in the covered tier, so the default
* is now the only tier. There were 19 `.md` entries under `content/docs` when that
* card made them visible — the collector reads `.md`, and an entry with a measured
* reason is what a page that cannot pass yet is owed — and the card then walked
* every one of them, then the `.mdx` pages, then the package READMEs, and last the
* root `README.md`, back OFF this list rather than re-wording their reasons. Each
* page left by compiling, never by softening this gate.
*
* ⛔ An empty object is NOT an invitation to park the next page that fails. A new
* entry is new debt and owes the same thing every entry above owed: a reason that
* says WHAT would have to change, measured on the page rather than estimated. The
* sentence this replaces carried the literal `12 .mdx pages and 32 package
* READMEs` until objectui#5174's batch 7, by which point BOTH halves had drifted;
* nothing fails on a stale number written here, which is why no count is written
* here at all.
*
* Batch 1 took ten: `api/schema-reference`, `plugins/index`, and the `guide/` pages
* `architecture-overview`, `deployment`, `expressions`, `notifications`,
Expand Down Expand Up @@ -744,38 +748,7 @@ const TS_FENCE_LANGUAGES = new Set(['ts', 'tsx', 'typescript']);
*
* @type {Record<string, string>}
*/
const UNGATED_DOCS = {
// objectui#7115 put the root README into the scan surface; this entry is what
// that bought on THIS gate's question. The file is now VISIBLE to the ledger
// instead of invisible to the walk — the objectui#5174 distinction quoted in
// the header — and the debt below is measured, not estimated. ⚠️ Read as debt,
// never as a pass: these 6 diagnostics are real.
//
// It read 9, and named the three TS2305s as the ones that mattered, until
// objectui#7417 paid exactly those down — three names the page taught that no
// built `dist/index.d.ts` exports. What replaced each was already in the tree,
// so none of the three widened a public surface: `ObjectRenderer` (no export of
// @object-ui/app-shell bears that name; the page now composes `ObjectView` from
// @object-ui/plugin-view, the spelling examples/byo-backend-console/src/App.tsx
// already runs), `registerDefaultRenderers` (@object-ui/components registers its
// renderers as an import side effect — `sideEffects: true`, and its barrel's
// `import './renderers'` — and exports no such function, so the page now imports
// the package for the side effect), and `createObjectStackAdapter`, which ships
// from @object-ui/data-objectstack, not @object-ui/core, exactly as
// packages/plugin-dashboard/README.md already writes it.
//
// ⚠️ The remaining 6 are fragment shape, and no gate protects this page's
// import names from a fourth phantom: check-readme-exports.mjs states its
// surface as `packages/NAME/README.md`, and the root README imports from
// several packages rather than owning one, so that gate's rule would have to be
// restated before its surface could move (objectui#7417 triage).
'README.md':
'4 undefined-name diagnostic(s) — blocks use ambient names the page never defines (`myAPI`, ' +
'`MySidebar`) or continue an earlier block (`SchemaRenderer`, `schema`); 2 elided-body ' +
'diagnostic(s) (TS2420, TS2355) — a `DataSource` implementation written as `// ... other ' +
'methods`. This entry read 9 until objectui#7417 paid down the three TS2305s it carried; ' +
'what is left is fragment shape, and no gate reads this page\'s import names.',
};
const UNGATED_DOCS = {};

// ── Fence scanning ───────────────────────────────────────────────────────────

Expand Down
Loading