gentle-shell-bridge 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +91 -722
- package/docs/contract.md +92 -35
- package/package.json +13 -1
- package/src/api.ts +1 -1
- package/.codegraph/.gitignore +0 -5
- package/PRD.md +0 -144
- package/examples/bash-card.ts +0 -1694
- package/gentle-shell-bridge-0.3.0.tgz +0 -0
- package/odd/tasks/palette-sections.md +0 -30
- package/odd/tasks/plugin-keymap.md +0 -32
- package/odd/tasks/plugin-surface-contract.md +0 -55
- package/test/api.test.ts +0 -395
- package/test/apply-on-move.test.ts +0 -477
- package/test/arm.test.ts +0 -220
- package/test/bridge-ready.test.ts +0 -309
- package/test/bus.test.ts +0 -165
- package/test/button-rows.test.ts +0 -409
- package/test/capture.test.ts +0 -356
- package/test/card-style-rows.test.ts +0 -510
- package/test/card-style-transform.test.ts +0 -379
- package/test/card-style-wiring.test.ts +0 -258
- package/test/card-styles-e2e.test.ts +0 -491
- package/test/card-styles.test.ts +0 -324
- package/test/card-transcript-path.test.ts +0 -178
- package/test/config.test.ts +0 -93
- package/test/e2e.test.ts +0 -443
- package/test/example-bash-identity.test.ts +0 -372
- package/test/example-bash-matrix.test.ts +0 -856
- package/test/example-designs.test.ts +0 -734
- package/test/example-neon-transform.test.ts +0 -283
- package/test/example-plain-style.test.ts +0 -1268
- package/test/extension.test.ts +0 -160
- package/test/fake-events.ts +0 -58
- package/test/fake-host.ts +0 -211
- package/test/fake-sidebar.ts +0 -516
- package/test/fake-transcript.ts +0 -486
- package/test/frame-telemetry.test.ts +0 -417
- package/test/hook.test.ts +0 -196
- package/test/manifest.test.ts +0 -105
- package/test/new-category.test.ts +0 -979
- package/test/notices.test.ts +0 -328
- package/test/plugin-integration-lines.test.ts +0 -979
- package/test/plugin-surface.test.ts +0 -152
- package/test/presence.test.ts +0 -459
- package/test/rail-surfaces.test.ts +0 -457
- package/test/rail-width.test.ts +0 -423
- package/test/regression.test.ts +0 -483
- package/test/repaint-api.test.ts +0 -200
- package/test/reserved-categories.test.ts +0 -361
- package/test/row-labels.test.ts +0 -284
- package/test/row-names.test.ts +0 -473
- package/test/row-origin.test.ts +0 -395
- package/test/section-interaction.test.ts +0 -364
- package/test/section-panel.test.ts +0 -403
- package/test/sections-rows.test.ts +0 -291
- package/test/sidebar-backend.test.ts +0 -471
- package/test/sidebar-e2e.test.ts +0 -331
- package/test/sidebar-hover.test.ts +0 -276
- package/test/sidebar-independent.test.ts +0 -349
- package/test/sidebar-render.test.ts +0 -281
- package/test/sidebar-sections.test.ts +0 -245
- package/test/status-card-styles.test.ts +0 -201
- package/test/status-section-frame.test.ts +0 -181
- package/test/status-sections.test.ts +0 -243
- package/test/status.test.ts +0 -209
- package/test/store.test.ts +0 -192
- package/test/surface-repaint-cost.test.ts +0 -520
- package/test/tool-design-chain.test.ts +0 -483
- package/test/tool-design-cost.test.ts +0 -473
- package/test/tool-design-rows.test.ts +0 -359
- package/test/tool-designs.test.ts +0 -745
- package/test/transform-pipeline.test.ts +0 -465
- package/test/transforms-bus.test.ts +0 -233
- package/test/verifier-width-regressions.test.ts +0 -164
- package/tsconfig.json +0 -18
|
@@ -1,372 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* T10: the worked example's DESIGN for `bash`, driven through the real bus (S1, S5, S6, S8).
|
|
3
|
-
*
|
|
4
|
-
* The host heads a minimal bash card with the bare command and supplies the `$` prompt as the card's
|
|
5
|
-
* glyph (`quiet-tools.ts:521-525`). The design in `examples/bash-card.ts` heads that card `bash`
|
|
6
|
-
* instead, and changes nothing else: the frame, the ANSI, the padding, the right-aligned hint and
|
|
7
|
-
* every body row are the host's own bytes.
|
|
8
|
-
*
|
|
9
|
-
* This file loads the real example, arms the real bridge (which installs the one resolver and the
|
|
10
|
-
* `Cards` rows), and renders the components Pi keeps — the call component and the result component —
|
|
11
|
-
* so the claim is made about the rows a user sees, not about a helper. `float` here; the `neon`
|
|
12
|
-
* outline is `test/example-neon-transform.test.ts`.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import assert from "node:assert/strict";
|
|
16
|
-
import { mkdtempSync, rmSync } from "node:fs";
|
|
17
|
-
import { tmpdir } from "node:os";
|
|
18
|
-
import { join } from "node:path";
|
|
19
|
-
import test from "node:test";
|
|
20
|
-
|
|
21
|
-
import { publishBridgeApi, resetBridgeApiForTests } from "../src/api.ts";
|
|
22
|
-
import {
|
|
23
|
-
resetBusForTests,
|
|
24
|
-
resetCardStylesForTests,
|
|
25
|
-
resetSectionsForTests,
|
|
26
|
-
} from "../src/bus.ts";
|
|
27
|
-
import { resetCardStyleTransformForTests } from "../src/card-style-transform.ts";
|
|
28
|
-
import { disableCardStyleTransform, resetCardStyleWiringForTests } from "../src/card-style-wiring.ts";
|
|
29
|
-
import { disableCaptureBackend, resetCaptureStateForTests } from "../src/capture.ts";
|
|
30
|
-
import gentleShellBridge, { type BridgeExtensionApi } from "../src/extension.ts";
|
|
31
|
-
import { resetHookStateForTests } from "../src/hook.ts";
|
|
32
|
-
import { resetNoticesForTests } from "../src/notices.ts";
|
|
33
|
-
import { resetPluginLinesForTests } from "../src/plugin-lines.ts";
|
|
34
|
-
import { resetRepaintForTests } from "../src/repaint.ts";
|
|
35
|
-
import { buildRows, resetRowBuildStateForTests } from "../src/rows.ts";
|
|
36
|
-
import { disableSidebarBackend, resetSidebarStateForTests } from "../src/sidebar.ts";
|
|
37
|
-
import { resetSectionFailuresForTests } from "../src/sidebar-render.ts";
|
|
38
|
-
import { resetStoreStateForTests } from "../src/store.ts";
|
|
39
|
-
import { resetToolDesignsForTests, setToolDesignSelection } from "../src/tool-designs.ts";
|
|
40
|
-
import { resetToolDesignRowStateForTests } from "../src/tool-design-rows.ts";
|
|
41
|
-
import { resetToolDesignWiringForTests } from "../src/tool-design-wiring.ts";
|
|
42
|
-
import type { CustomizeRow, InlineHelpers } from "../src/types.ts";
|
|
43
|
-
import { createFakeHost } from "./fake-host.ts";
|
|
44
|
-
import {
|
|
45
|
-
BASH_MINIMAL_FLOAT_CALL,
|
|
46
|
-
BASH_MINIMAL_FLOAT_RESULT,
|
|
47
|
-
stripAnsi,
|
|
48
|
-
} from "./fake-transcript.ts";
|
|
49
|
-
|
|
50
|
-
let configHome: string;
|
|
51
|
-
let previousConfigHome: string | undefined;
|
|
52
|
-
|
|
53
|
-
test.before(() => {
|
|
54
|
-
configHome = mkdtempSync(join(tmpdir(), "gsb-example-identity-"));
|
|
55
|
-
previousConfigHome = process.env.GENTLE_PI_CONFIG_HOME;
|
|
56
|
-
process.env.GENTLE_PI_CONFIG_HOME = configHome;
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test.after(() => {
|
|
60
|
-
if (previousConfigHome === undefined) delete process.env.GENTLE_PI_CONFIG_HOME;
|
|
61
|
-
else process.env.GENTLE_PI_CONFIG_HOME = previousConfigHome;
|
|
62
|
-
rmSync(configHome, { recursive: true, force: true });
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test.beforeEach(() => {
|
|
66
|
-
rmSync(join(configHome, "gentle-shell-bridge"), { recursive: true, force: true });
|
|
67
|
-
resetBridgeApiForTests();
|
|
68
|
-
resetBusForTests();
|
|
69
|
-
resetSectionsForTests();
|
|
70
|
-
resetCardStylesForTests();
|
|
71
|
-
resetCardStyleTransformForTests();
|
|
72
|
-
resetCardStyleWiringForTests();
|
|
73
|
-
resetCaptureStateForTests();
|
|
74
|
-
resetHookStateForTests();
|
|
75
|
-
resetRowBuildStateForTests();
|
|
76
|
-
resetSidebarStateForTests();
|
|
77
|
-
resetSectionFailuresForTests();
|
|
78
|
-
resetNoticesForTests();
|
|
79
|
-
resetPluginLinesForTests();
|
|
80
|
-
resetRepaintForTests();
|
|
81
|
-
resetStoreStateForTests();
|
|
82
|
-
resetToolDesignsForTests();
|
|
83
|
-
resetToolDesignRowStateForTests();
|
|
84
|
-
resetToolDesignWiringForTests();
|
|
85
|
-
disableCaptureBackend();
|
|
86
|
-
disableSidebarBackend();
|
|
87
|
-
disableCardStyleTransform();
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
type SessionHandler = (event: unknown, ctx: { hasUI?: boolean; ui?: unknown }) => void;
|
|
91
|
-
|
|
92
|
-
interface FakePi {
|
|
93
|
-
on?: (event: string, handler: SessionHandler) => void;
|
|
94
|
-
registerCommand?: () => void;
|
|
95
|
-
registerToolRenderer?: (resolver: unknown) => void;
|
|
96
|
-
/** Present because the bridge checks the REQUIRED host package at runtime (S9/T12). */
|
|
97
|
-
getCommands?: () => Array<{ name: string }>;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
type ExampleInit = (pi: FakePi) => () => void;
|
|
101
|
-
|
|
102
|
-
const loadExample = async (tag: string): Promise<ExampleInit> => {
|
|
103
|
-
const specifier = new URL(`../examples/bash-card.ts?${tag}`, import.meta.url).href;
|
|
104
|
-
return ((await import(specifier)) as { default: ExampleInit }).default;
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const inlineHelpers: InlineHelpers = {
|
|
108
|
-
input: async () => undefined,
|
|
109
|
-
confirm: async () => true,
|
|
110
|
-
capture: async () => undefined,
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
/** Pi's own component contract, as far as a card uses it. */
|
|
114
|
-
interface FakeComponent {
|
|
115
|
-
render(width: number): string[];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
interface FakeRenderers {
|
|
119
|
-
renderShell?: unknown;
|
|
120
|
-
renderCall?: unknown;
|
|
121
|
-
renderResult?: unknown;
|
|
122
|
-
[member: string]: unknown;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/** A component that returns ONE array instance, so "the host's own rows" is observable by identity. */
|
|
126
|
-
function fakeComponent(lines: readonly string[]): FakeComponent {
|
|
127
|
-
const rows = [...lines];
|
|
128
|
-
return { render: (): string[] => rows };
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** The renderers a tool advertises: a call component and a result component, like the host's. */
|
|
132
|
-
function fakeRenderers(call: readonly string[], result: readonly string[]): FakeRenderers {
|
|
133
|
-
// One component instance per renderer, like Pi: the renderer is called once and the SAME object
|
|
134
|
-
// is re-rendered on every frame, which is what makes "the host's own array instance" observable.
|
|
135
|
-
const callComponent = fakeComponent(call);
|
|
136
|
-
const resultComponent = fakeComponent(result);
|
|
137
|
-
return {
|
|
138
|
-
renderShell: "default",
|
|
139
|
-
renderCall: () => callComponent,
|
|
140
|
-
renderResult: () => resultComponent,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const THEME = { name: "fake-theme" };
|
|
145
|
-
|
|
146
|
-
/** The component Pi keeps after resolving a renderer once, when the card is constructed. */
|
|
147
|
-
function mount(
|
|
148
|
-
renderers: FakeRenderers,
|
|
149
|
-
member: "renderCall" | "renderResult",
|
|
150
|
-
): FakeComponent {
|
|
151
|
-
const renderer = renderers[member];
|
|
152
|
-
assert.equal(typeof renderer, "function");
|
|
153
|
-
return member === "renderCall"
|
|
154
|
-
? (renderer as (args: unknown, theme: unknown, ctx: unknown) => FakeComponent)(
|
|
155
|
-
{ command: "npm test" },
|
|
156
|
-
THEME,
|
|
157
|
-
{},
|
|
158
|
-
)
|
|
159
|
-
: (renderer as (result: unknown, options: unknown, theme: unknown, ctx: unknown) => FakeComponent)(
|
|
160
|
-
{ content: [] },
|
|
161
|
-
{ expanded: false },
|
|
162
|
-
THEME,
|
|
163
|
-
{},
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
interface World {
|
|
168
|
-
/** The one resolver the bridge registered on this Pi. */
|
|
169
|
-
readonly resolver: (tool: string, next: () => FakeRenderers) => FakeRenderers | undefined;
|
|
170
|
-
/** The rows the customize menu builds right now. */
|
|
171
|
-
rows(): CustomizeRow[];
|
|
172
|
-
/** Press the value with this label on the `bash` design line. */
|
|
173
|
-
pick(value: string): Promise<void>;
|
|
174
|
-
dispose(): void;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* A session as Pi runs it: the bridge arms itself (installing the one resolver and the design rows),
|
|
179
|
-
* then the example registers its design from its own `session_start`.
|
|
180
|
-
*/
|
|
181
|
-
/** The tool-design line's setting, old bridge (`bash`) and current bridge (`Card bash`). */
|
|
182
|
-
const isBashDesignSetting = (setting: string | undefined): boolean =>
|
|
183
|
-
setting === "bash" || setting === "Card bash";
|
|
184
|
-
|
|
185
|
-
async function startWorld(tag: string): Promise<World> {
|
|
186
|
-
publishBridgeApi();
|
|
187
|
-
const host = createFakeHost();
|
|
188
|
-
const resolvers: unknown[] = [];
|
|
189
|
-
const sessionHandlers: SessionHandler[] = [];
|
|
190
|
-
const pi: FakePi = {
|
|
191
|
-
// `gentle-pi` is present, so the bridge's `session_start` arms (S9/T12).
|
|
192
|
-
getCommands: () => [{ name: "gentle:customize" }],
|
|
193
|
-
on(_event, handler) {
|
|
194
|
-
sessionHandlers.push(handler);
|
|
195
|
-
},
|
|
196
|
-
registerCommand() {},
|
|
197
|
-
registerToolRenderer(resolver) {
|
|
198
|
-
resolvers.push(resolver);
|
|
199
|
-
},
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
gentleShellBridge(pi as BridgeExtensionApi);
|
|
203
|
-
const dispose = (await loadExample(tag))(pi);
|
|
204
|
-
for (const handler of sessionHandlers) handler({}, { hasUI: true, ui: host.ui });
|
|
205
|
-
|
|
206
|
-
assert.equal(resolvers.length, 1, "the bridge registers exactly one resolver");
|
|
207
|
-
const resolver = resolvers[0] as World["resolver"];
|
|
208
|
-
assert.equal(typeof resolver, "function");
|
|
209
|
-
|
|
210
|
-
const rows = (): CustomizeRow[] => buildRows({ theme: undefined, configHome }).rows;
|
|
211
|
-
|
|
212
|
-
return {
|
|
213
|
-
resolver,
|
|
214
|
-
rows,
|
|
215
|
-
pick: async (value) => {
|
|
216
|
-
const row = rows().find(
|
|
217
|
-
(candidate) =>
|
|
218
|
-
isBashDesignSetting(candidate.choice?.setting) && candidate.choice?.value === value,
|
|
219
|
-
);
|
|
220
|
-
assert.ok(row !== undefined, `the Cards line for bash carries the value ${value}`);
|
|
221
|
-
assert.ok(row.action !== undefined, `the ${value} value must have an action`);
|
|
222
|
-
await row.action(inlineHelpers);
|
|
223
|
-
},
|
|
224
|
-
dispose,
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* The heading row with the host's `$` mark replaced by `bash`, and three fill columns fewer.
|
|
230
|
-
* The host's bytes are `test/fake-transcript.ts`'s `BASH_MINIMAL_FLOAT_CALL[1]`: the mark sits inside
|
|
231
|
-
* the title run the host painted, so the word replaces one character and the row's space fill — not
|
|
232
|
-
* the hint, not the rail — gives the three extra columns back.
|
|
233
|
-
*/
|
|
234
|
-
const DESIGNED_FLOAT_HEADING =
|
|
235
|
-
" \u001b[48;5;236m\u001b[95m▎\u001b[39m\u001b[95m \u001b[39m\u001b[95mbash \u001b[95m\u001b[1mnpm test\u001b[22m\u001b[39m" +
|
|
236
|
-
"\u001b[37m (timeout 30s)\u001b[39m\u001b[39m\u001b[95m \u001b[39m \u001b[2mctrl+o to expand\u001b[39m" +
|
|
237
|
-
" \u001b[95m \u001b[39m\u001b[49m ";
|
|
238
|
-
|
|
239
|
-
// ---------------------------------------------------------------------------------------------
|
|
240
|
-
// The default: the host's own card, no intervention
|
|
241
|
-
// ---------------------------------------------------------------------------------------------
|
|
242
|
-
|
|
243
|
-
test("T10/S8: the design appears on the `bash` Cards line beside the host's own card", async () => {
|
|
244
|
-
const world = await startWorld("cards-line");
|
|
245
|
-
|
|
246
|
-
const values = world
|
|
247
|
-
.rows()
|
|
248
|
-
.filter((row) => isBashDesignSetting(row.choice?.setting))
|
|
249
|
-
.map((row) => row.choice?.value);
|
|
250
|
-
assert.deepEqual(values, ["native", "bash heading"], "the host's card is the default value");
|
|
251
|
-
|
|
252
|
-
const native = world
|
|
253
|
-
.rows()
|
|
254
|
-
.find((row) => isBashDesignSetting(row.choice?.setting) && row.choice?.value === "native");
|
|
255
|
-
assert.equal(native?.choice?.current(), true, "nothing is selected on install");
|
|
256
|
-
|
|
257
|
-
world.dispose();
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
test("T10: with the host's own card selected, the resolver draws the host's rows unchanged", async () => {
|
|
261
|
-
const world = await startWorld("native-bytes");
|
|
262
|
-
const renderers = fakeRenderers(BASH_MINIMAL_FLOAT_CALL, BASH_MINIMAL_FLOAT_RESULT);
|
|
263
|
-
const resolved = world.resolver("bash", () => renderers);
|
|
264
|
-
assert.ok(resolved !== undefined);
|
|
265
|
-
|
|
266
|
-
const call = mount(resolved, "renderCall");
|
|
267
|
-
const result = mount(resolved, "renderResult");
|
|
268
|
-
|
|
269
|
-
const hostCall = mount(renderers, "renderCall").render(60);
|
|
270
|
-
const hostResult = mount(renderers, "renderResult").render(60);
|
|
271
|
-
|
|
272
|
-
assert.equal(call.render(60), hostCall, "the host's own ARRAY instance, not a copy");
|
|
273
|
-
assert.equal(result.render(60), hostResult, "both renderers, byte for byte");
|
|
274
|
-
assert.deepEqual(call.render(60), [...BASH_MINIMAL_FLOAT_CALL]);
|
|
275
|
-
assert.deepEqual(result.render(60), [...BASH_MINIMAL_FLOAT_RESULT]);
|
|
276
|
-
|
|
277
|
-
world.dispose();
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
// ---------------------------------------------------------------------------------------------
|
|
281
|
-
// The design: `bash` where the host prints `$`, and every other byte the host's
|
|
282
|
-
// ---------------------------------------------------------------------------------------------
|
|
283
|
-
|
|
284
|
-
test("T10: the `bash` design changes the heading mark and nothing else, byte for byte", async () => {
|
|
285
|
-
const world = await startWorld("designed-bytes");
|
|
286
|
-
const renderers = fakeRenderers(BASH_MINIMAL_FLOAT_CALL, BASH_MINIMAL_FLOAT_RESULT);
|
|
287
|
-
const resolved = world.resolver("bash", () => renderers);
|
|
288
|
-
assert.ok(resolved !== undefined);
|
|
289
|
-
const call = mount(resolved, "renderCall");
|
|
290
|
-
const result = mount(resolved, "renderResult");
|
|
291
|
-
|
|
292
|
-
await world.pick("bash heading");
|
|
293
|
-
|
|
294
|
-
const output = call.render(60);
|
|
295
|
-
|
|
296
|
-
assert.equal(output.length, BASH_MINIMAL_FLOAT_CALL.length, "the frame keeps its row count");
|
|
297
|
-
assert.equal(output[1], DESIGNED_FLOAT_HEADING, "the heading mark is `bash`");
|
|
298
|
-
assert.equal(
|
|
299
|
-
stripAnsi(output[1] ?? "").length,
|
|
300
|
-
stripAnsi(BASH_MINIMAL_FLOAT_CALL[1] ?? "").length,
|
|
301
|
-
"width preserved",
|
|
302
|
-
);
|
|
303
|
-
for (const index of [0]) {
|
|
304
|
-
assert.equal(
|
|
305
|
-
output[index],
|
|
306
|
-
BASH_MINIMAL_FLOAT_CALL[index],
|
|
307
|
-
`row ${index} is the host's byte for byte`,
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
assert.notEqual(
|
|
311
|
-
output,
|
|
312
|
-
BASH_MINIMAL_FLOAT_CALL,
|
|
313
|
-
"a new frame was produced, not the host's array mutated",
|
|
314
|
-
);
|
|
315
|
-
|
|
316
|
-
const resultOutput = result.render(60);
|
|
317
|
-
assert.deepEqual(
|
|
318
|
-
resultOutput,
|
|
319
|
-
mount(renderers, "renderResult").render(60),
|
|
320
|
-
"the body is the host's, row for row",
|
|
321
|
-
);
|
|
322
|
-
assert.deepEqual(resultOutput, [...BASH_MINIMAL_FLOAT_RESULT], "every result row is byte-identical");
|
|
323
|
-
assert.ok(
|
|
324
|
-
resultOutput.some((row) => row.includes("duration 1.2s")),
|
|
325
|
-
"the host's body is what was drawn",
|
|
326
|
-
);
|
|
327
|
-
|
|
328
|
-
world.dispose();
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
test("T10: picking the host's own card again restores the host's rows", async () => {
|
|
332
|
-
const world = await startWorld("back-to-native");
|
|
333
|
-
const renderers = fakeRenderers(BASH_MINIMAL_FLOAT_CALL, BASH_MINIMAL_FLOAT_RESULT);
|
|
334
|
-
const resolved = world.resolver("bash", () => renderers);
|
|
335
|
-
assert.ok(resolved !== undefined);
|
|
336
|
-
const call = mount(resolved, "renderCall");
|
|
337
|
-
|
|
338
|
-
await world.pick("bash heading");
|
|
339
|
-
assert.equal(call.render(60)[1], DESIGNED_FLOAT_HEADING);
|
|
340
|
-
|
|
341
|
-
await world.pick("native");
|
|
342
|
-
assert.deepEqual(call.render(60), [...BASH_MINIMAL_FLOAT_CALL], "the host's card, unchanged");
|
|
343
|
-
|
|
344
|
-
world.dispose();
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
test("T10: the design is declared for the `bash` tool name, so another tool is untouched", async () => {
|
|
348
|
-
const world = await startWorld("other-tool");
|
|
349
|
-
const readRenderers = fakeRenderers(
|
|
350
|
-
[" \u001b[90m▎\u001b[39m \u001b[2m≡ read src/api.ts\u001b[39m"],
|
|
351
|
-
[" \u001b[90m▎\u001b[39m export function bridgeApi() {"],
|
|
352
|
-
);
|
|
353
|
-
|
|
354
|
-
const resolved = world.resolver("read", () => readRenderers);
|
|
355
|
-
|
|
356
|
-
assert.equal(resolved, readRenderers, "a tool with no design keeps the host's own renderers");
|
|
357
|
-
world.dispose();
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
test("T10: a design whose selection names nothing falls back to the host's card", async () => {
|
|
361
|
-
const world = await startWorld("missing-selection");
|
|
362
|
-
const renderers = fakeRenderers(BASH_MINIMAL_FLOAT_CALL, BASH_MINIMAL_FLOAT_RESULT);
|
|
363
|
-
const resolved = world.resolver("bash", () => renderers);
|
|
364
|
-
assert.ok(resolved !== undefined);
|
|
365
|
-
const call = mount(resolved, "renderCall");
|
|
366
|
-
|
|
367
|
-
setToolDesignSelection("bash", "bash-card.retired");
|
|
368
|
-
|
|
369
|
-
assert.deepEqual(call.render(60), [...BASH_MINIMAL_FLOAT_CALL], "a design nobody owns draws the host's card");
|
|
370
|
-
|
|
371
|
-
world.dispose();
|
|
372
|
-
});
|