@operato/board 10.28.3 → 10.29.1
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 +30 -0
- package/coverage/lcov-report/index.html +57 -27
- package/coverage/lcov.info +950 -233
- package/dist/src/figure-provider.d.ts +3 -4
- package/dist/src/figure-provider.js +3 -3
- package/dist/src/figure-provider.js.map +1 -1
- package/dist/test/figure-provider.test.js +36 -36
- package/dist/test/figure-provider.test.js.map +1 -1
- package/dist/test/resolved-scene.test.js +3 -3
- package/dist/test/resolved-scene.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -16
- package/test/figure-provider.test.ts +36 -36
- package/test/resolved-scene.test.ts +3 -3
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* What the server hands over for one released type: the figure asset
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* What the server hands over for one released type: the figure asset. The board does not read the asset; the scene's
|
|
3
|
+
* own registration compiles it with the kernel (ADR-0087 decision 5), which refuses an asset of any other format by
|
|
4
|
+
* its version. A payload without an asset is not a figure this board can draw.
|
|
5
5
|
*/
|
|
6
6
|
export type FigurePayload = {
|
|
7
|
-
format: 'v3';
|
|
8
7
|
type: string;
|
|
9
8
|
asset: any;
|
|
10
9
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
4
|
import gql from 'graphql-tag';
|
|
5
|
-
import { Component,
|
|
5
|
+
import { Component, registerFigure, registerTypeResolver } from '@hatiolab/things-scene';
|
|
6
6
|
import { client, gqlContext } from '@operato/graphql';
|
|
7
7
|
/*
|
|
8
8
|
* Where a board gets the figures somebody authored.
|
|
@@ -31,9 +31,9 @@ const FIGURE_TYPE = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
|
|
|
31
31
|
/** Registers one released figure with the scene. Anything but a figure asset is refused by name. */
|
|
32
32
|
export function registerFigurePayload(type, payload) {
|
|
33
33
|
var _a;
|
|
34
|
-
if ((payload === null || payload === void 0 ? void 0 : payload.
|
|
34
|
+
if (!(payload === null || payload === void 0 ? void 0 : payload.asset) || typeof payload.asset !== 'object')
|
|
35
35
|
throw new Error(`not a figure asset: ${type}`);
|
|
36
|
-
|
|
36
|
+
registerFigure((_a = payload.type) !== null && _a !== void 0 ? _a : type, payload.asset);
|
|
37
37
|
}
|
|
38
38
|
const FETCH_FIGURE_BLUEPRINT = gql `
|
|
39
39
|
query FetchFigureBlueprint($type: String!) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-provider.js","sourceRoot":"","sources":["../../src/figure-provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,OAAO,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"figure-provider.js","sourceRoot":"","sources":["../../src/figure-provider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AACxF,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAErD;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,kEAAkE;AAClE,MAAM,WAAW,GAAG,+BAA+B,CAAA;AAYnD,oGAAoG;AACpG,MAAM,UAAU,qBAAqB,CAAC,IAAY,EAAE,OAAsB;;IACxE,IAAI,CAAC,CAAC,OAA+B,aAA/B,OAAO,uBAAP,OAAO,CAA0B,KAAK,CAAA,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAA;IACjI,cAAc,CAAC,MAAA,OAAO,CAAC,IAAI,mCAAI,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,CAAA;AACrD,CAAC;AAED,MAAM,sBAAsB,GAAG,GAAG,CAAA;;;;CAIjC,CAAA;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAmB,KAAK,EAAE,IAAY,EAAE,EAAE;;IACzE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC;QAClC,KAAK,EAAE,sBAAsB;QAC7B,SAAS,EAAE,EAAE,IAAI,EAAE;QACnB,OAAO,EAAE,UAAU,EAAE;KACtB,CAAC,CAAA;IAEF;;;;MAIE;IACF,MAAM,MAAM,GAAI,QAAyD,CAAC,MAAM,CAAA;IAChF,IAAI,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,WAAC,OAAA,MAAA,CAAC,aAAD,CAAC,uBAAD,CAAC,CAAE,OAAO,mCAAI,MAAM,CAAC,CAAC,CAAC,CAAA,EAAA,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACtE,CAAC;IAED,OAAO,MAAA,MAAA,QAAQ,CAAC,IAAI,0CAAE,eAAe,mCAAI,IAAI,CAAA;AAC/C,CAAC,CAAA;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAwB,oBAAoB;IAC/E,OAAO,KAAK,UAAU,kBAAkB,CAAC,KAAwB;QAC/D,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA;QACxF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAM;QACR,CAAC;QAED,MAAM,QAAQ,GAAuC,EAAE,CAAA;QAEvD,MAAM,OAAO,CAAC,GAAG,CACf,MAAM,CAAC,GAAG,CAAC,KAAK,EAAC,IAAI,EAAC,EAAE;YACtB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAA;gBACjC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,sDAAsD;oBACtD,OAAM;gBACR,CAAC;gBAED,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YACtC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YAChC,CAAC;QACH,CAAC,CAAC,CACH,CAAA;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB;;;cAGE;YACF,MAAM,IAAI,KAAK,CACb,uBAAuB,QAAQ;iBAC5B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;iBAClG,IAAI,CAAC,IAAI,CAAC,EAAE,CAChB,CAAA;QACH,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAwB,oBAAoB;IAChF,OAAO,oBAAoB,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAA;AAC1D,CAAC","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport gql from 'graphql-tag'\n\nimport { Component, registerFigure, registerTypeResolver } from '@hatiolab/things-scene'\nimport { client, gqlContext } from '@operato/graphql'\n\n/*\n * Where a board gets the figures somebody authored.\n *\n * ── Why the seat is filled here ─────────────────────────────────────────────\n * things-scene keeps the seat (`registerTypeResolver`) and knows nothing about figures, GraphQL or\n * who published what. The board package is where a saved model already gets its values from the\n * server — `board-provider.ts` reads a board by id the same way — so this is where the types a\n * model names, and nobody has registered, get fetched. Putting it in the authoring package would\n * make every consumer drag the modeller along, and putting it in each app would make every app\n * build the same thing (ADR-0063 결정 2 · ADR-0045).\n *\n * ── What it asks for, and what it does not ──────────────────────────────────\n * Uppercase names are the figure namespace, so those are the only ones asked about: a model that\n * names `rect` or a mistyped `Conveyor` never reaches the server. A type that is already\n * registered is left alone — a figure never replaces a component that is already drawing.\n *\n * ── An answer of \"nobody published this\" is not a failure ───────────────────\n * `figureBlueprint` returns null for a type that has no released figure, and that type stays\n * unregistered on purpose: the scene draws it as a stand-in and saves it back untouched\n * (ADR-0063 결정 1). Being unable to ask at all is a different fact, so a transport or server\n * error rejects — `resolveUnknownTypes` reports those in `failed` and the board still opens.\n */\n\n/** The figure namespace: `EQ_MIXER`, `CONVEYOR`, `VEH_AGV_01`. */\nconst FIGURE_TYPE = /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/\n\n/**\n * What the server hands over for one released type: the figure asset. The board does not read the asset; the scene's\n * own registration compiles it with the kernel (ADR-0087 decision 5), which refuses an asset of any other format by\n * its version. A payload without an asset is not a figure this board can draw.\n */\nexport type FigurePayload = { type: string; asset: any }\n\n/** Asks for one type's payload. Null when no released figure carries that name. */\nexport type BlueprintFetch = (type: string) => Promise<FigurePayload | null>\n\n/** Registers one released figure with the scene. Anything but a figure asset is refused by name. */\nexport function registerFigurePayload(type: string, payload: FigurePayload): void {\n if (!(payload as { asset?: unknown })?.asset || typeof payload.asset !== 'object') throw new Error(`not a figure asset: ${type}`)\n registerFigure(payload.type ?? type, payload.asset)\n}\n\nconst FETCH_FIGURE_BLUEPRINT = gql`\n query FetchFigureBlueprint($type: String!) {\n figureBlueprint(type: $type)\n }\n`\n\nexport const fetchFigureBlueprint: BlueprintFetch = async (type: string) => {\n const response = await client.query({\n query: FETCH_FIGURE_BLUEPRINT,\n variables: { type },\n context: gqlContext()\n })\n\n /*\n The client runs with errorPolicy 'all', so a rejected query comes back as a resolved response\n carrying `errors` and a null field. Without this the caller cannot tell \"no such figure\" from\n \"the door said no\".\n */\n const errors = (response as { errors?: readonly { message?: string }[] }).errors\n if (errors?.length) {\n throw new Error(errors.map(e => e?.message ?? String(e)).join('\\n'))\n }\n\n return response.data?.figureBlueprint ?? null\n}\n\n/**\n * Builds the resolver that fills things-scene's seat.\n *\n * `fetch` is a seam for tests — the default one talks to the server.\n */\nexport function createFigureResolver(fetch: BlueprintFetch = fetchFigureBlueprint) {\n return async function resolveFigureTypes(types: readonly string[]): Promise<void> {\n const asking = types.filter(type => FIGURE_TYPE.test(type) && !Component.register(type))\n if (asking.length === 0) {\n return\n }\n\n const failures: { type: string; error: unknown }[] = []\n\n await Promise.all(\n asking.map(async type => {\n try {\n const payload = await fetch(type)\n if (!payload) {\n /* Nobody published this type. It stays a stand-in. */\n return\n }\n\n registerFigurePayload(type, payload)\n } catch (error) {\n failures.push({ type, error })\n }\n })\n )\n\n if (failures.length > 0) {\n /*\n What did register stays registered — the seat reads the registry back, not what this says.\n The throw is how \"could not ask\" reaches `TypeResolution.failed`.\n */\n throw new Error(\n `Figure 를 가져오지 못했다:\\n${failures\n .map(({ type, error }) => ` - ${type}: ${error instanceof Error ? error.message : String(error)}`)\n .join('\\n')}`\n )\n }\n }\n}\n\n/**\n * Takes the seat. The package entry (`index.ts`) calls this, so an app that has `@operato/board`\n * gets published figures on its boards without registering anything itself. Returns the function\n * that takes the seat back.\n */\nexport function installFigureResolver(fetch: BlueprintFetch = fetchFigureBlueprint): () => void {\n return registerTypeResolver(createFigureResolver(fetch))\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expect } from '@open-wc/testing';
|
|
2
|
-
import { Component,
|
|
2
|
+
import { Component, hasFigure, registerTypeResolver, resetFigures, resolveUnknownTypes } from '@hatiolab/things-scene';
|
|
3
3
|
import { createFigureResolver } from '../src/figure-provider.js';
|
|
4
4
|
/**
|
|
5
5
|
* The path a published figure takes to a board (ADR-0063 결정 2).
|
|
@@ -12,12 +12,12 @@ import { createFigureResolver } from '../src/figure-provider.js';
|
|
|
12
12
|
* to the scene's own registration, and a fixture that drifts from the format should fail loudly here rather than
|
|
13
13
|
* draw nothing at runtime.
|
|
14
14
|
*/
|
|
15
|
-
/** What the door hands over: a figure asset
|
|
16
|
-
const
|
|
17
|
-
version: 'figure-
|
|
15
|
+
/** What the door hands over: a figure asset. One box standing on the floor, its room declared. */
|
|
16
|
+
const figureAssetOf = (type) => ({
|
|
17
|
+
version: 'figure-asset-1',
|
|
18
18
|
name: type,
|
|
19
19
|
document: {
|
|
20
|
-
version: 'figure-
|
|
20
|
+
version: 'figure-prototype-1',
|
|
21
21
|
model: {
|
|
22
22
|
version: 'r3-spatial-1',
|
|
23
23
|
inputs: [],
|
|
@@ -51,7 +51,7 @@ const v3AssetOf = (type) => ({
|
|
|
51
51
|
placement: 'floor'
|
|
52
52
|
}
|
|
53
53
|
});
|
|
54
|
-
const
|
|
54
|
+
const figurePayloadOf = (type) => ({ type, asset: figureAssetOf(type) });
|
|
55
55
|
/** Records what was asked for, and answers from a table. */
|
|
56
56
|
function fetcherOf(published, failing = []) {
|
|
57
57
|
const asked = [];
|
|
@@ -69,38 +69,38 @@ function fetcherOf(published, failing = []) {
|
|
|
69
69
|
}
|
|
70
70
|
describe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () => {
|
|
71
71
|
afterEach(() => {
|
|
72
|
-
|
|
72
|
+
resetFigures();
|
|
73
73
|
});
|
|
74
74
|
it('대문자 이름만 서버에 묻는다 — 씬의 기본 type 과 오타는 문을 지나지 않는다', async () => {
|
|
75
|
-
const { asked, fetch } = fetcherOf({ EQ_MIXER:
|
|
75
|
+
const { asked, fetch } = fetcherOf({ EQ_MIXER: figurePayloadOf('EQ_MIXER') });
|
|
76
76
|
await createFigureResolver(fetch)(['EQ_MIXER', 'rect', 'Conveyor', 'text', 'VEH_AGV_01']);
|
|
77
77
|
expect(asked).to.deep.equal(['EQ_MIXER', 'VEH_AGV_01']);
|
|
78
78
|
});
|
|
79
79
|
it('이미 등록된 type 은 묻지 않는다 — 그리고 있는 컴포넌트를 figure 가 덮지 않는다', async () => {
|
|
80
|
-
const { asked, fetch } = fetcherOf({ EQ_TAKEN:
|
|
80
|
+
const { asked, fetch } = fetcherOf({ EQ_TAKEN: figurePayloadOf('EQ_TAKEN') });
|
|
81
81
|
/* Somebody else already draws this name — a plugin, an app's own component. */
|
|
82
82
|
Component.register('EQ_TAKEN', class Taken extends Component {
|
|
83
83
|
});
|
|
84
84
|
await createFigureResolver(fetch)(['EQ_TAKEN']);
|
|
85
85
|
expect(asked).to.deep.equal([]);
|
|
86
|
-
expect(
|
|
86
|
+
expect(hasFigure('EQ_TAKEN')).to.equal(false);
|
|
87
87
|
});
|
|
88
88
|
it('받은 자산을 등록한다 — 도면은 type 만 적으면 된다', async () => {
|
|
89
|
-
const { fetch } = fetcherOf({ EQ_REGISTERED:
|
|
89
|
+
const { fetch } = fetcherOf({ EQ_REGISTERED: figurePayloadOf('EQ_REGISTERED') });
|
|
90
90
|
await createFigureResolver(fetch)(['EQ_REGISTERED']);
|
|
91
|
-
expect(
|
|
91
|
+
expect(hasFigure('EQ_REGISTERED')).to.equal(true);
|
|
92
92
|
/* The component type is registered with it — the model writes `type` and nothing else. */
|
|
93
93
|
expect(Component.register('EQ_REGISTERED')).to.not.equal(undefined);
|
|
94
94
|
});
|
|
95
95
|
it('자산은 씬의 문으로 등록한다 — 보드는 그것을 읽지 않고 씬에 넘긴다', async () => {
|
|
96
|
-
const { fetch } = fetcherOf({
|
|
97
|
-
await createFigureResolver(fetch)(['
|
|
98
|
-
expect(
|
|
96
|
+
const { fetch } = fetcherOf({ EQ: figurePayloadOf('EQ') });
|
|
97
|
+
await createFigureResolver(fetch)(['EQ']);
|
|
98
|
+
expect(hasFigure('EQ')).to.equal(true);
|
|
99
99
|
/* 도면은 type 하나만 적으면 그려진다. */
|
|
100
|
-
expect(Component.register('
|
|
100
|
+
expect(Component.register('EQ')).to.not.equal(undefined);
|
|
101
101
|
});
|
|
102
|
-
it('자산이
|
|
103
|
-
const { fetch } = fetcherOf({ EQ_NEW:
|
|
102
|
+
it('자산이 없는 답은 그 type 만 실패로 남는다 — 옛 청사진을 그리지 않는다', async () => {
|
|
103
|
+
const { fetch } = fetcherOf({ EQ_NEW: figurePayloadOf('EQ_NEW'), EQ_OLD: { version: 1, type: 'EQ_OLD', groups: [] } });
|
|
104
104
|
let message = '';
|
|
105
105
|
try {
|
|
106
106
|
await createFigureResolver(fetch)(['EQ_NEW', 'EQ_OLD']);
|
|
@@ -109,23 +109,23 @@ describe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () =>
|
|
|
109
109
|
message = error instanceof Error ? error.message : String(error);
|
|
110
110
|
}
|
|
111
111
|
expect(message).to.contain('not a figure asset: EQ_OLD');
|
|
112
|
-
expect(
|
|
113
|
-
expect(
|
|
112
|
+
expect(hasFigure('EQ_NEW')).to.equal(true);
|
|
113
|
+
expect(hasFigure('EQ_OLD')).to.equal(false);
|
|
114
114
|
});
|
|
115
|
-
it('읽을 수 없는
|
|
116
|
-
const broken =
|
|
115
|
+
it('읽을 수 없는 자산은 그 type 만 실패로 남는다', async () => {
|
|
116
|
+
const broken = figurePayloadOf('EQ_ASSET_BROKEN');
|
|
117
117
|
broken.asset.appearance = [];
|
|
118
|
-
const { fetch } = fetcherOf({
|
|
118
|
+
const { fetch } = fetcherOf({ EQ_BESIDE: figurePayloadOf('EQ_BESIDE'), EQ_ASSET_BROKEN: broken });
|
|
119
119
|
let message = '';
|
|
120
120
|
try {
|
|
121
|
-
await createFigureResolver(fetch)(['
|
|
121
|
+
await createFigureResolver(fetch)(['EQ_BESIDE', 'EQ_ASSET_BROKEN']);
|
|
122
122
|
}
|
|
123
123
|
catch (error) {
|
|
124
124
|
message = error instanceof Error ? error.message : String(error);
|
|
125
125
|
}
|
|
126
|
-
expect(message).to.contain('
|
|
127
|
-
expect(
|
|
128
|
-
expect(
|
|
126
|
+
expect(message).to.contain('EQ_ASSET_BROKEN');
|
|
127
|
+
expect(hasFigure('EQ_BESIDE')).to.equal(true);
|
|
128
|
+
expect(hasFigure('EQ_ASSET_BROKEN')).to.equal(false);
|
|
129
129
|
});
|
|
130
130
|
it('발행된 것이 없으면 조용히 자리표시로 남는다 — 거절이 아니다', async () => {
|
|
131
131
|
const { fetch } = fetcherOf({});
|
|
@@ -137,10 +137,10 @@ describe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () =>
|
|
|
137
137
|
rejected = true;
|
|
138
138
|
}
|
|
139
139
|
expect(rejected).to.equal(false);
|
|
140
|
-
expect(
|
|
140
|
+
expect(hasFigure('EQ_NOT_PUBLISHED')).to.equal(false);
|
|
141
141
|
});
|
|
142
142
|
it('물을 수 없으면 거절한다. 그때도 답을 받은 것은 등록된다', async () => {
|
|
143
|
-
const { fetch } = fetcherOf({ EQ_BESIDE_BROKEN:
|
|
143
|
+
const { fetch } = fetcherOf({ EQ_BESIDE_BROKEN: figurePayloadOf('EQ_BESIDE_BROKEN') }, ['EQ_BROKEN']);
|
|
144
144
|
let message = '';
|
|
145
145
|
try {
|
|
146
146
|
await createFigureResolver(fetch)(['EQ_BESIDE_BROKEN', 'EQ_BROKEN']);
|
|
@@ -150,12 +150,12 @@ describe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () =>
|
|
|
150
150
|
}
|
|
151
151
|
expect(message).to.contain('EQ_BROKEN');
|
|
152
152
|
expect(message).to.not.contain('EQ_BESIDE_BROKEN');
|
|
153
|
-
expect(
|
|
153
|
+
expect(hasFigure('EQ_BESIDE_BROKEN')).to.equal(true);
|
|
154
154
|
});
|
|
155
155
|
it('읽을 수 없는 자산은 그 type 만 실패로 남는다 — 다른 type 을 막지 않는다', async () => {
|
|
156
156
|
const { fetch } = fetcherOf({
|
|
157
|
-
EQ_BESIDE_MALFORMED:
|
|
158
|
-
EQ_MALFORMED: {
|
|
157
|
+
EQ_BESIDE_MALFORMED: figurePayloadOf('EQ_BESIDE_MALFORMED'),
|
|
158
|
+
EQ_MALFORMED: { type: 'EQ_MALFORMED', asset: { version: 'figure-asset-1' } }
|
|
159
159
|
});
|
|
160
160
|
let message = '';
|
|
161
161
|
try {
|
|
@@ -165,11 +165,11 @@ describe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () =>
|
|
|
165
165
|
message = error instanceof Error ? error.message : String(error);
|
|
166
166
|
}
|
|
167
167
|
expect(message).to.contain('EQ_MALFORMED');
|
|
168
|
-
expect(
|
|
169
|
-
expect(
|
|
168
|
+
expect(hasFigure('EQ_BESIDE_MALFORMED')).to.equal(true);
|
|
169
|
+
expect(hasFigure('EQ_MALFORMED')).to.equal(false);
|
|
170
170
|
});
|
|
171
171
|
it('씬의 자리에 앉아 동작한다 — 모델의 모르는 type 이 해석 뒤에 남지 않는다', async () => {
|
|
172
|
-
const { fetch } = fetcherOf({ EQ_ON_A_BOARD:
|
|
172
|
+
const { fetch } = fetcherOf({ EQ_ON_A_BOARD: figurePayloadOf('EQ_ON_A_BOARD') });
|
|
173
173
|
const takeBack = registerTypeResolver(createFigureResolver(fetch));
|
|
174
174
|
try {
|
|
175
175
|
const model = {
|
|
@@ -182,7 +182,7 @@ describe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () =>
|
|
|
182
182
|
const resolution = await resolveUnknownTypes(model);
|
|
183
183
|
expect(resolution.unresolved).to.deep.equal(['EQ_NEVER_PUBLISHED']);
|
|
184
184
|
expect(resolution.failed).to.deep.equal([]);
|
|
185
|
-
expect(
|
|
185
|
+
expect(hasFigure('EQ_ON_A_BOARD')).to.equal(true);
|
|
186
186
|
}
|
|
187
187
|
finally {
|
|
188
188
|
takeBack();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-provider.test.js","sourceRoot":"","sources":["../../test/figure-provider.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAEzC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,oBAAoB,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAE1H,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAEhE;;;;;;;;;;GAUG;AAEH,uHAAuH;AACvH,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC;IACnC,OAAO,EAAE,mBAAmB;IAC5B,IAAI,EAAE,IAAI;IACV,QAAQ,EAAE;QACR,OAAO,EAAE,uBAAuB;QAChC,KAAK,EAAE;YACL,OAAO,EAAE,cAAc;YACvB,MAAM,EAAE,EAAE;YACV,SAAS,EAAE;gBACT,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE;gBACnC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;gBACrC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;gBAC3C,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE;gBACpC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE;aACpC;YACD,KAAK,EAAE;gBACL,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE;gBAC7H;oBACE,EAAE,EAAE,WAAW;oBACf,EAAE,EAAE,SAAS;oBACb,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;oBAChD,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC3B,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,OAAO,EAAE;iBAC5C;gBACD,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE;aAC9F;SACF;QACD,YAAY,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;KAChF;IACD,YAAY,EAAE,EAAE;IAChB,aAAa,EAAE,EAAE;IACjB,OAAO,EAAE,EAAE,iBAAiB,EAAE,SAAS,EAAE;IACzC,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,CAAC;IACxE,SAAS,EAAE;QACT,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;QACpH,SAAS,EAAE,OAAO;KACnB;CACF,CAAC,CAAA;AAEF,MAAM,WAAW,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAa,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAE/F,4DAA4D;AAC5D,SAAS,SAAS,CAAC,SAAkC,EAAE,UAAoB,EAAE;IAC3E,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,OAAO;QACL,KAAK;QACL,KAAK,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE;;YAC5B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAChB,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,GAAG,CAAC,CAAA;YACnD,CAAC;YACD,OAAO,CAAC,MAAA,SAAS,CAAC,IAAI,CAAC,mCAAI,IAAI,CAAU,CAAA;QAC3C,CAAC;KACF,CAAA;AACH,CAAC;AAED,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,SAAS,CAAC,GAAG,EAAE;QACb,cAAc,EAAE,CAAA;IAClB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAEzE,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;QAEzF,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAEzE,+EAA+E;QAC/E,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,KAAM,SAAQ,SAAS;SAAY,CAAC,CAAA;QAEzE,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;QAE/C,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC/B,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACjD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,aAAa,EAAE,WAAW,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;QAE5E,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAA;QAEpD,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACnD,0FAA0F;QAC1F,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAE5D,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;QAE5C,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3C,4BAA4B;QAC5B,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IAC7D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QAElH,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAA;QACzD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAA;QACxD,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC5C,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,MAAM,GAAG,WAAW,CAAC,cAAc,CAAC,CAAA;QAC1C,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAA;QAC5B,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,YAAY,EAAE,WAAW,CAAC,cAAc,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAA;QAEhG,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC,CAAA;QACrE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;QAC1C,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAClD,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAAA;QAE/B,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAA;QACzD,CAAC;QAAC,WAAM,CAAC;YACP,QAAQ,GAAG,IAAI,CAAA;QACjB,CAAC;QAED,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAChC,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,gBAAgB,EAAE,WAAW,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;QAEjG,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAA;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QACvC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;QAClD,MAAM,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;YAC1B,mBAAmB,EAAE,WAAW,CAAC,qBAAqB,CAAC;YACvD,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE;SAC9F,CAAC,CAAA;QAEF,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC,CAAA;QAC5E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;QAC1C,MAAM,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACzD,MAAM,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,aAAa,EAAE,WAAW,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;QAC5E,MAAM,QAAQ,GAAG,oBAAoB,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAA;QAElE,IAAI,CAAC;YACH,MAAM,KAAK,GAAG;gBACZ,IAAI,EAAE,WAAW;gBACjB,UAAU,EAAE;oBACV,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;oBACnE,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;iBACzE;aACF,CAAA;YAED,MAAM,UAAU,GAAG,MAAM,mBAAmB,CAAC,KAAK,CAAC,CAAA;YAEnD,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;YACnE,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YAC3C,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACrD,CAAC;gBAAS,CAAC;YACT,QAAQ,EAAE,CAAA;QACZ,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { expect } from '@open-wc/testing'\n\nimport { Component, hasFigureV3, registerTypeResolver, resetFiguresV3, resolveUnknownTypes } from '@hatiolab/things-scene'\n\nimport { createFigureResolver } from '../src/figure-provider.js'\n\n/**\n * The path a published figure takes to a board (ADR-0063 결정 2).\n *\n * things-scene holds the seat and knows nothing about figures; this package fills it. What is\n * checked here is the part that belongs to the board: which names are asked about, what happens to\n * the answer, and how \"nobody published this\" stays apart from \"could not ask\".\n *\n * The payload below is written out rather than built with figure-model: this package does not read it, it passes it\n * to the scene's own registration, and a fixture that drifts from the format should fail loudly here rather than\n * draw nothing at runtime.\n */\n\n/** What the door hands over: a figure asset under a `format` tag. One box standing on the floor, its room declared. */\nconst v3AssetOf = (type: string) => ({\n version: 'figure-v3-asset-1',\n name: type,\n document: {\n version: 'figure-v3-prototype-1',\n model: {\n version: 'r3-spatial-1',\n inputs: [],\n constants: [\n { id: 'w', unit: 'mm', value: 100 },\n { id: 'half', unit: 'mm', value: 50 },\n { id: 'minusHalf', unit: 'mm', value: -50 },\n { id: 'zero', unit: 'mm', value: 0 },\n { id: 'a0', unit: 'deg', value: 0 }\n ],\n nodes: [\n { id: 'body.shape', op: 'box-shape@1', args: ['w', 'w', 'w'], outputs: { shape: 'body.s' }, params: { frame: 'body.local' } },\n {\n id: 'body.pose',\n op: 'rigid@1',\n args: ['zero', 'half', 'zero', 'a0', 'a0', 'a0'],\n outputs: { pose: 'body.p' },\n params: { from: 'body.local', to: 'asset' }\n },\n { id: 'body', op: 'place@1', args: ['body.s', 'body.p'], outputs: { placed: 'body.placed' } }\n ]\n },\n capabilities: { version: 'r3-capability-3', assetFrame: 'asset', bindings: [] }\n },\n designInputs: {},\n stateDefaults: {},\n palette: { 'palette.primary': '#477b9e' },\n appearance: [{ target: 'body', material: { token: 'palette.primary' } }],\n occupancy: {\n bounds: { x: { min: 'minusHalf', max: 'half' }, y: { min: 'zero', max: 'w' }, z: { min: 'minusHalf', max: 'half' } },\n placement: 'floor'\n }\n})\n\nconst v3PayloadOf = (type: string) => ({ format: 'v3' as const, type, asset: v3AssetOf(type) })\n\n/** Records what was asked for, and answers from a table. */\nfunction fetcherOf(published: Record<string, unknown>, failing: string[] = []) {\n const asked: string[] = []\n\n return {\n asked,\n fetch: async (type: string) => {\n asked.push(type)\n if (failing.includes(type)) {\n throw new Error(`no route to the door (${type})`)\n }\n return (published[type] ?? null) as never\n }\n }\n}\n\ndescribe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () => {\n afterEach(() => {\n resetFiguresV3()\n })\n\n it('대문자 이름만 서버에 묻는다 — 씬의 기본 type 과 오타는 문을 지나지 않는다', async () => {\n const { asked, fetch } = fetcherOf({ EQ_MIXER: v3PayloadOf('EQ_MIXER') })\n\n await createFigureResolver(fetch)(['EQ_MIXER', 'rect', 'Conveyor', 'text', 'VEH_AGV_01'])\n\n expect(asked).to.deep.equal(['EQ_MIXER', 'VEH_AGV_01'])\n })\n\n it('이미 등록된 type 은 묻지 않는다 — 그리고 있는 컴포넌트를 figure 가 덮지 않는다', async () => {\n const { asked, fetch } = fetcherOf({ EQ_TAKEN: v3PayloadOf('EQ_TAKEN') })\n\n /* Somebody else already draws this name — a plugin, an app's own component. */\n Component.register('EQ_TAKEN', class Taken extends Component {} as never)\n\n await createFigureResolver(fetch)(['EQ_TAKEN'])\n\n expect(asked).to.deep.equal([])\n expect(hasFigureV3('EQ_TAKEN')).to.equal(false)\n })\n\n it('받은 자산을 등록한다 — 도면은 type 만 적으면 된다', async () => {\n const { fetch } = fetcherOf({ EQ_REGISTERED: v3PayloadOf('EQ_REGISTERED') })\n\n await createFigureResolver(fetch)(['EQ_REGISTERED'])\n\n expect(hasFigureV3('EQ_REGISTERED')).to.equal(true)\n /* The component type is registered with it — the model writes `type` and nothing else. */\n expect(Component.register('EQ_REGISTERED')).to.not.equal(undefined)\n })\n\n it('자산은 씬의 문으로 등록한다 — 보드는 그것을 읽지 않고 씬에 넘긴다', async () => {\n const { fetch } = fetcherOf({ EQ_V3: v3PayloadOf('EQ_V3') })\n\n await createFigureResolver(fetch)(['EQ_V3'])\n\n expect(hasFigureV3('EQ_V3')).to.equal(true)\n /* 도면은 type 하나만 적으면 그려진다. */\n expect(Component.register('EQ_V3')).to.not.equal(undefined)\n })\n\n it('자산이 아닌 것(format 이 v3 가 아닌 답)은 그 type 만 실패로 남는다 — 옛 청사진을 그리지 않는다', async () => {\n const { fetch } = fetcherOf({ EQ_NEW: v3PayloadOf('EQ_NEW'), EQ_OLD: { version: 1, type: 'EQ_OLD', groups: [] } })\n\n let message = ''\n try {\n await createFigureResolver(fetch)(['EQ_NEW', 'EQ_OLD'])\n } catch (error) {\n message = error instanceof Error ? error.message : String(error)\n }\n\n expect(message).to.contain('not a figure asset: EQ_OLD')\n expect(hasFigureV3('EQ_NEW')).to.equal(true)\n expect(hasFigureV3('EQ_OLD')).to.equal(false)\n })\n\n it('읽을 수 없는 V3 자산은 그 type 만 실패로 남는다', async () => {\n const broken = v3PayloadOf('EQ_V3_BROKEN')\n broken.asset.appearance = []\n const { fetch } = fetcherOf({ EQ_BESIDE_V3: v3PayloadOf('EQ_BESIDE_V3'), EQ_V3_BROKEN: broken })\n\n let message = ''\n try {\n await createFigureResolver(fetch)(['EQ_BESIDE_V3', 'EQ_V3_BROKEN'])\n } catch (error) {\n message = error instanceof Error ? error.message : String(error)\n }\n\n expect(message).to.contain('EQ_V3_BROKEN')\n expect(hasFigureV3('EQ_BESIDE_V3')).to.equal(true)\n expect(hasFigureV3('EQ_V3_BROKEN')).to.equal(false)\n })\n\n it('발행된 것이 없으면 조용히 자리표시로 남는다 — 거절이 아니다', async () => {\n const { fetch } = fetcherOf({})\n\n let rejected = false\n try {\n await createFigureResolver(fetch)(['EQ_NOT_PUBLISHED'])\n } catch {\n rejected = true\n }\n\n expect(rejected).to.equal(false)\n expect(hasFigureV3('EQ_NOT_PUBLISHED')).to.equal(false)\n })\n\n it('물을 수 없으면 거절한다. 그때도 답을 받은 것은 등록된다', async () => {\n const { fetch } = fetcherOf({ EQ_BESIDE_BROKEN: v3PayloadOf('EQ_BESIDE_BROKEN') }, ['EQ_BROKEN'])\n\n let message = ''\n try {\n await createFigureResolver(fetch)(['EQ_BESIDE_BROKEN', 'EQ_BROKEN'])\n } catch (error) {\n message = error instanceof Error ? error.message : String(error)\n }\n\n expect(message).to.contain('EQ_BROKEN')\n expect(message).to.not.contain('EQ_BESIDE_BROKEN')\n expect(hasFigureV3('EQ_BESIDE_BROKEN')).to.equal(true)\n })\n\n it('읽을 수 없는 자산은 그 type 만 실패로 남는다 — 다른 type 을 막지 않는다', async () => {\n const { fetch } = fetcherOf({\n EQ_BESIDE_MALFORMED: v3PayloadOf('EQ_BESIDE_MALFORMED'),\n EQ_MALFORMED: { format: 'v3', type: 'EQ_MALFORMED', asset: { version: 'figure-v3-asset-1' } }\n })\n\n let message = ''\n try {\n await createFigureResolver(fetch)(['EQ_BESIDE_MALFORMED', 'EQ_MALFORMED'])\n } catch (error) {\n message = error instanceof Error ? error.message : String(error)\n }\n\n expect(message).to.contain('EQ_MALFORMED')\n expect(hasFigureV3('EQ_BESIDE_MALFORMED')).to.equal(true)\n expect(hasFigureV3('EQ_MALFORMED')).to.equal(false)\n })\n\n it('씬의 자리에 앉아 동작한다 — 모델의 모르는 type 이 해석 뒤에 남지 않는다', async () => {\n const { fetch } = fetcherOf({ EQ_ON_A_BOARD: v3PayloadOf('EQ_ON_A_BOARD') })\n const takeBack = registerTypeResolver(createFigureResolver(fetch))\n\n try {\n const model = {\n type: 'container',\n components: [\n { type: 'EQ_ON_A_BOARD', left: 0, top: 0, width: 100, height: 100 },\n { type: 'EQ_NEVER_PUBLISHED', left: 0, top: 0, width: 100, height: 100 }\n ]\n }\n\n const resolution = await resolveUnknownTypes(model)\n\n expect(resolution.unresolved).to.deep.equal(['EQ_NEVER_PUBLISHED'])\n expect(resolution.failed).to.deep.equal([])\n expect(hasFigureV3('EQ_ON_A_BOARD')).to.equal(true)\n } finally {\n takeBack()\n }\n })\n})\n"]}
|
|
1
|
+
{"version":3,"file":"figure-provider.test.js","sourceRoot":"","sources":["../../test/figure-provider.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAEzC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,oBAAoB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAEtH,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAEhE;;;;;;;;;;GAUG;AAEH,kGAAkG;AAClG,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC;IACvC,OAAO,EAAE,gBAAgB;IACzB,IAAI,EAAE,IAAI;IACV,QAAQ,EAAE;QACR,OAAO,EAAE,oBAAoB;QAC7B,KAAK,EAAE;YACL,OAAO,EAAE,cAAc;YACvB,MAAM,EAAE,EAAE;YACV,SAAS,EAAE;gBACT,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE;gBACnC,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;gBACrC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;gBAC3C,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE;gBACpC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE;aACpC;YACD,KAAK,EAAE;gBACL,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE;gBAC7H;oBACE,EAAE,EAAE,WAAW;oBACf,EAAE,EAAE,SAAS;oBACb,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;oBAChD,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC3B,MAAM,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,OAAO,EAAE;iBAC5C;gBACD,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE;aAC9F;SACF;QACD,YAAY,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE;KAChF;IACD,YAAY,EAAE,EAAE;IAChB,aAAa,EAAE,EAAE;IACjB,OAAO,EAAE,EAAE,iBAAiB,EAAE,SAAS,EAAE;IACzC,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,CAAC;IACxE,SAAS,EAAE;QACT,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;QACpH,SAAS,EAAE,OAAO;KACnB;CACF,CAAC,CAAA;AAEF,MAAM,eAAe,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAEhF,4DAA4D;AAC5D,SAAS,SAAS,CAAC,SAAkC,EAAE,UAAoB,EAAE;IAC3E,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,OAAO;QACL,KAAK;QACL,KAAK,EAAE,KAAK,EAAE,IAAY,EAAE,EAAE;;YAC5B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAChB,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,GAAG,CAAC,CAAA;YACnD,CAAC;YACD,OAAO,CAAC,MAAA,SAAS,CAAC,IAAI,CAAC,mCAAI,IAAI,CAAU,CAAA;QAC3C,CAAC;KACF,CAAA;AACH,CAAC;AAED,QAAQ,CAAC,oCAAoC,EAAE,GAAG,EAAE;IAClD,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,EAAE,CAAA;IAChB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAE7E,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAA;QAEzF,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,QAAQ,EAAE,eAAe,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;QAE7E,+EAA+E;QAC/E,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,KAAM,SAAQ,SAAS;SAAY,CAAC,CAAA;QAEzE,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAA;QAE/C,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC/B,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,KAAK,IAAI,EAAE;QAC/C,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,aAAa,EAAE,eAAe,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;QAEhF,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAA;QAEpD,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACjD,0FAA0F;QAC1F,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,EAAE,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QAE1D,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QAEzC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACtC,4BAA4B;QAC5B,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QAEtH,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAA;QACzD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAA;QACxD,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC1C,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;QAC5C,MAAM,MAAM,GAAG,eAAe,CAAC,iBAAiB,CAAC,CAAA;QACjD,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAA;QAC5B,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,SAAS,EAAE,eAAe,CAAC,WAAW,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC,CAAA;QAEjG,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAA;QACrE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;QAC7C,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC7C,MAAM,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC,CAAA;QAE/B,IAAI,QAAQ,GAAG,KAAK,CAAA;QACpB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAA;QACzD,CAAC;QAAC,WAAM,CAAC;YACP,QAAQ,GAAG,IAAI,CAAA;QACjB,CAAC;QAED,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAChC,MAAM,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACvD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,gBAAgB,EAAE,eAAe,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAA;QAErG,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAA;QACtE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;QACvC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAA;QAClD,MAAM,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC/D,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC;YAC1B,mBAAmB,EAAE,eAAe,CAAC,qBAAqB,CAAC;YAC3D,YAAY,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE;SAC7E,CAAC,CAAA;QAEF,IAAI,OAAO,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB,EAAE,cAAc,CAAC,CAAC,CAAA;QAC5E,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAClE,CAAC;QAED,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;QAC1C,MAAM,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACvD,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,EAAE,KAAK,EAAE,GAAG,SAAS,CAAC,EAAE,aAAa,EAAE,eAAe,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;QAChF,MAAM,QAAQ,GAAG,oBAAoB,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAA;QAElE,IAAI,CAAC;YACH,MAAM,KAAK,GAAG;gBACZ,IAAI,EAAE,WAAW;gBACjB,UAAU,EAAE;oBACV,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;oBACnE,EAAE,IAAI,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;iBACzE;aACF,CAAA;YAED,MAAM,UAAU,GAAG,MAAM,mBAAmB,CAAC,KAAK,CAAC,CAAA;YAEnD,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAA;YACnE,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YAC3C,MAAM,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACnD,CAAC;gBAAS,CAAC;YACT,QAAQ,EAAE,CAAA;QACZ,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA","sourcesContent":["import { expect } from '@open-wc/testing'\n\nimport { Component, hasFigure, registerTypeResolver, resetFigures, resolveUnknownTypes } from '@hatiolab/things-scene'\n\nimport { createFigureResolver } from '../src/figure-provider.js'\n\n/**\n * The path a published figure takes to a board (ADR-0063 결정 2).\n *\n * things-scene holds the seat and knows nothing about figures; this package fills it. What is\n * checked here is the part that belongs to the board: which names are asked about, what happens to\n * the answer, and how \"nobody published this\" stays apart from \"could not ask\".\n *\n * The payload below is written out rather than built with figure-model: this package does not read it, it passes it\n * to the scene's own registration, and a fixture that drifts from the format should fail loudly here rather than\n * draw nothing at runtime.\n */\n\n/** What the door hands over: a figure asset. One box standing on the floor, its room declared. */\nconst figureAssetOf = (type: string) => ({\n version: 'figure-asset-1',\n name: type,\n document: {\n version: 'figure-prototype-1',\n model: {\n version: 'r3-spatial-1',\n inputs: [],\n constants: [\n { id: 'w', unit: 'mm', value: 100 },\n { id: 'half', unit: 'mm', value: 50 },\n { id: 'minusHalf', unit: 'mm', value: -50 },\n { id: 'zero', unit: 'mm', value: 0 },\n { id: 'a0', unit: 'deg', value: 0 }\n ],\n nodes: [\n { id: 'body.shape', op: 'box-shape@1', args: ['w', 'w', 'w'], outputs: { shape: 'body.s' }, params: { frame: 'body.local' } },\n {\n id: 'body.pose',\n op: 'rigid@1',\n args: ['zero', 'half', 'zero', 'a0', 'a0', 'a0'],\n outputs: { pose: 'body.p' },\n params: { from: 'body.local', to: 'asset' }\n },\n { id: 'body', op: 'place@1', args: ['body.s', 'body.p'], outputs: { placed: 'body.placed' } }\n ]\n },\n capabilities: { version: 'r3-capability-3', assetFrame: 'asset', bindings: [] }\n },\n designInputs: {},\n stateDefaults: {},\n palette: { 'palette.primary': '#477b9e' },\n appearance: [{ target: 'body', material: { token: 'palette.primary' } }],\n occupancy: {\n bounds: { x: { min: 'minusHalf', max: 'half' }, y: { min: 'zero', max: 'w' }, z: { min: 'minusHalf', max: 'half' } },\n placement: 'floor'\n }\n})\n\nconst figurePayloadOf = (type: string) => ({ type, asset: figureAssetOf(type) })\n\n/** Records what was asked for, and answers from a table. */\nfunction fetcherOf(published: Record<string, unknown>, failing: string[] = []) {\n const asked: string[] = []\n\n return {\n asked,\n fetch: async (type: string) => {\n asked.push(type)\n if (failing.includes(type)) {\n throw new Error(`no route to the door (${type})`)\n }\n return (published[type] ?? null) as never\n }\n }\n}\n\ndescribe('figure 공급자 — 보드가 발행된 Figure 를 받는 길', () => {\n afterEach(() => {\n resetFigures()\n })\n\n it('대문자 이름만 서버에 묻는다 — 씬의 기본 type 과 오타는 문을 지나지 않는다', async () => {\n const { asked, fetch } = fetcherOf({ EQ_MIXER: figurePayloadOf('EQ_MIXER') })\n\n await createFigureResolver(fetch)(['EQ_MIXER', 'rect', 'Conveyor', 'text', 'VEH_AGV_01'])\n\n expect(asked).to.deep.equal(['EQ_MIXER', 'VEH_AGV_01'])\n })\n\n it('이미 등록된 type 은 묻지 않는다 — 그리고 있는 컴포넌트를 figure 가 덮지 않는다', async () => {\n const { asked, fetch } = fetcherOf({ EQ_TAKEN: figurePayloadOf('EQ_TAKEN') })\n\n /* Somebody else already draws this name — a plugin, an app's own component. */\n Component.register('EQ_TAKEN', class Taken extends Component {} as never)\n\n await createFigureResolver(fetch)(['EQ_TAKEN'])\n\n expect(asked).to.deep.equal([])\n expect(hasFigure('EQ_TAKEN')).to.equal(false)\n })\n\n it('받은 자산을 등록한다 — 도면은 type 만 적으면 된다', async () => {\n const { fetch } = fetcherOf({ EQ_REGISTERED: figurePayloadOf('EQ_REGISTERED') })\n\n await createFigureResolver(fetch)(['EQ_REGISTERED'])\n\n expect(hasFigure('EQ_REGISTERED')).to.equal(true)\n /* The component type is registered with it — the model writes `type` and nothing else. */\n expect(Component.register('EQ_REGISTERED')).to.not.equal(undefined)\n })\n\n it('자산은 씬의 문으로 등록한다 — 보드는 그것을 읽지 않고 씬에 넘긴다', async () => {\n const { fetch } = fetcherOf({ EQ: figurePayloadOf('EQ') })\n\n await createFigureResolver(fetch)(['EQ'])\n\n expect(hasFigure('EQ')).to.equal(true)\n /* 도면은 type 하나만 적으면 그려진다. */\n expect(Component.register('EQ')).to.not.equal(undefined)\n })\n\n it('자산이 없는 답은 그 type 만 실패로 남는다 — 옛 청사진을 그리지 않는다', async () => {\n const { fetch } = fetcherOf({ EQ_NEW: figurePayloadOf('EQ_NEW'), EQ_OLD: { version: 1, type: 'EQ_OLD', groups: [] } })\n\n let message = ''\n try {\n await createFigureResolver(fetch)(['EQ_NEW', 'EQ_OLD'])\n } catch (error) {\n message = error instanceof Error ? error.message : String(error)\n }\n\n expect(message).to.contain('not a figure asset: EQ_OLD')\n expect(hasFigure('EQ_NEW')).to.equal(true)\n expect(hasFigure('EQ_OLD')).to.equal(false)\n })\n\n it('읽을 수 없는 자산은 그 type 만 실패로 남는다', async () => {\n const broken = figurePayloadOf('EQ_ASSET_BROKEN')\n broken.asset.appearance = []\n const { fetch } = fetcherOf({ EQ_BESIDE: figurePayloadOf('EQ_BESIDE'), EQ_ASSET_BROKEN: broken })\n\n let message = ''\n try {\n await createFigureResolver(fetch)(['EQ_BESIDE', 'EQ_ASSET_BROKEN'])\n } catch (error) {\n message = error instanceof Error ? error.message : String(error)\n }\n\n expect(message).to.contain('EQ_ASSET_BROKEN')\n expect(hasFigure('EQ_BESIDE')).to.equal(true)\n expect(hasFigure('EQ_ASSET_BROKEN')).to.equal(false)\n })\n\n it('발행된 것이 없으면 조용히 자리표시로 남는다 — 거절이 아니다', async () => {\n const { fetch } = fetcherOf({})\n\n let rejected = false\n try {\n await createFigureResolver(fetch)(['EQ_NOT_PUBLISHED'])\n } catch {\n rejected = true\n }\n\n expect(rejected).to.equal(false)\n expect(hasFigure('EQ_NOT_PUBLISHED')).to.equal(false)\n })\n\n it('물을 수 없으면 거절한다. 그때도 답을 받은 것은 등록된다', async () => {\n const { fetch } = fetcherOf({ EQ_BESIDE_BROKEN: figurePayloadOf('EQ_BESIDE_BROKEN') }, ['EQ_BROKEN'])\n\n let message = ''\n try {\n await createFigureResolver(fetch)(['EQ_BESIDE_BROKEN', 'EQ_BROKEN'])\n } catch (error) {\n message = error instanceof Error ? error.message : String(error)\n }\n\n expect(message).to.contain('EQ_BROKEN')\n expect(message).to.not.contain('EQ_BESIDE_BROKEN')\n expect(hasFigure('EQ_BESIDE_BROKEN')).to.equal(true)\n })\n\n it('읽을 수 없는 자산은 그 type 만 실패로 남는다 — 다른 type 을 막지 않는다', async () => {\n const { fetch } = fetcherOf({\n EQ_BESIDE_MALFORMED: figurePayloadOf('EQ_BESIDE_MALFORMED'),\n EQ_MALFORMED: { type: 'EQ_MALFORMED', asset: { version: 'figure-asset-1' } }\n })\n\n let message = ''\n try {\n await createFigureResolver(fetch)(['EQ_BESIDE_MALFORMED', 'EQ_MALFORMED'])\n } catch (error) {\n message = error instanceof Error ? error.message : String(error)\n }\n\n expect(message).to.contain('EQ_MALFORMED')\n expect(hasFigure('EQ_BESIDE_MALFORMED')).to.equal(true)\n expect(hasFigure('EQ_MALFORMED')).to.equal(false)\n })\n\n it('씬의 자리에 앉아 동작한다 — 모델의 모르는 type 이 해석 뒤에 남지 않는다', async () => {\n const { fetch } = fetcherOf({ EQ_ON_A_BOARD: figurePayloadOf('EQ_ON_A_BOARD') })\n const takeBack = registerTypeResolver(createFigureResolver(fetch))\n\n try {\n const model = {\n type: 'container',\n components: [\n { type: 'EQ_ON_A_BOARD', left: 0, top: 0, width: 100, height: 100 },\n { type: 'EQ_NEVER_PUBLISHED', left: 0, top: 0, width: 100, height: 100 }\n ]\n }\n\n const resolution = await resolveUnknownTypes(model)\n\n expect(resolution.unresolved).to.deep.equal(['EQ_NEVER_PUBLISHED'])\n expect(resolution.failed).to.deep.equal([])\n expect(hasFigure('EQ_ON_A_BOARD')).to.equal(true)\n } finally {\n takeBack()\n }\n })\n})\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { expect, fixture, html } from '@open-wc/testing';
|
|
2
2
|
import { executeServerCommand } from '@web/test-runner-commands';
|
|
3
|
-
import { registerTypeResolver,
|
|
3
|
+
import { registerTypeResolver, resetFigures } from '@hatiolab/things-scene';
|
|
4
4
|
import { createResolvedScene } from '../src/resolved-scene.js';
|
|
5
5
|
import '../src/ox-board-preview.js';
|
|
6
6
|
/**
|
|
@@ -40,7 +40,7 @@ describe('모르는 type 이 없으면 아무에게도 묻지 않는다', () =>
|
|
|
40
40
|
});
|
|
41
41
|
afterEach(() => {
|
|
42
42
|
takeBack();
|
|
43
|
-
|
|
43
|
+
resetFigures();
|
|
44
44
|
});
|
|
45
45
|
it('씬의 기본 type 만 있는 보드는 공급자를 부르지 않는다', async () => {
|
|
46
46
|
var _a;
|
|
@@ -60,7 +60,7 @@ describe('기다리는 동안 화면이 바뀌면 늦게 온 씬은 들어서지
|
|
|
60
60
|
let takeBack;
|
|
61
61
|
afterEach(() => {
|
|
62
62
|
takeBack === null || takeBack === void 0 ? void 0 : takeBack();
|
|
63
|
-
|
|
63
|
+
resetFigures();
|
|
64
64
|
});
|
|
65
65
|
it('앞의 모델을 풀고 돌아왔을 때 미리보기가 다른 모델을 들고 있으면 그 씬은 버린다', async () => {
|
|
66
66
|
/* The first model's type resolves slowly; the second one has nothing to resolve. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolved-scene.test.js","sourceRoot":"","sources":["../../test/resolved-scene.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAExD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAEhE,OAAO,EAAE,oBAAoB,EAAE,
|
|
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 } 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"]}
|