@operato/board 10.29.52 → 10.29.57
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/CHANGELOG.md +22 -0
- package/dist/src/resolved-scene.d.ts +9 -0
- package/dist/src/resolved-scene.js +12 -0
- package/dist/src/resolved-scene.js.map +1 -1
- package/dist/test/resolved-scene.test.js +29 -1
- package/dist/test/resolved-scene.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/test/resolved-scene.test.ts +33 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
### [10.29.57](https://github.com/hatiolab/operato/compare/v10.29.56...v10.29.57) (2026-10-27)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
* **board:** useThemes -- a scene opens with the domain's themes as its style (ADR-0166 7) ([4fdea63](https://github.com/hatiolab/operato/commit/4fdea63f244aa13f3c98969e4211d4288ae4c83b))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### :bug: Bug Fix
|
|
15
|
+
|
|
16
|
+
* **slot-layout-editor:** words for ACCEPTS_EMPTY, things-scene ^10.1.102 ([ca42efb](https://github.com/hatiolab/operato/commit/ca42efb8b2feb6cc917febd5a0597f6a1360aef9))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### [10.29.56](https://github.com/hatiolab/operato/compare/v10.29.55...v10.29.56) (2026-10-26)
|
|
21
|
+
|
|
22
|
+
**Note:** Version bump only for package @operato/board
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
### [10.29.52](https://github.com/hatiolab/operato/compare/v10.29.51...v10.29.52) (2026-10-25)
|
|
7
29
|
|
|
8
30
|
**Note:** Version bump only for package @operato/board
|
|
@@ -16,4 +16,13 @@ export type ItemTypesProvider = () => Promise<unknown>;
|
|
|
16
16
|
* Null takes it back.
|
|
17
17
|
*/
|
|
18
18
|
export declare function useItemTypes(provider: ItemTypesProvider | null): void;
|
|
19
|
+
/** Answers the domain's themes -- its legends among them -- for a scene about to open: name → value, the active ones. */
|
|
20
|
+
export type ThemesProvider = () => Promise<Record<string, unknown>>;
|
|
21
|
+
/**
|
|
22
|
+
* An app whose boards show legends (ADR-0166 7) gives this package what answers its domain's active themes, once, from
|
|
23
|
+
* its bootstrap. Every scene this package opens is then given them as its `style`, name → value, where a figure's table
|
|
24
|
+
* finds the legend chosen for its role. An app that gives none opens its scenes without them: tables show by the
|
|
25
|
+
* figures' own. Null takes it back.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useThemes(provider: ThemesProvider | null): void;
|
|
19
28
|
export declare function createResolvedScene(options: SceneCreateOptions, stillWanted?: StillWanted): Promise<ReturnType<typeof create> | null>;
|
|
@@ -12,10 +12,22 @@ let itemTypesProvider = null;
|
|
|
12
12
|
export function useItemTypes(provider) {
|
|
13
13
|
itemTypesProvider = provider;
|
|
14
14
|
}
|
|
15
|
+
let themesProvider = null;
|
|
16
|
+
/**
|
|
17
|
+
* An app whose boards show legends (ADR-0166 7) gives this package what answers its domain's active themes, once, from
|
|
18
|
+
* its bootstrap. Every scene this package opens is then given them as its `style`, name → value, where a figure's table
|
|
19
|
+
* finds the legend chosen for its role. An app that gives none opens its scenes without them: tables show by the
|
|
20
|
+
* figures' own. Null takes it back.
|
|
21
|
+
*/
|
|
22
|
+
export function useThemes(provider) {
|
|
23
|
+
themesProvider = provider;
|
|
24
|
+
}
|
|
15
25
|
export async function createResolvedScene(options, stillWanted) {
|
|
16
26
|
var _a;
|
|
17
27
|
if (itemTypesProvider && options.itemTypes === undefined)
|
|
18
28
|
options = { ...options, itemTypes: await itemTypesProvider() };
|
|
29
|
+
if (themesProvider && options.style === undefined)
|
|
30
|
+
options = { ...options, style: await themesProvider() };
|
|
19
31
|
const resolution = await resolveUnknownTypes(options.model);
|
|
20
32
|
const { unresolved, failed } = resolution;
|
|
21
33
|
/* The reason a resolver gave for each type it refused (ADR-0114 A3); older scenes report none. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolved-scene.js","sourceRoot":"","sources":["../../src/resolved-scene.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAoCpE,IAAI,iBAAiB,GAA6B,IAAI,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,QAAkC;IAC7D,iBAAiB,GAAG,QAAQ,CAAA;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA2B,EAC3B,WAAyB;;IAEzB,IAAI,iBAAiB,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS;QAAE,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,EAAE,EAAE,CAAA;IACxH,MAAM,UAAU,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC3D,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;IACzC,kGAAkG;IAClG,MAAM,OAAO,GAAwC,MAAC,UAAkB,CAAC,OAAO,mCAAI,EAAE,CAAA;IAEtF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;QACzE,MAAM,OAAO,GAAG;YACd,GAAG,MAAM,CAAC,GAAG,CACX,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACvG;YACD,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,WAAC,OAAA,GAAG,IAAI,KAAK,MAAA,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mCAAI,UAAU,EAAE,CAAA,EAAA,CAAC;SACvG,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,yBAAyB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC9D,CAAC;IAED,IAAI,WAAW,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QAClC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,CAAA;AACxB,CAAC","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { create, resolveUnknownTypes } from '@hatiolab/things-scene'\nimport type { SceneCreateOptions } from '@hatiolab/things-scene'\n\n/*\n * The one place this package turns a model into a scene.\n *\n * ── Why it is one place ─────────────────────────────────────────────────────\n * `create()` is synchronous and compiles what is registered at that moment, so the types a model\n * names and nobody has registered have to be fetched first (`figure-provider.ts` fetches them).\n * Written at each scene site, that \"first\" is six lines that drift apart, and the seventh site\n * forgets it. So every site in this package calls this function instead, and a test counts that\n * nobody else imports `create` (test/scene-create-single-door.test.ts).\n *\n * ── It costs nothing when there is nothing to resolve ───────────────────────\n * `resolveUnknownTypes` collects the model's unregistered types first and only wakes a resolver if\n * there are any. A board of plain scene components asks no server anything — every board-opening\n * screen goes through here, so that has to stay true.\n *\n * ── A scene opens even when the figures do not ──────────────────────────────\n * Resolution never throws: a resolver that rejects is reported in `failed`, and a type nobody\n * published stays in `unresolved`. Both draw as stand-ins and are saved back untouched (ADR-0063\n * 결정 1). They are not the same fact, so the warning says which happened to which type — silence\n * would leave \"the server said no\" looking exactly like \"there is no such figure\".\n */\n\n/**\n * Tells whether the caller still wants this scene after the await.\n *\n * The wait makes the caller re-entrant: an element can be detached, or handed a new model, while\n * the types are being fetched. Without this, the late scene overwrites the current one.\n */\nexport type StillWanted = () => boolean\n\n/** Answers the domain's item type table (ADR-0155) for a scene about to open. */\nexport type ItemTypesProvider = () => Promise<unknown>\n\nlet itemTypesProvider: ItemTypesProvider | null = null\n\n/**\n * An app that uses item types (ADR-0155) gives this package what answers its domain's table, once, from its bootstrap\n * (operato-board gives figure-library's `fetchDomainItemTypes`). Every scene this package opens is then given the table\n * as it opens. An app that gives none opens its scenes without one: their items keep the component type, as before.\n * Null takes it back.\n */\nexport function useItemTypes(provider: ItemTypesProvider | null): void {\n itemTypesProvider = provider\n}\n\nexport async function createResolvedScene(\n options: SceneCreateOptions,\n stillWanted?: StillWanted\n): Promise<ReturnType<typeof create> | null> {\n if (itemTypesProvider && options.itemTypes === undefined) options = { ...options, itemTypes: await itemTypesProvider() }\n const resolution = await resolveUnknownTypes(options.model)\n const { unresolved, failed } = resolution\n /* The reason a resolver gave for each type it refused (ADR-0114 A3); older scenes report none. */\n const refused: { type: string; message: string }[] = (resolution as any).refused ?? []\n\n if (failed.length > 0 || unresolved.length > 0) {\n const asked = new Set(failed.flatMap(({ types }) => types))\n const said = new Map(refused.map(({ type, message }) => [type, message]))\n const reasons = [\n ...failed.map(\n ({ types, error }) => `${types.join(', ')}: ${error instanceof Error ? error.message : String(error)}`\n ),\n ...unresolved.filter(type => !asked.has(type)).map(type => `${type}: ${said.get(type) ?? '해석되지 않았다'}`)\n ]\n console.warn(`[board] 그리지 못한 type — ${reasons.join(' | ')}`)\n }\n\n if (stillWanted && !stillWanted()) {\n return null\n }\n\n return create(options)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"resolved-scene.js","sourceRoot":"","sources":["../../src/resolved-scene.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAoCpE,IAAI,iBAAiB,GAA6B,IAAI,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,QAAkC;IAC7D,iBAAiB,GAAG,QAAQ,CAAA;AAC9B,CAAC;AAKD,IAAI,cAAc,GAA0B,IAAI,CAAA;AAEhD;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,QAA+B;IACvD,cAAc,GAAG,QAAQ,CAAA;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,OAA2B,EAC3B,WAAyB;;IAEzB,IAAI,iBAAiB,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS;QAAE,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,EAAE,EAAE,CAAA;IACxH,IAAI,cAAc,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,EAAE,EAAE,CAAA;IAC1G,MAAM,UAAU,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC3D,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;IACzC,kGAAkG;IAClG,MAAM,OAAO,GAAwC,MAAC,UAAkB,CAAC,OAAO,mCAAI,EAAE,CAAA;IAEtF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;QAC3D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;QACzE,MAAM,OAAO,GAAG;YACd,GAAG,MAAM,CAAC,GAAG,CACX,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACvG;YACD,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,WAAC,OAAA,GAAG,IAAI,KAAK,MAAA,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,mCAAI,UAAU,EAAE,CAAA,EAAA,CAAC;SACvG,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,yBAAyB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC9D,CAAC;IAED,IAAI,WAAW,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;QAClC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,MAAM,CAAC,OAAO,CAAC,CAAA;AACxB,CAAC","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { create, resolveUnknownTypes } from '@hatiolab/things-scene'\nimport type { SceneCreateOptions } from '@hatiolab/things-scene'\n\n/*\n * The one place this package turns a model into a scene.\n *\n * ── Why it is one place ─────────────────────────────────────────────────────\n * `create()` is synchronous and compiles what is registered at that moment, so the types a model\n * names and nobody has registered have to be fetched first (`figure-provider.ts` fetches them).\n * Written at each scene site, that \"first\" is six lines that drift apart, and the seventh site\n * forgets it. So every site in this package calls this function instead, and a test counts that\n * nobody else imports `create` (test/scene-create-single-door.test.ts).\n *\n * ── It costs nothing when there is nothing to resolve ───────────────────────\n * `resolveUnknownTypes` collects the model's unregistered types first and only wakes a resolver if\n * there are any. A board of plain scene components asks no server anything — every board-opening\n * screen goes through here, so that has to stay true.\n *\n * ── A scene opens even when the figures do not ──────────────────────────────\n * Resolution never throws: a resolver that rejects is reported in `failed`, and a type nobody\n * published stays in `unresolved`. Both draw as stand-ins and are saved back untouched (ADR-0063\n * 결정 1). They are not the same fact, so the warning says which happened to which type — silence\n * would leave \"the server said no\" looking exactly like \"there is no such figure\".\n */\n\n/**\n * Tells whether the caller still wants this scene after the await.\n *\n * The wait makes the caller re-entrant: an element can be detached, or handed a new model, while\n * the types are being fetched. Without this, the late scene overwrites the current one.\n */\nexport type StillWanted = () => boolean\n\n/** Answers the domain's item type table (ADR-0155) for a scene about to open. */\nexport type ItemTypesProvider = () => Promise<unknown>\n\nlet itemTypesProvider: ItemTypesProvider | null = null\n\n/**\n * An app that uses item types (ADR-0155) gives this package what answers its domain's table, once, from its bootstrap\n * (operato-board gives figure-library's `fetchDomainItemTypes`). Every scene this package opens is then given the table\n * as it opens. An app that gives none opens its scenes without one: their items keep the component type, as before.\n * Null takes it back.\n */\nexport function useItemTypes(provider: ItemTypesProvider | null): void {\n itemTypesProvider = provider\n}\n\n/** Answers the domain's themes -- its legends among them -- for a scene about to open: name → value, the active ones. */\nexport type ThemesProvider = () => Promise<Record<string, unknown>>\n\nlet themesProvider: ThemesProvider | null = null\n\n/**\n * An app whose boards show legends (ADR-0166 7) gives this package what answers its domain's active themes, once, from\n * its bootstrap. Every scene this package opens is then given them as its `style`, name → value, where a figure's table\n * finds the legend chosen for its role. An app that gives none opens its scenes without them: tables show by the\n * figures' own. Null takes it back.\n */\nexport function useThemes(provider: ThemesProvider | null): void {\n themesProvider = provider\n}\n\nexport async function createResolvedScene(\n options: SceneCreateOptions,\n stillWanted?: StillWanted\n): Promise<ReturnType<typeof create> | null> {\n if (itemTypesProvider && options.itemTypes === undefined) options = { ...options, itemTypes: await itemTypesProvider() }\n if (themesProvider && options.style === undefined) options = { ...options, style: await themesProvider() }\n const resolution = await resolveUnknownTypes(options.model)\n const { unresolved, failed } = resolution\n /* The reason a resolver gave for each type it refused (ADR-0114 A3); older scenes report none. */\n const refused: { type: string; message: string }[] = (resolution as any).refused ?? []\n\n if (failed.length > 0 || unresolved.length > 0) {\n const asked = new Set(failed.flatMap(({ types }) => types))\n const said = new Map(refused.map(({ type, message }) => [type, message]))\n const reasons = [\n ...failed.map(\n ({ types, error }) => `${types.join(', ')}: ${error instanceof Error ? error.message : String(error)}`\n ),\n ...unresolved.filter(type => !asked.has(type)).map(type => `${type}: ${said.get(type) ?? '해석되지 않았다'}`)\n ]\n console.warn(`[board] 그리지 못한 type — ${reasons.join(' | ')}`)\n }\n\n if (stillWanted && !stillWanted()) {\n return null\n }\n\n return create(options)\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expect, fixture, html } from '@open-wc/testing';
|
|
2
2
|
import { executeServerCommand } from '@web/test-runner-commands';
|
|
3
3
|
import { registerTypeResolver, resetFigures } from '@hatiolab/things-scene';
|
|
4
|
-
import { createResolvedScene, useItemTypes } from '../src/resolved-scene.js';
|
|
4
|
+
import { createResolvedScene, useItemTypes, useThemes } from '../src/resolved-scene.js';
|
|
5
5
|
import '../src/ox-board-preview.js';
|
|
6
6
|
/**
|
|
7
7
|
* The one door a model goes through to become a scene (ADR-0063 결정 2).
|
|
@@ -106,4 +106,32 @@ describe('아이템 타입 표를 쓰는 앱의 씬은 열 때 표를 받는다
|
|
|
106
106
|
scene === null || scene === void 0 ? void 0 : scene.dispose();
|
|
107
107
|
});
|
|
108
108
|
});
|
|
109
|
+
describe('범례를 쓰는 앱의 씬은 열 때 도메인의 테마를 받는다 (ADR-0166 7)', () => {
|
|
110
|
+
afterEach(() => useThemes(null));
|
|
111
|
+
it('앱이 준 공급자가 답한 테마를 씬의 루트가 style 로 갖는다. 열 때마다 묻는다', async () => {
|
|
112
|
+
let asked = 0;
|
|
113
|
+
useThemes(async () => {
|
|
114
|
+
asked++;
|
|
115
|
+
return { 'carrier-load': { FULL: '#3B6D11', default: {} } };
|
|
116
|
+
});
|
|
117
|
+
const first = await createResolvedScene({ model: KNOWN_MODEL });
|
|
118
|
+
const second = await createResolvedScene({ model: KNOWN_MODEL });
|
|
119
|
+
expect(first.rootContainer.style['carrier-load'].FULL).to.equal('#3B6D11');
|
|
120
|
+
expect(asked).to.equal(2);
|
|
121
|
+
first === null || first === void 0 ? void 0 : first.dispose();
|
|
122
|
+
second === null || second === void 0 ? void 0 : second.dispose();
|
|
123
|
+
});
|
|
124
|
+
it('씬을 여는 쪽이 style 을 주면 공급자를 묻지 않는다; 공급자가 없으면 style 이 없다', async () => {
|
|
125
|
+
let asked = 0;
|
|
126
|
+
useThemes(async () => (asked++, {}));
|
|
127
|
+
const given = await createResolvedScene({ model: KNOWN_MODEL, style: { plant: { RUN: '#22C55E' } } });
|
|
128
|
+
expect(asked).to.equal(0);
|
|
129
|
+
expect(given.rootContainer.style.plant.RUN).to.equal('#22C55E');
|
|
130
|
+
given === null || given === void 0 ? void 0 : given.dispose();
|
|
131
|
+
useThemes(null);
|
|
132
|
+
const bare = await createResolvedScene({ model: KNOWN_MODEL });
|
|
133
|
+
expect(bare.rootContainer.style).to.equal(undefined);
|
|
134
|
+
bare === null || bare === void 0 ? void 0 : bare.dispose();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
109
137
|
//# sourceMappingURL=resolved-scene.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolved-scene.test.js","sourceRoot":"","sources":["../../test/resolved-scene.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, html } from '@open-wc/testing'\nimport type { LitElement } from 'lit'\nimport { executeServerCommand } from '@web/test-runner-commands'\n\nimport { registerTypeResolver, resetFigures } from '@hatiolab/things-scene'\n\nimport { createResolvedScene, useItemTypes } from '../src/resolved-scene.js'\nimport '../src/ox-board-preview.js'\n\n/**\n * The one door a model goes through to become a scene (ADR-0063 결정 2).\n *\n * Three things are counted here, and each of them is something that goes wrong quietly otherwise:\n * a scene built somewhere else never resolves its types, a board of ordinary components pays for a\n * server round trip it does not need, and a scene that was waiting lands on a viewer that has\n * already moved on.\n */\n\nconst KNOWN_MODEL = {\n type: 'container',\n components: [{ type: 'rect', left: 0, top: 0, width: 100, height: 100 }]\n}\n\nconst modelWith = (types: string[]) => ({\n type: 'container',\n components: types.map((type, index) => ({ type, left: index * 10, top: 0, width: 100, height: 100 }))\n})\n\ndescribe('씬을 만드는 문은 하나다', () => {\n it('things-scene 의 create 를 읽는 파일은 resolved-scene.ts 하나뿐이다', async () => {\n /*\n * 세는 범위는 이 꾸러미와 `@operato/process` 다 — 문은 여기 있고 그 꾸러미가 둘째 소비자다.\n * 이 꾸러미만 보던 규칙은 옆에 씬 둘이 서 있는 동안 「문은 하나」라고 답하고 있었다.\n */\n const files = await executeServerCommand<unknown, string[]>('files-importing-scene-create')\n\n expect(files).to.deep.equal(['src/resolved-scene.ts'])\n })\n})\n\ndescribe('모르는 type 이 없으면 아무에게도 묻지 않는다', () => {\n let asked: string[][]\n let takeBack: () => void\n\n beforeEach(() => {\n asked = []\n takeBack = registerTypeResolver(async types => {\n asked.push([...types])\n })\n })\n\n afterEach(() => {\n takeBack()\n resetFigures()\n })\n\n it('씬의 기본 type 만 있는 보드는 공급자를 부르지 않는다', async () => {\n const scene = await createResolvedScene({ model: KNOWN_MODEL })\n\n expect(asked).to.deep.equal([])\n expect(scene).to.not.equal(null)\n\n scene?.release?.()\n })\n\n it('모르는 type 이 있을 때만 부른다', async () => {\n const scene = await createResolvedScene({ model: modelWith(['rect', 'EQ_ASKED_ABOUT']) })\n\n expect(asked).to.deep.equal([['EQ_ASKED_ABOUT']])\n\n scene?.release?.()\n })\n})\n\ndescribe('기다리는 동안 화면이 바뀌면 늦게 온 씬은 들어서지 않는다', () => {\n let takeBack: () => void\n\n afterEach(() => {\n takeBack?.()\n resetFigures()\n })\n\n it('앞의 모델을 풀고 돌아왔을 때 미리보기가 다른 모델을 들고 있으면 그 씬은 버린다', async () => {\n /* The first model's type resolves slowly; the second one has nothing to resolve. */\n let releaseFirst: () => void = () => {}\n const firstResolved = new Promise<void>(resolve => {\n releaseFirst = resolve\n })\n\n takeBack = registerTypeResolver(async types => {\n if (types.includes('EQ_SLOW')) {\n await firstResolved\n }\n })\n\n const element = (await fixture(html`<ox-board-preview></ox-board-preview>`)) as LitElement & {\n boardModel: unknown\n _scene: { root: { components: unknown[] } } | null\n }\n\n element.boardModel = modelWith(['EQ_SLOW'])\n await element.updateComplete\n\n /* The second model arrives while the first one is still waiting on its type. */\n element.boardModel = modelWith(['rect', 'rect'])\n await element.updateComplete\n\n releaseFirst()\n await new Promise(resolve => setTimeout(resolve, 0))\n\n expect(element._scene).to.not.equal(null)\n expect(element._scene!.root.components.length).to.equal(2)\n })\n})\n\ndescribe('아이템 타입 표를 쓰는 앱의 씬은 열 때 표를 받는다 (ADR-0155)', () => {\n afterEach(() => useItemTypes(null))\n\n it('앱이 준 공급자가 답한 표를 씬의 루트가 갖는다. 열 때마다 묻는다', async () => {\n let asked = 0\n useItemTypes(async () => {\n asked++\n return { types: [{ code: 'REEL', size: { width: 760, length: 840, height: 840 } }] }\n })\n const first = await createResolvedScene({ model: KNOWN_MODEL })\n const second = await createResolvedScene({ model: KNOWN_MODEL })\n expect((first as any).rootContainer.itemTypes.types.has('REEL')).to.equal(true)\n expect(asked).to.equal(2)\n first?.dispose()\n second?.dispose()\n })\n\n it('공급자를 주지 않은 앱의 씬은 표가 없다', async () => {\n const scene = await createResolvedScene({ model: KNOWN_MODEL })\n expect((scene as any).rootContainer.itemTypes).to.equal(undefined)\n scene?.dispose()\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"resolved-scene.test.js","sourceRoot":"","sources":["../../test/resolved-scene.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture, html } from '@open-wc/testing'\nimport type { LitElement } from 'lit'\nimport { executeServerCommand } from '@web/test-runner-commands'\n\nimport { registerTypeResolver, resetFigures } from '@hatiolab/things-scene'\n\nimport { createResolvedScene, useItemTypes, useThemes } from '../src/resolved-scene.js'\nimport '../src/ox-board-preview.js'\n\n/**\n * The one door a model goes through to become a scene (ADR-0063 결정 2).\n *\n * Three things are counted here, and each of them is something that goes wrong quietly otherwise:\n * a scene built somewhere else never resolves its types, a board of ordinary components pays for a\n * server round trip it does not need, and a scene that was waiting lands on a viewer that has\n * already moved on.\n */\n\nconst KNOWN_MODEL = {\n type: 'container',\n components: [{ type: 'rect', left: 0, top: 0, width: 100, height: 100 }]\n}\n\nconst modelWith = (types: string[]) => ({\n type: 'container',\n components: types.map((type, index) => ({ type, left: index * 10, top: 0, width: 100, height: 100 }))\n})\n\ndescribe('씬을 만드는 문은 하나다', () => {\n it('things-scene 의 create 를 읽는 파일은 resolved-scene.ts 하나뿐이다', async () => {\n /*\n * 세는 범위는 이 꾸러미와 `@operato/process` 다 — 문은 여기 있고 그 꾸러미가 둘째 소비자다.\n * 이 꾸러미만 보던 규칙은 옆에 씬 둘이 서 있는 동안 「문은 하나」라고 답하고 있었다.\n */\n const files = await executeServerCommand<unknown, string[]>('files-importing-scene-create')\n\n expect(files).to.deep.equal(['src/resolved-scene.ts'])\n })\n})\n\ndescribe('모르는 type 이 없으면 아무에게도 묻지 않는다', () => {\n let asked: string[][]\n let takeBack: () => void\n\n beforeEach(() => {\n asked = []\n takeBack = registerTypeResolver(async types => {\n asked.push([...types])\n })\n })\n\n afterEach(() => {\n takeBack()\n resetFigures()\n })\n\n it('씬의 기본 type 만 있는 보드는 공급자를 부르지 않는다', async () => {\n const scene = await createResolvedScene({ model: KNOWN_MODEL })\n\n expect(asked).to.deep.equal([])\n expect(scene).to.not.equal(null)\n\n scene?.release?.()\n })\n\n it('모르는 type 이 있을 때만 부른다', async () => {\n const scene = await createResolvedScene({ model: modelWith(['rect', 'EQ_ASKED_ABOUT']) })\n\n expect(asked).to.deep.equal([['EQ_ASKED_ABOUT']])\n\n scene?.release?.()\n })\n})\n\ndescribe('기다리는 동안 화면이 바뀌면 늦게 온 씬은 들어서지 않는다', () => {\n let takeBack: () => void\n\n afterEach(() => {\n takeBack?.()\n resetFigures()\n })\n\n it('앞의 모델을 풀고 돌아왔을 때 미리보기가 다른 모델을 들고 있으면 그 씬은 버린다', async () => {\n /* The first model's type resolves slowly; the second one has nothing to resolve. */\n let releaseFirst: () => void = () => {}\n const firstResolved = new Promise<void>(resolve => {\n releaseFirst = resolve\n })\n\n takeBack = registerTypeResolver(async types => {\n if (types.includes('EQ_SLOW')) {\n await firstResolved\n }\n })\n\n const element = (await fixture(html`<ox-board-preview></ox-board-preview>`)) as LitElement & {\n boardModel: unknown\n _scene: { root: { components: unknown[] } } | null\n }\n\n element.boardModel = modelWith(['EQ_SLOW'])\n await element.updateComplete\n\n /* The second model arrives while the first one is still waiting on its type. */\n element.boardModel = modelWith(['rect', 'rect'])\n await element.updateComplete\n\n releaseFirst()\n await new Promise(resolve => setTimeout(resolve, 0))\n\n expect(element._scene).to.not.equal(null)\n expect(element._scene!.root.components.length).to.equal(2)\n })\n})\n\ndescribe('아이템 타입 표를 쓰는 앱의 씬은 열 때 표를 받는다 (ADR-0155)', () => {\n afterEach(() => useItemTypes(null))\n\n it('앱이 준 공급자가 답한 표를 씬의 루트가 갖는다. 열 때마다 묻는다', async () => {\n let asked = 0\n useItemTypes(async () => {\n asked++\n return { types: [{ code: 'REEL', size: { width: 760, length: 840, height: 840 } }] }\n })\n const first = await createResolvedScene({ model: KNOWN_MODEL })\n const second = await createResolvedScene({ model: KNOWN_MODEL })\n expect((first as any).rootContainer.itemTypes.types.has('REEL')).to.equal(true)\n expect(asked).to.equal(2)\n first?.dispose()\n second?.dispose()\n })\n\n it('공급자를 주지 않은 앱의 씬은 표가 없다', async () => {\n const scene = await createResolvedScene({ model: KNOWN_MODEL })\n expect((scene as any).rootContainer.itemTypes).to.equal(undefined)\n scene?.dispose()\n })\n})\n\ndescribe('범례를 쓰는 앱의 씬은 열 때 도메인의 테마를 받는다 (ADR-0166 7)', () => {\n afterEach(() => useThemes(null))\n\n it('앱이 준 공급자가 답한 테마를 씬의 루트가 style 로 갖는다. 열 때마다 묻는다', async () => {\n let asked = 0\n useThemes(async () => {\n asked++\n return { 'carrier-load': { FULL: '#3B6D11', default: {} } }\n })\n const first = await createResolvedScene({ model: KNOWN_MODEL })\n const second = await createResolvedScene({ model: KNOWN_MODEL })\n expect((first as any).rootContainer.style['carrier-load'].FULL).to.equal('#3B6D11')\n expect(asked).to.equal(2)\n first?.dispose()\n second?.dispose()\n })\n\n it('씬을 여는 쪽이 style 을 주면 공급자를 묻지 않는다; 공급자가 없으면 style 이 없다', async () => {\n let asked = 0\n useThemes(async () => (asked++, {}))\n const given = await createResolvedScene({ model: KNOWN_MODEL, style: { plant: { RUN: '#22C55E' } } })\n expect(asked).to.equal(0)\n expect((given as any).rootContainer.style.plant.RUN).to.equal('#22C55E')\n given?.dispose()\n useThemes(null)\n const bare = await createResolvedScene({ model: KNOWN_MODEL })\n expect((bare as any).rootContainer.style).to.equal(undefined)\n bare?.dispose()\n })\n})\n\n"]}
|