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
1 change: 1 addition & 0 deletions packages/metadata-protocol/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
Expand Down
7 changes: 6 additions & 1 deletion packages/metadata-protocol/src/mutation-listeners.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,12 @@ function makeProtocol() {
return new ObjectStackProtocolImplementation({} as any);
}

const evt = (over: Partial<MetadataMutationEvent> = {}): MetadataMutationEvent => ({
// `body` mirrors `runMutationProjector`'s own declared parameter
// (`MetadataMutationEvent & { body?: unknown }`) — the projector cases below
// pass one, and the bare `Partial<MetadataMutationEvent>` rejected it.
const evt = (
over: Partial<MetadataMutationEvent> & { body?: unknown } = {},
): MetadataMutationEvent & { body?: unknown } => ({
type: 'hook',
name: 'rebind_probe_hook',
state: 'active',
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@ function makeTransactionalEngine(opts: { driverCanTransact?: boolean } = {}) {
const rollbacks: unknown[] = [];
const handle = { id: 'trx-1' };

const insert = vi.fn(async (_object: string, data: any) => {
// Third parameter declared because the write path PASSES it and the
// assertions below read `call[2]`: a 2-arity mock made that a tuple
// with no element at index 2.
const insert = vi.fn(async (_object: string, data: any, _options?: any) => {
if (data?.title === POISON) throw new Error('insert exploded');
return { id: `rec-${insert.mock.calls.length}`, ...data };
});
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,7 +44,12 @@ function matches(r: Row, where: Record<string, unknown>): boolean {
return true;
}

function makeStubEngine(seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>) {
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: `string & unknown` is `string`, so a plain
// intersection refuses every body written as an object literal.
function makeStubEngine(
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const rows: Row[] = seedRows.map((r) => ({
id: `r_${++nextId}`,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,7 +57,12 @@ function matches(r: Record<string, any>, where: Record<string, unknown>): boolea
* actually observable.
*/
function makeStubEngine(
seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>,
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: on the row `metadata` is the STORED string, and
// `string & unknown` is `string`, so a plain intersection refuses every
// body written as an object literal — which is the seeding convenience
// this harness exists for, and what it already does at runtime below.
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const tables = new Map<string, Record<string, any>[]>();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-replay.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-retry.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core';

Expand DownExpand Up@@ -193,7 +193,7 @@ describe('seed loader — state_machine initialStates exemption (#3433)', () =>
// fallback), its options must carry the exemption flag — that is what the
// engine reads to skip the state_machine rule.
const writeCalls = [
...(engine.insertMany as any).mock.calls,
...((engine as any).insertMany).mock.calls,
...(engine.insert as any).mock.calls,
].filter(([obj]) => obj === 'showcase_project');
expect(writeCalls.length).toBeGreaterThan(0);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@

import { describe, it, expect, vi } from 'vitest';
import { SeedLoadResultSchema, SeedLoaderResultSchema } from '@objectstack/spec/data';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -334,7 +334,7 @@ describe('#4867 — history counters are never invented from a failed read', ()
expect(infoSpy).toHaveBeenCalledTimes(1);
expect((infoSpy.mock.calls[0] as [string])[0]).toMatch(/readable again/i);
// Numbering resumes after the surviving max — never from 1 again.
expect(engine.committed().at(-1)).toEqual({
expect(engine.committed().slice(-1)[0]).toEqual({
name: 'case_grid',
version: 3,
event_seq: 4,
Expand Down
26 changes: 11 additions & 15 deletions scripts/check-type-check-coverage.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -677,15 +677,6 @@ const DEBT = {
+ 'metadata.test.ts (34) and register-notifies-watchers.test.ts (16) do still hold 50 of the 89, '
+ 'but that is over HALF -- the "two thirds" claimed here was true at neither 92 nor 89.',
},
'@objectstack/metadata-protocol': {
errors: 63,
note: 'code-tier 40 (TS2322 x34, TS2532/TS2493 x2 each, TS2353, TS2339); config-tier 10 (TS2835 x9, '
+ 'TS2550); noise 13 (TS7006). Re-measured 63 at 5ab08428 -- the 2.25x drift that opened #5278, and '
+ 'the entry whose note was most misleading: it read "code-tier 9, the rest config-tier and noise", '
+ 'while code-tier alone is now 40. 27 of the TS2322 are in protocol.stored-migration.test.ts and 10 '
+ 'in seed-loader-multi-value-reference.test.ts, so this is concentrated debt in two files rather '
+ 'than a package-wide drizzle -- read it as two repairs, not as forty.',
},
'@objectstack/observability': {
errors: 11,
note: 'all code-tier (TS2554 wrong arity x10, TS2552).',
Expand DownExpand Up@@ -1898,9 +1889,12 @@ function workspacePackages() {
// "the workspace root itself: code-tier 4 ..." qualifies);
// * a tier counted twice, or a further `code-tier 9`-shaped count ANYWHERE
// later in the note, means the note is quoting its own history and the
// entry is skipped. metadata-protocol quotes the misleading note #5278
// found ("code-tier 9, the rest config-tier and noise") and is skipped for
// exactly that reason -- correct entry, no verdict;
// entry is skipped. metadata-protocol's entry quoted the misleading note
// #5278 found ("code-tier 9, the rest config-tier and noise") and was
// skipped for exactly that reason -- correct entry, no verdict. That entry
// has since GRADUATED (the package declares `typecheck` and its 63 errors
// are repaired), so the rule's live example is the self-test case below
// rather than a ledger row you can still read here;
// * per-code tallies (`TS2835 x72, TS7006 x49, ...`) are NOT summed. They are
// partial by construction, and the worked example this rule was written
// against says why: `@objectstack/rest`'s tally summed to 147 while saying
Expand DownExpand Up@@ -4206,9 +4200,11 @@ function selfTest() {
},
{
// The false-positive guard, and the reason the rule abstains rather than
// reasons: metadata-protocol's real note quotes the misleading one #5278
// found. Reading either count as the entry's own would red a correct
// entry, which is worse than the silence this check replaces.
// reasons: metadata-protocol's real note quoted the misleading one #5278
// found (that entry has since graduated, which is why this synthetic case
// now carries the shape). Reading either count as the entry's own would
// red a correct entry, which is worse than the silence this check
// replaces.
label: 'a note quoting its own history is SKIPPED, not guessed at',
packages: [],
root: { name: 'root', scripts: { typecheck: 'turbo run typecheck' } },
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
fix(metadata-protocol): add the missing `typecheck` script and repair all 63 test-layer type errors, graduating the package out of the DEBT ledger by zhuangjianguo · Pull Request #14018 · objectstack-ai/objectstack · GitHub
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
1 change: 1 addition & 0 deletions packages/metadata-protocol/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
Expand Down
7 changes: 6 additions & 1 deletion packages/metadata-protocol/src/mutation-listeners.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,12 @@ function makeProtocol() {
return new ObjectStackProtocolImplementation({} as any);
}

const evt = (over: Partial<MetadataMutationEvent> = {}): MetadataMutationEvent => ({
// `body` mirrors `runMutationProjector`'s own declared parameter
// (`MetadataMutationEvent & { body?: unknown }`) — the projector cases below
// pass one, and the bare `Partial<MetadataMutationEvent>` rejected it.
const evt = (
over: Partial<MetadataMutationEvent> & { body?: unknown } = {},
): MetadataMutationEvent & { body?: unknown } => ({
type: 'hook',
name: 'rebind_probe_hook',
state: 'active',
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@ function makeTransactionalEngine(opts: { driverCanTransact?: boolean } = {}) {
const rollbacks: unknown[] = [];
const handle = { id: 'trx-1' };

const insert = vi.fn(async (_object: string, data: any) => {
// Third parameter declared because the write path PASSES it and the
// assertions below read `call[2]`: a 2-arity mock made that a tuple
// with no element at index 2.
const insert = vi.fn(async (_object: string, data: any, _options?: any) => {
if (data?.title === POISON) throw new Error('insert exploded');
return { id: `rec-${insert.mock.calls.length}`, ...data };
});
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,7 +44,12 @@ function matches(r: Row, where: Record<string, unknown>): boolean {
return true;
}

function makeStubEngine(seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>) {
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: `string & unknown` is `string`, so a plain
// intersection refuses every body written as an object literal.
function makeStubEngine(
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const rows: Row[] = seedRows.map((r) => ({
id: `r_${++nextId}`,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,7 +57,12 @@ function matches(r: Record<string, any>, where: Record<string, unknown>): boolea
* actually observable.
*/
function makeStubEngine(
seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>,
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: on the row `metadata` is the STORED string, and
// `string & unknown` is `string`, so a plain intersection refuses every
// body written as an object literal — which is the seeding convenience
// this harness exists for, and what it already does at runtime below.
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const tables = new Map<string, Record<string, any>[]>();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-replay.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-retry.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core';

Expand DownExpand Up@@ -193,7 +193,7 @@ describe('seed loader — state_machine initialStates exemption (#3433)', () =>
// fallback), its options must carry the exemption flag — that is what the
// engine reads to skip the state_machine rule.
const writeCalls = [
...(engine.insertMany as any).mock.calls,
...((engine as any).insertMany).mock.calls,
...(engine.insert as any).mock.calls,
].filter(([obj]) => obj === 'showcase_project');
expect(writeCalls.length).toBeGreaterThan(0);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@

import { describe, it, expect, vi } from 'vitest';
import { SeedLoadResultSchema, SeedLoaderResultSchema } from '@objectstack/spec/data';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -334,7 +334,7 @@ describe('#4867 — history counters are never invented from a failed read', ()
expect(infoSpy).toHaveBeenCalledTimes(1);
expect((infoSpy.mock.calls[0] as [string])[0]).toMatch(/readable again/i);
// Numbering resumes after the surviving max — never from 1 again.
expect(engine.committed().at(-1)).toEqual({
expect(engine.committed().slice(-1)[0]).toEqual({
name: 'case_grid',
version: 3,
event_seq: 4,
Expand Down
26 changes: 11 additions & 15 deletions scripts/check-type-check-coverage.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -677,15 +677,6 @@ const DEBT = {
+ 'metadata.test.ts (34) and register-notifies-watchers.test.ts (16) do still hold 50 of the 89, '
+ 'but that is over HALF -- the "two thirds" claimed here was true at neither 92 nor 89.',
},
'@objectstack/metadata-protocol': {
errors: 63,
note: 'code-tier 40 (TS2322 x34, TS2532/TS2493 x2 each, TS2353, TS2339); config-tier 10 (TS2835 x9, '
+ 'TS2550); noise 13 (TS7006). Re-measured 63 at 5ab08428 -- the 2.25x drift that opened #5278, and '
+ 'the entry whose note was most misleading: it read "code-tier 9, the rest config-tier and noise", '
+ 'while code-tier alone is now 40. 27 of the TS2322 are in protocol.stored-migration.test.ts and 10 '
+ 'in seed-loader-multi-value-reference.test.ts, so this is concentrated debt in two files rather '
+ 'than a package-wide drizzle -- read it as two repairs, not as forty.',
},
'@objectstack/observability': {
errors: 11,
note: 'all code-tier (TS2554 wrong arity x10, TS2552).',
Expand DownExpand Up@@ -1898,9 +1889,12 @@ function workspacePackages() {
// "the workspace root itself: code-tier 4 ..." qualifies);
// * a tier counted twice, or a further `code-tier 9`-shaped count ANYWHERE
// later in the note, means the note is quoting its own history and the
// entry is skipped. metadata-protocol quotes the misleading note #5278
// found ("code-tier 9, the rest config-tier and noise") and is skipped for
// exactly that reason -- correct entry, no verdict;
// entry is skipped. metadata-protocol's entry quoted the misleading note
// #5278 found ("code-tier 9, the rest config-tier and noise") and was
// skipped for exactly that reason -- correct entry, no verdict. That entry
// has since GRADUATED (the package declares `typecheck` and its 63 errors
// are repaired), so the rule's live example is the self-test case below
// rather than a ledger row you can still read here;
// * per-code tallies (`TS2835 x72, TS7006 x49, ...`) are NOT summed. They are
// partial by construction, and the worked example this rule was written
// against says why: `@objectstack/rest`'s tally summed to 147 while saying
Expand DownExpand Up@@ -4206,9 +4200,11 @@ function selfTest() {
},
{
// The false-positive guard, and the reason the rule abstains rather than
// reasons: metadata-protocol's real note quotes the misleading one #5278
// found. Reading either count as the entry's own would red a correct
// entry, which is worse than the silence this check replaces.
// reasons: metadata-protocol's real note quoted the misleading one #5278
// found (that entry has since graduated, which is why this synthetic case
// now carries the shape). Reading either count as the entry's own would
// red a correct entry, which is worse than the silence this check
// replaces.
label: 'a note quoting its own history is SKIPPED, not guessed at',
packages: [],
root: { name: 'root', scripts: { typecheck: 'turbo run typecheck' } },
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(metadata-protocol): add the missing `typecheck` script and repair all 63 test-layer type errors, graduating the package out of the DEBT ledger by zhuangjianguo · Pull Request #14018 · objectstack-ai/objectstack · GitHub
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
1 change: 1 addition & 0 deletions packages/metadata-protocol/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
Expand Down
7 changes: 6 additions & 1 deletion packages/metadata-protocol/src/mutation-listeners.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,12 @@ function makeProtocol() {
return new ObjectStackProtocolImplementation({} as any);
}

const evt = (over: Partial<MetadataMutationEvent> = {}): MetadataMutationEvent => ({
// `body` mirrors `runMutationProjector`'s own declared parameter
// (`MetadataMutationEvent & { body?: unknown }`) — the projector cases below
// pass one, and the bare `Partial<MetadataMutationEvent>` rejected it.
const evt = (
over: Partial<MetadataMutationEvent> & { body?: unknown } = {},
): MetadataMutationEvent & { body?: unknown } => ({
type: 'hook',
name: 'rebind_probe_hook',
state: 'active',
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@ function makeTransactionalEngine(opts: { driverCanTransact?: boolean } = {}) {
const rollbacks: unknown[] = [];
const handle = { id: 'trx-1' };

const insert = vi.fn(async (_object: string, data: any) => {
// Third parameter declared because the write path PASSES it and the
// assertions below read `call[2]`: a 2-arity mock made that a tuple
// with no element at index 2.
const insert = vi.fn(async (_object: string, data: any, _options?: any) => {
if (data?.title === POISON) throw new Error('insert exploded');
return { id: `rec-${insert.mock.calls.length}`, ...data };
});
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,7 +44,12 @@ function matches(r: Row, where: Record<string, unknown>): boolean {
return true;
}

function makeStubEngine(seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>) {
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: `string & unknown` is `string`, so a plain
// intersection refuses every body written as an object literal.
function makeStubEngine(
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const rows: Row[] = seedRows.map((r) => ({
id: `r_${++nextId}`,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,7 +57,12 @@ function matches(r: Record<string, any>, where: Record<string, unknown>): boolea
* actually observable.
*/
function makeStubEngine(
seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>,
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: on the row `metadata` is the STORED string, and
// `string & unknown` is `string`, so a plain intersection refuses every
// body written as an object literal — which is the seeding convenience
// this harness exists for, and what it already does at runtime below.
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const tables = new Map<string, Record<string, any>[]>();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-replay.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-retry.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core';

Expand DownExpand Up@@ -193,7 +193,7 @@ describe('seed loader — state_machine initialStates exemption (#3433)', () =>
// fallback), its options must carry the exemption flag — that is what the
// engine reads to skip the state_machine rule.
const writeCalls = [
...(engine.insertMany as any).mock.calls,
...((engine as any).insertMany).mock.calls,
...(engine.insert as any).mock.calls,
].filter(([obj]) => obj === 'showcase_project');
expect(writeCalls.length).toBeGreaterThan(0);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@

import { describe, it, expect, vi } from 'vitest';
import { SeedLoadResultSchema, SeedLoaderResultSchema } from '@objectstack/spec/data';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -334,7 +334,7 @@ describe('#4867 — history counters are never invented from a failed read', ()
expect(infoSpy).toHaveBeenCalledTimes(1);
expect((infoSpy.mock.calls[0] as [string])[0]).toMatch(/readable again/i);
// Numbering resumes after the surviving max — never from 1 again.
expect(engine.committed().at(-1)).toEqual({
expect(engine.committed().slice(-1)[0]).toEqual({
name: 'case_grid',
version: 3,
event_seq: 4,
Expand Down
26 changes: 11 additions & 15 deletions scripts/check-type-check-coverage.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -677,15 +677,6 @@ const DEBT = {
+ 'metadata.test.ts (34) and register-notifies-watchers.test.ts (16) do still hold 50 of the 89, '
+ 'but that is over HALF -- the "two thirds" claimed here was true at neither 92 nor 89.',
},
'@objectstack/metadata-protocol': {
errors: 63,
note: 'code-tier 40 (TS2322 x34, TS2532/TS2493 x2 each, TS2353, TS2339); config-tier 10 (TS2835 x9, '
+ 'TS2550); noise 13 (TS7006). Re-measured 63 at 5ab08428 -- the 2.25x drift that opened #5278, and '
+ 'the entry whose note was most misleading: it read "code-tier 9, the rest config-tier and noise", '
+ 'while code-tier alone is now 40. 27 of the TS2322 are in protocol.stored-migration.test.ts and 10 '
+ 'in seed-loader-multi-value-reference.test.ts, so this is concentrated debt in two files rather '
+ 'than a package-wide drizzle -- read it as two repairs, not as forty.',
},
'@objectstack/observability': {
errors: 11,
note: 'all code-tier (TS2554 wrong arity x10, TS2552).',
Expand DownExpand Up@@ -1898,9 +1889,12 @@ function workspacePackages() {
// "the workspace root itself: code-tier 4 ..." qualifies);
// * a tier counted twice, or a further `code-tier 9`-shaped count ANYWHERE
// later in the note, means the note is quoting its own history and the
// entry is skipped. metadata-protocol quotes the misleading note #5278
// found ("code-tier 9, the rest config-tier and noise") and is skipped for
// exactly that reason -- correct entry, no verdict;
// entry is skipped. metadata-protocol's entry quoted the misleading note
// #5278 found ("code-tier 9, the rest config-tier and noise") and was
// skipped for exactly that reason -- correct entry, no verdict. That entry
// has since GRADUATED (the package declares `typecheck` and its 63 errors
// are repaired), so the rule's live example is the self-test case below
// rather than a ledger row you can still read here;
// * per-code tallies (`TS2835 x72, TS7006 x49, ...`) are NOT summed. They are
// partial by construction, and the worked example this rule was written
// against says why: `@objectstack/rest`'s tally summed to 147 while saying
Expand DownExpand Up@@ -4206,9 +4200,11 @@ function selfTest() {
},
{
// The false-positive guard, and the reason the rule abstains rather than
// reasons: metadata-protocol's real note quotes the misleading one #5278
// found. Reading either count as the entry's own would red a correct
// entry, which is worse than the silence this check replaces.
// reasons: metadata-protocol's real note quoted the misleading one #5278
// found (that entry has since graduated, which is why this synthetic case
// now carries the shape). Reading either count as the entry's own would
// red a correct entry, which is worse than the silence this check
// replaces.
label: 'a note quoting its own history is SKIPPED, not guessed at',
packages: [],
root: { name: 'root', scripts: { typecheck: 'turbo run typecheck' } },
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(metadata-protocol): add the missing `typecheck` script and repair all 63 test-layer type errors, graduating the package out of the DEBT ledger by zhuangjianguo · Pull Request #14018 · objectstack-ai/objectstack · GitHub
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
1 change: 1 addition & 0 deletions packages/metadata-protocol/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
Expand Down
7 changes: 6 additions & 1 deletion packages/metadata-protocol/src/mutation-listeners.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,12 @@ function makeProtocol() {
return new ObjectStackProtocolImplementation({} as any);
}

const evt = (over: Partial<MetadataMutationEvent> = {}): MetadataMutationEvent => ({
// `body` mirrors `runMutationProjector`'s own declared parameter
// (`MetadataMutationEvent & { body?: unknown }`) — the projector cases below
// pass one, and the bare `Partial<MetadataMutationEvent>` rejected it.
const evt = (
over: Partial<MetadataMutationEvent> & { body?: unknown } = {},
): MetadataMutationEvent & { body?: unknown } => ({
type: 'hook',
name: 'rebind_probe_hook',
state: 'active',
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@ function makeTransactionalEngine(opts: { driverCanTransact?: boolean } = {}) {
const rollbacks: unknown[] = [];
const handle = { id: 'trx-1' };

const insert = vi.fn(async (_object: string, data: any) => {
// Third parameter declared because the write path PASSES it and the
// assertions below read `call[2]`: a 2-arity mock made that a tuple
// with no element at index 2.
const insert = vi.fn(async (_object: string, data: any, _options?: any) => {
if (data?.title === POISON) throw new Error('insert exploded');
return { id: `rec-${insert.mock.calls.length}`, ...data };
});
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,7 +44,12 @@ function matches(r: Row, where: Record<string, unknown>): boolean {
return true;
}

function makeStubEngine(seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>) {
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: `string & unknown` is `string`, so a plain
// intersection refuses every body written as an object literal.
function makeStubEngine(
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const rows: Row[] = seedRows.map((r) => ({
id: `r_${++nextId}`,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,7 +57,12 @@ function matches(r: Record<string, any>, where: Record<string, unknown>): boolea
* actually observable.
*/
function makeStubEngine(
seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>,
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: on the row `metadata` is the STORED string, and
// `string & unknown` is `string`, so a plain intersection refuses every
// body written as an object literal — which is the seeding convenience
// this harness exists for, and what it already does at runtime below.
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const tables = new Map<string, Record<string, any>[]>();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-replay.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-retry.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core';

Expand DownExpand Up@@ -193,7 +193,7 @@ describe('seed loader — state_machine initialStates exemption (#3433)', () =>
// fallback), its options must carry the exemption flag — that is what the
// engine reads to skip the state_machine rule.
const writeCalls = [
...(engine.insertMany as any).mock.calls,
...((engine as any).insertMany).mock.calls,
...(engine.insert as any).mock.calls,
].filter(([obj]) => obj === 'showcase_project');
expect(writeCalls.length).toBeGreaterThan(0);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@

import { describe, it, expect, vi } from 'vitest';
import { SeedLoadResultSchema, SeedLoaderResultSchema } from '@objectstack/spec/data';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -334,7 +334,7 @@ describe('#4867 — history counters are never invented from a failed read', ()
expect(infoSpy).toHaveBeenCalledTimes(1);
expect((infoSpy.mock.calls[0] as [string])[0]).toMatch(/readable again/i);
// Numbering resumes after the surviving max — never from 1 again.
expect(engine.committed().at(-1)).toEqual({
expect(engine.committed().slice(-1)[0]).toEqual({
name: 'case_grid',
version: 3,
event_seq: 4,
Expand Down
26 changes: 11 additions & 15 deletions scripts/check-type-check-coverage.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -677,15 +677,6 @@ const DEBT = {
+ 'metadata.test.ts (34) and register-notifies-watchers.test.ts (16) do still hold 50 of the 89, '
+ 'but that is over HALF -- the "two thirds" claimed here was true at neither 92 nor 89.',
},
'@objectstack/metadata-protocol': {
errors: 63,
note: 'code-tier 40 (TS2322 x34, TS2532/TS2493 x2 each, TS2353, TS2339); config-tier 10 (TS2835 x9, '
+ 'TS2550); noise 13 (TS7006). Re-measured 63 at 5ab08428 -- the 2.25x drift that opened #5278, and '
+ 'the entry whose note was most misleading: it read "code-tier 9, the rest config-tier and noise", '
+ 'while code-tier alone is now 40. 27 of the TS2322 are in protocol.stored-migration.test.ts and 10 '
+ 'in seed-loader-multi-value-reference.test.ts, so this is concentrated debt in two files rather '
+ 'than a package-wide drizzle -- read it as two repairs, not as forty.',
},
'@objectstack/observability': {
errors: 11,
note: 'all code-tier (TS2554 wrong arity x10, TS2552).',
Expand DownExpand Up@@ -1898,9 +1889,12 @@ function workspacePackages() {
// "the workspace root itself: code-tier 4 ..." qualifies);
// * a tier counted twice, or a further `code-tier 9`-shaped count ANYWHERE
// later in the note, means the note is quoting its own history and the
// entry is skipped. metadata-protocol quotes the misleading note #5278
// found ("code-tier 9, the rest config-tier and noise") and is skipped for
// exactly that reason -- correct entry, no verdict;
// entry is skipped. metadata-protocol's entry quoted the misleading note
// #5278 found ("code-tier 9, the rest config-tier and noise") and was
// skipped for exactly that reason -- correct entry, no verdict. That entry
// has since GRADUATED (the package declares `typecheck` and its 63 errors
// are repaired), so the rule's live example is the self-test case below
// rather than a ledger row you can still read here;
// * per-code tallies (`TS2835 x72, TS7006 x49, ...`) are NOT summed. They are
// partial by construction, and the worked example this rule was written
// against says why: `@objectstack/rest`'s tally summed to 147 while saying
Expand DownExpand Up@@ -4206,9 +4200,11 @@ function selfTest() {
},
{
// The false-positive guard, and the reason the rule abstains rather than
// reasons: metadata-protocol's real note quotes the misleading one #5278
// found. Reading either count as the entry's own would red a correct
// entry, which is worse than the silence this check replaces.
// reasons: metadata-protocol's real note quoted the misleading one #5278
// found (that entry has since graduated, which is why this synthetic case
// now carries the shape). Reading either count as the entry's own would
// red a correct entry, which is worse than the silence this check
// replaces.
label: 'a note quoting its own history is SKIPPED, not guessed at',
packages: [],
root: { name: 'root', scripts: { typecheck: 'turbo run typecheck' } },
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' fix(metadata-protocol): add the missing `typecheck` script and repair all 63 test-layer type errors, graduating the package out of the DEBT ledger by zhuangjianguo · Pull Request #14018 · objectstack-ai/objectstack · GitHub
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
1 change: 1 addition & 0 deletions packages/metadata-protocol/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
Expand Down
7 changes: 6 additions & 1 deletion packages/metadata-protocol/src/mutation-listeners.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,12 @@ function makeProtocol() {
return new ObjectStackProtocolImplementation({} as any);
}

const evt = (over: Partial<MetadataMutationEvent> = {}): MetadataMutationEvent => ({
// `body` mirrors `runMutationProjector`'s own declared parameter
// (`MetadataMutationEvent & { body?: unknown }`) — the projector cases below
// pass one, and the bare `Partial<MetadataMutationEvent>` rejected it.
const evt = (
over: Partial<MetadataMutationEvent> & { body?: unknown } = {},
): MetadataMutationEvent & { body?: unknown } => ({
type: 'hook',
name: 'rebind_probe_hook',
state: 'active',
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@ function makeTransactionalEngine(opts: { driverCanTransact?: boolean } = {}) {
const rollbacks: unknown[] = [];
const handle = { id: 'trx-1' };

const insert = vi.fn(async (_object: string, data: any) => {
// Third parameter declared because the write path PASSES it and the
// assertions below read `call[2]`: a 2-arity mock made that a tuple
// with no element at index 2.
const insert = vi.fn(async (_object: string, data: any, _options?: any) => {
if (data?.title === POISON) throw new Error('insert exploded');
return { id: `rec-${insert.mock.calls.length}`, ...data };
});
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,7 +44,12 @@ function matches(r: Row, where: Record<string, unknown>): boolean {
return true;
}

function makeStubEngine(seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>) {
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: `string & unknown` is `string`, so a plain
// intersection refuses every body written as an object literal.
function makeStubEngine(
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const rows: Row[] = seedRows.map((r) => ({
id: `r_${++nextId}`,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,7 +57,12 @@ function matches(r: Record<string, any>, where: Record<string, unknown>): boolea
* actually observable.
*/
function makeStubEngine(
seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>,
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: on the row `metadata` is the STORED string, and
// `string & unknown` is `string`, so a plain intersection refuses every
// body written as an object literal — which is the seeding convenience
// this harness exists for, and what it already does at runtime below.
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const tables = new Map<string, Record<string, any>[]>();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-replay.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-retry.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core';

Expand DownExpand Up@@ -193,7 +193,7 @@ describe('seed loader — state_machine initialStates exemption (#3433)', () =>
// fallback), its options must carry the exemption flag — that is what the
// engine reads to skip the state_machine rule.
const writeCalls = [
...(engine.insertMany as any).mock.calls,
...((engine as any).insertMany).mock.calls,
...(engine.insert as any).mock.calls,
].filter(([obj]) => obj === 'showcase_project');
expect(writeCalls.length).toBeGreaterThan(0);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@

import { describe, it, expect, vi } from 'vitest';
import { SeedLoadResultSchema, SeedLoaderResultSchema } from '@objectstack/spec/data';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -334,7 +334,7 @@ describe('#4867 — history counters are never invented from a failed read', ()
expect(infoSpy).toHaveBeenCalledTimes(1);
expect((infoSpy.mock.calls[0] as [string])[0]).toMatch(/readable again/i);
// Numbering resumes after the surviving max — never from 1 again.
expect(engine.committed().at(-1)).toEqual({
expect(engine.committed().slice(-1)[0]).toEqual({
name: 'case_grid',
version: 3,
event_seq: 4,
Expand Down
26 changes: 11 additions & 15 deletions scripts/check-type-check-coverage.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -677,15 +677,6 @@ const DEBT = {
+ 'metadata.test.ts (34) and register-notifies-watchers.test.ts (16) do still hold 50 of the 89, '
+ 'but that is over HALF -- the "two thirds" claimed here was true at neither 92 nor 89.',
},
'@objectstack/metadata-protocol': {
errors: 63,
note: 'code-tier 40 (TS2322 x34, TS2532/TS2493 x2 each, TS2353, TS2339); config-tier 10 (TS2835 x9, '
+ 'TS2550); noise 13 (TS7006). Re-measured 63 at 5ab08428 -- the 2.25x drift that opened #5278, and '
+ 'the entry whose note was most misleading: it read "code-tier 9, the rest config-tier and noise", '
+ 'while code-tier alone is now 40. 27 of the TS2322 are in protocol.stored-migration.test.ts and 10 '
+ 'in seed-loader-multi-value-reference.test.ts, so this is concentrated debt in two files rather '
+ 'than a package-wide drizzle -- read it as two repairs, not as forty.',
},
'@objectstack/observability': {
errors: 11,
note: 'all code-tier (TS2554 wrong arity x10, TS2552).',
Expand DownExpand Up@@ -1898,9 +1889,12 @@ function workspacePackages() {
// "the workspace root itself: code-tier 4 ..." qualifies);
// * a tier counted twice, or a further `code-tier 9`-shaped count ANYWHERE
// later in the note, means the note is quoting its own history and the
// entry is skipped. metadata-protocol quotes the misleading note #5278
// found ("code-tier 9, the rest config-tier and noise") and is skipped for
// exactly that reason -- correct entry, no verdict;
// entry is skipped. metadata-protocol's entry quoted the misleading note
// #5278 found ("code-tier 9, the rest config-tier and noise") and was
// skipped for exactly that reason -- correct entry, no verdict. That entry
// has since GRADUATED (the package declares `typecheck` and its 63 errors
// are repaired), so the rule's live example is the self-test case below
// rather than a ledger row you can still read here;
// * per-code tallies (`TS2835 x72, TS7006 x49, ...`) are NOT summed. They are
// partial by construction, and the worked example this rule was written
// against says why: `@objectstack/rest`'s tally summed to 147 while saying
Expand DownExpand Up@@ -4206,9 +4200,11 @@ function selfTest() {
},
{
// The false-positive guard, and the reason the rule abstains rather than
// reasons: metadata-protocol's real note quotes the misleading one #5278
// found. Reading either count as the entry's own would red a correct
// entry, which is worse than the silence this check replaces.
// reasons: metadata-protocol's real note quoted the misleading one #5278
// found (that entry has since graduated, which is why this synthetic case
// now carries the shape). Reading either count as the entry's own would
// red a correct entry, which is worse than the silence this check
// replaces.
label: 'a note quoting its own history is SKIPPED, not guessed at',
packages: [],
root: { name: 'root', scripts: { typecheck: 'turbo run typecheck' } },
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(metadata-protocol): add the missing `typecheck` script and repair all 63 test-layer type errors, graduating the package out of the DEBT ledger by zhuangjianguo · Pull Request #14018 · objectstack-ai/objectstack · GitHub
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
1 change: 1 addition & 0 deletions packages/metadata-protocol/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
Expand Down
7 changes: 6 additions & 1 deletion packages/metadata-protocol/src/mutation-listeners.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,12 @@ function makeProtocol() {
return new ObjectStackProtocolImplementation({} as any);
}

const evt = (over: Partial<MetadataMutationEvent> = {}): MetadataMutationEvent => ({
// `body` mirrors `runMutationProjector`'s own declared parameter
// (`MetadataMutationEvent & { body?: unknown }`) — the projector cases below
// pass one, and the bare `Partial<MetadataMutationEvent>` rejected it.
const evt = (
over: Partial<MetadataMutationEvent> & { body?: unknown } = {},
): MetadataMutationEvent & { body?: unknown } => ({
type: 'hook',
name: 'rebind_probe_hook',
state: 'active',
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@ function makeTransactionalEngine(opts: { driverCanTransact?: boolean } = {}) {
const rollbacks: unknown[] = [];
const handle = { id: 'trx-1' };

const insert = vi.fn(async (_object: string, data: any) => {
// Third parameter declared because the write path PASSES it and the
// assertions below read `call[2]`: a 2-arity mock made that a tuple
// with no element at index 2.
const insert = vi.fn(async (_object: string, data: any, _options?: any) => {
if (data?.title === POISON) throw new Error('insert exploded');
return { id: `rec-${insert.mock.calls.length}`, ...data };
});
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,7 +44,12 @@ function matches(r: Row, where: Record<string, unknown>): boolean {
return true;
}

function makeStubEngine(seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>) {
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: `string & unknown` is `string`, so a plain
// intersection refuses every body written as an object literal.
function makeStubEngine(
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const rows: Row[] = seedRows.map((r) => ({
id: `r_${++nextId}`,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,7 +57,12 @@ function matches(r: Record<string, any>, where: Record<string, unknown>): boolea
* actually observable.
*/
function makeStubEngine(
seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>,
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: on the row `metadata` is the STORED string, and
// `string & unknown` is `string`, so a plain intersection refuses every
// body written as an object literal — which is the seeding convenience
// this harness exists for, and what it already does at runtime below.
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const tables = new Map<string, Record<string, any>[]>();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-replay.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-retry.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core';

Expand DownExpand Up@@ -193,7 +193,7 @@ describe('seed loader — state_machine initialStates exemption (#3433)', () =>
// fallback), its options must carry the exemption flag — that is what the
// engine reads to skip the state_machine rule.
const writeCalls = [
...(engine.insertMany as any).mock.calls,
...((engine as any).insertMany).mock.calls,
...(engine.insert as any).mock.calls,
].filter(([obj]) => obj === 'showcase_project');
expect(writeCalls.length).toBeGreaterThan(0);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@

import { describe, it, expect, vi } from 'vitest';
import { SeedLoadResultSchema, SeedLoaderResultSchema } from '@objectstack/spec/data';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -334,7 +334,7 @@ describe('#4867 — history counters are never invented from a failed read', ()
expect(infoSpy).toHaveBeenCalledTimes(1);
expect((infoSpy.mock.calls[0] as [string])[0]).toMatch(/readable again/i);
// Numbering resumes after the surviving max — never from 1 again.
expect(engine.committed().at(-1)).toEqual({
expect(engine.committed().slice(-1)[0]).toEqual({
name: 'case_grid',
version: 3,
event_seq: 4,
Expand Down
26 changes: 11 additions & 15 deletions scripts/check-type-check-coverage.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -677,15 +677,6 @@ const DEBT = {
+ 'metadata.test.ts (34) and register-notifies-watchers.test.ts (16) do still hold 50 of the 89, '
+ 'but that is over HALF -- the "two thirds" claimed here was true at neither 92 nor 89.',
},
'@objectstack/metadata-protocol': {
errors: 63,
note: 'code-tier 40 (TS2322 x34, TS2532/TS2493 x2 each, TS2353, TS2339); config-tier 10 (TS2835 x9, '
+ 'TS2550); noise 13 (TS7006). Re-measured 63 at 5ab08428 -- the 2.25x drift that opened #5278, and '
+ 'the entry whose note was most misleading: it read "code-tier 9, the rest config-tier and noise", '
+ 'while code-tier alone is now 40. 27 of the TS2322 are in protocol.stored-migration.test.ts and 10 '
+ 'in seed-loader-multi-value-reference.test.ts, so this is concentrated debt in two files rather '
+ 'than a package-wide drizzle -- read it as two repairs, not as forty.',
},
'@objectstack/observability': {
errors: 11,
note: 'all code-tier (TS2554 wrong arity x10, TS2552).',
Expand DownExpand Up@@ -1898,9 +1889,12 @@ function workspacePackages() {
// "the workspace root itself: code-tier 4 ..." qualifies);
// * a tier counted twice, or a further `code-tier 9`-shaped count ANYWHERE
// later in the note, means the note is quoting its own history and the
// entry is skipped. metadata-protocol quotes the misleading note #5278
// found ("code-tier 9, the rest config-tier and noise") and is skipped for
// exactly that reason -- correct entry, no verdict;
// entry is skipped. metadata-protocol's entry quoted the misleading note
// #5278 found ("code-tier 9, the rest config-tier and noise") and was
// skipped for exactly that reason -- correct entry, no verdict. That entry
// has since GRADUATED (the package declares `typecheck` and its 63 errors
// are repaired), so the rule's live example is the self-test case below
// rather than a ledger row you can still read here;
// * per-code tallies (`TS2835 x72, TS7006 x49, ...`) are NOT summed. They are
// partial by construction, and the worked example this rule was written
// against says why: `@objectstack/rest`'s tally summed to 147 while saying
Expand DownExpand Up@@ -4206,9 +4200,11 @@ function selfTest() {
},
{
// The false-positive guard, and the reason the rule abstains rather than
// reasons: metadata-protocol's real note quotes the misleading one #5278
// found. Reading either count as the entry's own would red a correct
// entry, which is worse than the silence this check replaces.
// reasons: metadata-protocol's real note quoted the misleading one #5278
// found (that entry has since graduated, which is why this synthetic case
// now carries the shape). Reading either count as the entry's own would
// red a correct entry, which is worse than the silence this check
// replaces.
label: 'a note quoting its own history is SKIPPED, not guessed at',
packages: [],
root: { name: 'root', scripts: { typecheck: 'turbo run typecheck' } },
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' fix(metadata-protocol): add the missing `typecheck` script and repair all 63 test-layer type errors, graduating the package out of the DEBT ledger by zhuangjianguo · Pull Request #14018 · objectstack-ai/objectstack · GitHub
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
1 change: 1 addition & 0 deletions packages/metadata-protocol/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
Expand Down
7 changes: 6 additions & 1 deletion packages/metadata-protocol/src/mutation-listeners.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,12 @@ function makeProtocol() {
return new ObjectStackProtocolImplementation({} as any);
}

const evt = (over: Partial<MetadataMutationEvent> = {}): MetadataMutationEvent => ({
// `body` mirrors `runMutationProjector`'s own declared parameter
// (`MetadataMutationEvent & { body?: unknown }`) — the projector cases below
// pass one, and the bare `Partial<MetadataMutationEvent>` rejected it.
const evt = (
over: Partial<MetadataMutationEvent> & { body?: unknown } = {},
): MetadataMutationEvent & { body?: unknown } => ({
type: 'hook',
name: 'rebind_probe_hook',
state: 'active',
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@ function makeTransactionalEngine(opts: { driverCanTransact?: boolean } = {}) {
const rollbacks: unknown[] = [];
const handle = { id: 'trx-1' };

const insert = vi.fn(async (_object: string, data: any) => {
// Third parameter declared because the write path PASSES it and the
// assertions below read `call[2]`: a 2-arity mock made that a tuple
// with no element at index 2.
const insert = vi.fn(async (_object: string, data: any, _options?: any) => {
if (data?.title === POISON) throw new Error('insert exploded');
return { id: `rec-${insert.mock.calls.length}`, ...data };
});
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,7 +44,12 @@ function matches(r: Row, where: Record<string, unknown>): boolean {
return true;
}

function makeStubEngine(seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>) {
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: `string & unknown` is `string`, so a plain
// intersection refuses every body written as an object literal.
function makeStubEngine(
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const rows: Row[] = seedRows.map((r) => ({
id: `r_${++nextId}`,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,7 +57,12 @@ function matches(r: Record<string, any>, where: Record<string, unknown>): boolea
* actually observable.
*/
function makeStubEngine(
seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>,
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: on the row `metadata` is the STORED string, and
// `string & unknown` is `string`, so a plain intersection refuses every
// body written as an object literal — which is the seeding convenience
// this harness exists for, and what it already does at runtime below.
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const tables = new Map<string, Record<string, any>[]>();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-replay.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-retry.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core';

Expand DownExpand Up@@ -193,7 +193,7 @@ describe('seed loader — state_machine initialStates exemption (#3433)', () =>
// fallback), its options must carry the exemption flag — that is what the
// engine reads to skip the state_machine rule.
const writeCalls = [
...(engine.insertMany as any).mock.calls,
...((engine as any).insertMany).mock.calls,
...(engine.insert as any).mock.calls,
].filter(([obj]) => obj === 'showcase_project');
expect(writeCalls.length).toBeGreaterThan(0);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@

import { describe, it, expect, vi } from 'vitest';
import { SeedLoadResultSchema, SeedLoaderResultSchema } from '@objectstack/spec/data';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -334,7 +334,7 @@ describe('#4867 — history counters are never invented from a failed read', ()
expect(infoSpy).toHaveBeenCalledTimes(1);
expect((infoSpy.mock.calls[0] as [string])[0]).toMatch(/readable again/i);
// Numbering resumes after the surviving max — never from 1 again.
expect(engine.committed().at(-1)).toEqual({
expect(engine.committed().slice(-1)[0]).toEqual({
name: 'case_grid',
version: 3,
event_seq: 4,
Expand Down
26 changes: 11 additions & 15 deletions scripts/check-type-check-coverage.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -677,15 +677,6 @@ const DEBT = {
+ 'metadata.test.ts (34) and register-notifies-watchers.test.ts (16) do still hold 50 of the 89, '
+ 'but that is over HALF -- the "two thirds" claimed here was true at neither 92 nor 89.',
},
'@objectstack/metadata-protocol': {
errors: 63,
note: 'code-tier 40 (TS2322 x34, TS2532/TS2493 x2 each, TS2353, TS2339); config-tier 10 (TS2835 x9, '
+ 'TS2550); noise 13 (TS7006). Re-measured 63 at 5ab08428 -- the 2.25x drift that opened #5278, and '
+ 'the entry whose note was most misleading: it read "code-tier 9, the rest config-tier and noise", '
+ 'while code-tier alone is now 40. 27 of the TS2322 are in protocol.stored-migration.test.ts and 10 '
+ 'in seed-loader-multi-value-reference.test.ts, so this is concentrated debt in two files rather '
+ 'than a package-wide drizzle -- read it as two repairs, not as forty.',
},
'@objectstack/observability': {
errors: 11,
note: 'all code-tier (TS2554 wrong arity x10, TS2552).',
Expand DownExpand Up@@ -1898,9 +1889,12 @@ function workspacePackages() {
// "the workspace root itself: code-tier 4 ..." qualifies);
// * a tier counted twice, or a further `code-tier 9`-shaped count ANYWHERE
// later in the note, means the note is quoting its own history and the
// entry is skipped. metadata-protocol quotes the misleading note #5278
// found ("code-tier 9, the rest config-tier and noise") and is skipped for
// exactly that reason -- correct entry, no verdict;
// entry is skipped. metadata-protocol's entry quoted the misleading note
// #5278 found ("code-tier 9, the rest config-tier and noise") and was
// skipped for exactly that reason -- correct entry, no verdict. That entry
// has since GRADUATED (the package declares `typecheck` and its 63 errors
// are repaired), so the rule's live example is the self-test case below
// rather than a ledger row you can still read here;
// * per-code tallies (`TS2835 x72, TS7006 x49, ...`) are NOT summed. They are
// partial by construction, and the worked example this rule was written
// against says why: `@objectstack/rest`'s tally summed to 147 while saying
Expand DownExpand Up@@ -4206,9 +4200,11 @@ function selfTest() {
},
{
// The false-positive guard, and the reason the rule abstains rather than
// reasons: metadata-protocol's real note quotes the misleading one #5278
// found. Reading either count as the entry's own would red a correct
// entry, which is worse than the silence this check replaces.
// reasons: metadata-protocol's real note quoted the misleading one #5278
// found (that entry has since graduated, which is why this synthetic case
// now carries the shape). Reading either count as the entry's own would
// red a correct entry, which is worse than the silence this check
// replaces.
label: 'a note quoting its own history is SKIPPED, not guessed at',
packages: [],
root: { name: 'root', scripts: { typecheck: 'turbo run typecheck' } },
Expand Down
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); fix(metadata-protocol): add the missing `typecheck` script and repair all 63 test-layer type errors, graduating the package out of the DEBT ledger by zhuangjianguo · Pull Request #14018 · objectstack-ai/objectstack · GitHub
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
1 change: 1 addition & 0 deletions packages/metadata-protocol/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,6 +27,7 @@
"build": "tsup && node ../../scripts/check-dts-emitted.mjs",
"dev": "tsc --watch",
"clean": "rm -rf dist",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:watch": "vitest"
},
Expand Down
7 changes: 6 additions & 1 deletion packages/metadata-protocol/src/mutation-listeners.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -20,7 +20,12 @@ function makeProtocol() {
return new ObjectStackProtocolImplementation({} as any);
}

const evt = (over: Partial<MetadataMutationEvent> = {}): MetadataMutationEvent => ({
// `body` mirrors `runMutationProjector`'s own declared parameter
// (`MetadataMutationEvent & { body?: unknown }`) — the projector cases below
// pass one, and the bare `Partial<MetadataMutationEvent>` rejected it.
const evt = (
over: Partial<MetadataMutationEvent> & { body?: unknown } = {},
): MetadataMutationEvent & { body?: unknown } => ({
type: 'hook',
name: 'rebind_probe_hook',
state: 'active',
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@ function makeTransactionalEngine(opts: { driverCanTransact?: boolean } = {}) {
const rollbacks: unknown[] = [];
const handle = { id: 'trx-1' };

const insert = vi.fn(async (_object: string, data: any) => {
// Third parameter declared because the write path PASSES it and the
// assertions below read `call[2]`: a 2-arity mock made that a tuple
// with no element at index 2.
const insert = vi.fn(async (_object: string, data: any, _options?: any) => {
if (data?.title === POISON) throw new Error('insert exploded');
return { id: `rec-${insert.mock.calls.length}`, ...data };
});
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,7 +44,12 @@ function matches(r: Row, where: Record<string, unknown>): boolean {
return true;
}

function makeStubEngine(seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>) {
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: `string & unknown` is `string`, so a plain
// intersection refuses every body written as an object literal.
function makeStubEngine(
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const rows: Row[] = seedRows.map((r) => ({
id: `r_${++nextId}`,
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,7 +57,12 @@ function matches(r: Record<string, any>, where: Record<string, unknown>): boolea
* actually observable.
*/
function makeStubEngine(
seedRows: Array<Partial<Row> & { type: string; name: string; metadata: unknown }>,
// `metadata` is `Omit`-ed out of the `Partial<Row>` half, never merely
// intersected over it: on the row `metadata` is the STORED string, and
// `string & unknown` is `string`, so a plain intersection refuses every
// body written as an object literal — which is the seeding convenience
// this harness exists for, and what it already does at runtime below.
seedRows: Array<Omit<Partial<Row>, 'metadata'> & { type: string; name: string; metadata: unknown }>,
) {
let nextId = 0;
const tables = new Map<string, Record<string, any>[]>();
Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-replay.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
2 changes: 1 addition & 1 deletion packages/metadata-protocol/src/seed-loader-retry.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { describe, it, expect, vi } from 'vitest';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate, type EngineFindOneQueryInput } from '@objectstack/metadata-core';

Expand DownExpand Up@@ -193,7 +193,7 @@ describe('seed loader — state_machine initialStates exemption (#3433)', () =>
// fallback), its options must carry the exemption flag — that is what the
// engine reads to skip the state_machine rule.
const writeCalls = [
...(engine.insertMany as any).mock.calls,
...((engine as any).insertMany).mock.calls,
...(engine.insert as any).mock.calls,
].filter(([obj]) => obj === 'showcase_project');
expect(writeCalls.length).toBeGreaterThan(0);
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,7 +2,7 @@

import { describe, it, expect, vi } from 'vitest';
import { SeedLoadResultSchema, SeedLoaderResultSchema } from '@objectstack/spec/data';
import { SeedLoaderService } from './seed-loader';
import { SeedLoaderService } from './seed-loader.js';
import type { IDataEngine, IMetadataService } from '@objectstack/spec/contracts';
import { assertEngineDeleteDispatch, assertEngineUpdateDispatch, assertEngineFindOnePredicate } from '@objectstack/metadata-core';

Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -334,7 +334,7 @@ describe('#4867 — history counters are never invented from a failed read', ()
expect(infoSpy).toHaveBeenCalledTimes(1);
expect((infoSpy.mock.calls[0] as [string])[0]).toMatch(/readable again/i);
// Numbering resumes after the surviving max — never from 1 again.
expect(engine.committed().at(-1)).toEqual({
expect(engine.committed().slice(-1)[0]).toEqual({
name: 'case_grid',
version: 3,
event_seq: 4,
Expand Down
26 changes: 11 additions & 15 deletions scripts/check-type-check-coverage.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -677,15 +677,6 @@ const DEBT = {
+ 'metadata.test.ts (34) and register-notifies-watchers.test.ts (16) do still hold 50 of the 89, '
+ 'but that is over HALF -- the "two thirds" claimed here was true at neither 92 nor 89.',
},
'@objectstack/metadata-protocol': {
errors: 63,
note: 'code-tier 40 (TS2322 x34, TS2532/TS2493 x2 each, TS2353, TS2339); config-tier 10 (TS2835 x9, '
+ 'TS2550); noise 13 (TS7006). Re-measured 63 at 5ab08428 -- the 2.25x drift that opened #5278, and '
+ 'the entry whose note was most misleading: it read "code-tier 9, the rest config-tier and noise", '
+ 'while code-tier alone is now 40. 27 of the TS2322 are in protocol.stored-migration.test.ts and 10 '
+ 'in seed-loader-multi-value-reference.test.ts, so this is concentrated debt in two files rather '
+ 'than a package-wide drizzle -- read it as two repairs, not as forty.',
},
'@objectstack/observability': {
errors: 11,
note: 'all code-tier (TS2554 wrong arity x10, TS2552).',
Expand DownExpand Up@@ -1898,9 +1889,12 @@ function workspacePackages() {
// "the workspace root itself: code-tier 4 ..." qualifies);
// * a tier counted twice, or a further `code-tier 9`-shaped count ANYWHERE
// later in the note, means the note is quoting its own history and the
// entry is skipped. metadata-protocol quotes the misleading note #5278
// found ("code-tier 9, the rest config-tier and noise") and is skipped for
// exactly that reason -- correct entry, no verdict;
// entry is skipped. metadata-protocol's entry quoted the misleading note
// #5278 found ("code-tier 9, the rest config-tier and noise") and was
// skipped for exactly that reason -- correct entry, no verdict. That entry
// has since GRADUATED (the package declares `typecheck` and its 63 errors
// are repaired), so the rule's live example is the self-test case below
// rather than a ledger row you can still read here;
// * per-code tallies (`TS2835 x72, TS7006 x49, ...`) are NOT summed. They are
// partial by construction, and the worked example this rule was written
// against says why: `@objectstack/rest`'s tally summed to 147 while saying
Expand DownExpand Up@@ -4206,9 +4200,11 @@ function selfTest() {
},
{
// The false-positive guard, and the reason the rule abstains rather than
// reasons: metadata-protocol's real note quotes the misleading one #5278
// found. Reading either count as the entry's own would red a correct
// entry, which is worse than the silence this check replaces.
// reasons: metadata-protocol's real note quoted the misleading one #5278
// found (that entry has since graduated, which is why this synthetic case
// now carries the shape). Reading either count as the entry's own would
// red a correct entry, which is worse than the silence this check
// replaces.
label: 'a note quoting its own history is SKIPPED, not guessed at',
packages: [],
root: { name: 'root', scripts: { typecheck: 'turbo run typecheck' } },
Expand Down
Loading