mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
7a1640e53f
* refactor: move errors/redaction/device into src/kernel — Phase 5 slice 3
Relocates the foundational primitive trio from src/utils/ into the kernel/ layer
(joining snapshot.ts from slice 2), per the target folder DAG in
plans/perfect-shape.md §5.5. A pure path codemod, no behavior change.
They form a closed cluster — device -> errors -> redaction, with redaction a
leaf — so kernel/ takes no upward dependency, and every importer becomes a clean
downward import toward kernel. errors.ts is the most-imported module in the
tree; device.ts the §5.5-named headliner. Moving all three atomically avoids a
half-state where one would import another across the utils/kernel boundary.
Imports rewritten by a resolve-based codemod (compares each specifier's resolved
path to the moved files, so the unrelated commands/management/device.ts and
other same-named files are untouched): 483 sites across 402 files. The two
platform-descriptor doc comments and the fallow health baseline key for
device.ts are updated to the new path; the contracts-schema-public guard that
asserts the error helpers pull no diagnostics/node: deps now reads kernel/.
Verified: tsc --noEmit, oxfmt + oxlint --deny-warnings, rslib build, full vitest
suite (2877 pass), fallow audit clean (411 changed files), Layering Guard empty;
kernel/ files import only within kernel.
* docs: update guidance references to kernel/{device,errors} after the move
AGENTS.md (Apple-family sync rule + normalizeError), ADR-0009, and
plans/apple-platform-consolidation.md still named the old src/utils/ paths.
Point them at src/kernel/. plans/perfect-shape.md's utils/device.ts mention is
left as-is — it describes the pre-move diagnosis.
133 lines
3.9 KiB
TypeScript
133 lines
3.9 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import { isDeepStrictEqual } from 'node:util';
|
|
import type { Platform } from '../../../src/kernel/device.ts';
|
|
|
|
export interface ProviderScenarioProviderScope {
|
|
deviceId?: string;
|
|
platform?: Platform;
|
|
}
|
|
|
|
export interface ProviderScenarioProviderEntry<
|
|
TResult = unknown,
|
|
> extends ProviderScenarioProviderScope {
|
|
command: string;
|
|
request?: unknown;
|
|
result?: TResult;
|
|
error?: Error | string;
|
|
}
|
|
|
|
export interface ProviderScenarioProviderCall<
|
|
TResult = unknown,
|
|
> extends ProviderScenarioProviderScope {
|
|
command: string;
|
|
request?: unknown;
|
|
result?: TResult;
|
|
}
|
|
|
|
export interface ProviderScenarioTranscript {
|
|
readonly calls: readonly ProviderScenarioProviderCall[];
|
|
readonly remaining: readonly ProviderScenarioProviderEntry[];
|
|
next<TResult = unknown>(
|
|
command: string,
|
|
request?: unknown,
|
|
scope?: ProviderScenarioProviderScope,
|
|
): TResult;
|
|
assertComplete(): void;
|
|
}
|
|
|
|
export function createProviderTranscript(
|
|
entries: readonly ProviderScenarioProviderEntry[],
|
|
options: { ordered?: boolean } = {},
|
|
): ProviderScenarioTranscript {
|
|
const pending = [...entries];
|
|
const calls: ProviderScenarioProviderCall[] = [];
|
|
|
|
return {
|
|
get calls() {
|
|
return [...calls];
|
|
},
|
|
get remaining() {
|
|
return [...pending];
|
|
},
|
|
next<TResult = unknown>(
|
|
command: string,
|
|
request?: unknown,
|
|
scope: ProviderScenarioProviderScope = {},
|
|
): TResult {
|
|
const entryIndex = options.ordered
|
|
? 0
|
|
: pending.findIndex((candidate) =>
|
|
providerEntryMatches(candidate, command, request, scope),
|
|
);
|
|
const entry = entryIndex >= 0 ? pending.splice(entryIndex, 1)[0] : undefined;
|
|
assert.ok(entry, `Unexpected provider call: ${formatCall(command, scope)}`);
|
|
assert.equal(command, entry.command, 'Provider command mismatch');
|
|
assertScope(scope, entry);
|
|
if (Object.hasOwn(entry, 'request')) {
|
|
assert.deepEqual(request, entry.request, 'Provider request mismatch');
|
|
}
|
|
|
|
const call = {
|
|
command,
|
|
request,
|
|
deviceId: scope.deviceId,
|
|
platform: scope.platform,
|
|
result: entry.result as TResult,
|
|
};
|
|
calls.push(call);
|
|
|
|
if (entry.error) {
|
|
throw entry.error instanceof Error ? entry.error : new Error(entry.error);
|
|
}
|
|
|
|
return entry.result as TResult;
|
|
},
|
|
assertComplete() {
|
|
assert.equal(
|
|
pending.length,
|
|
0,
|
|
`Unconsumed provider transcript entries: ${pending.map(formatEntry).join(', ')}`,
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
export function createOrderedProviderTranscript(
|
|
entries: readonly ProviderScenarioProviderEntry[],
|
|
): ProviderScenarioTranscript {
|
|
return createProviderTranscript(entries, { ordered: true });
|
|
}
|
|
|
|
function providerEntryMatches(
|
|
entry: ProviderScenarioProviderEntry,
|
|
command: string,
|
|
request: unknown,
|
|
scope: ProviderScenarioProviderScope,
|
|
): boolean {
|
|
if (entry.command !== command) return false;
|
|
if (entry.deviceId && entry.deviceId !== scope.deviceId) return false;
|
|
if (entry.platform && entry.platform !== scope.platform) return false;
|
|
return !Object.hasOwn(entry, 'request') || isDeepStrictEqual(request, entry.request);
|
|
}
|
|
|
|
function assertScope(
|
|
actual: ProviderScenarioProviderScope,
|
|
expected: ProviderScenarioProviderEntry,
|
|
): void {
|
|
if (expected.deviceId) {
|
|
assert.equal(actual.deviceId, expected.deviceId, 'Provider device id mismatch');
|
|
}
|
|
if (expected.platform) {
|
|
assert.equal(actual.platform, expected.platform, 'Provider platform mismatch');
|
|
}
|
|
}
|
|
|
|
function formatCall(command: string, scope: ProviderScenarioProviderScope): string {
|
|
return formatEntry({ command, ...scope });
|
|
}
|
|
|
|
function formatEntry(entry: { command: string; deviceId?: string; platform?: Platform }): string {
|
|
const scope = [entry.platform, entry.deviceId].filter(Boolean).join(':');
|
|
return scope ? `${scope}.${entry.command}` : entry.command;
|
|
}
|