@fugood/bricks-ctor 2.24.0-beta.40
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/compile/action-name-map.ts +988 -0
- package/compile/index.ts +1245 -0
- package/compile/util.ts +358 -0
- package/index.ts +6 -0
- package/package.json +28 -0
- package/skills/bricks-design/LICENSE.txt +180 -0
- package/skills/bricks-design/SKILL.md +66 -0
- package/skills/bricks-project/SKILL.md +32 -0
- package/skills/bricks-project/rules/animation.md +159 -0
- package/skills/bricks-project/rules/architecture-patterns.md +69 -0
- package/skills/bricks-project/rules/automations.md +221 -0
- package/skills/bricks-project/rules/buttress.md +156 -0
- package/skills/bricks-project/rules/data-calculation.md +208 -0
- package/skills/bricks-project/rules/local-sync.md +129 -0
- package/skills/bricks-project/rules/media-flow.md +158 -0
- package/skills/bricks-project/rules/remote-data-bank.md +196 -0
- package/skills/bricks-project/rules/standby-transition.md +124 -0
- package/skills/rive-marketplace/SKILL.md +99 -0
- package/tools/deploy.ts +151 -0
- package/tools/icons/.gitattributes +1 -0
- package/tools/icons/fa6pro-glyphmap.json +4686 -0
- package/tools/icons/fa6pro-meta.json +3671 -0
- package/tools/mcp-server.ts +28 -0
- package/tools/mcp-tools/compile.ts +91 -0
- package/tools/mcp-tools/huggingface.ts +762 -0
- package/tools/mcp-tools/icons.ts +70 -0
- package/tools/mcp-tools/lottie.ts +102 -0
- package/tools/mcp-tools/media.ts +110 -0
- package/tools/postinstall.ts +229 -0
- package/tools/preview-main.mjs +293 -0
- package/tools/preview.ts +143 -0
- package/tools/pull.ts +116 -0
- package/tsconfig.json +16 -0
- package/types/animation.ts +100 -0
- package/types/automation.ts +235 -0
- package/types/brick-base.ts +80 -0
- package/types/bricks/Camera.ts +246 -0
- package/types/bricks/Chart.ts +372 -0
- package/types/bricks/GenerativeMedia.ts +276 -0
- package/types/bricks/Icon.ts +98 -0
- package/types/bricks/Image.ts +114 -0
- package/types/bricks/Items.ts +476 -0
- package/types/bricks/Lottie.ts +168 -0
- package/types/bricks/Maps.ts +262 -0
- package/types/bricks/QrCode.ts +117 -0
- package/types/bricks/Rect.ts +150 -0
- package/types/bricks/RichText.ts +128 -0
- package/types/bricks/Rive.ts +220 -0
- package/types/bricks/Slideshow.ts +201 -0
- package/types/bricks/Svg.ts +99 -0
- package/types/bricks/Text.ts +148 -0
- package/types/bricks/TextInput.ts +242 -0
- package/types/bricks/Video.ts +175 -0
- package/types/bricks/VideoStreaming.ts +112 -0
- package/types/bricks/WebRtcStream.ts +65 -0
- package/types/bricks/WebView.ts +168 -0
- package/types/bricks/index.ts +21 -0
- package/types/canvas.ts +82 -0
- package/types/common.ts +144 -0
- package/types/data-calc-command.ts +7005 -0
- package/types/data-calc-script.ts +21 -0
- package/types/data-calc.ts +11 -0
- package/types/data.ts +95 -0
- package/types/generators/AlarmClock.ts +110 -0
- package/types/generators/Assistant.ts +621 -0
- package/types/generators/BleCentral.ts +247 -0
- package/types/generators/BlePeripheral.ts +208 -0
- package/types/generators/CanvasMap.ts +74 -0
- package/types/generators/CastlesPay.ts +87 -0
- package/types/generators/DataBank.ts +160 -0
- package/types/generators/File.ts +432 -0
- package/types/generators/GraphQl.ts +132 -0
- package/types/generators/Http.ts +222 -0
- package/types/generators/HttpServer.ts +176 -0
- package/types/generators/Information.ts +103 -0
- package/types/generators/Intent.ts +168 -0
- package/types/generators/Iterator.ts +108 -0
- package/types/generators/Keyboard.ts +105 -0
- package/types/generators/LlmAnthropicCompat.ts +212 -0
- package/types/generators/LlmAppleBuiltin.ts +159 -0
- package/types/generators/LlmGgml.ts +861 -0
- package/types/generators/LlmMediaTekNeuroPilot.ts +235 -0
- package/types/generators/LlmMlx.ts +227 -0
- package/types/generators/LlmOnnx.ts +213 -0
- package/types/generators/LlmOpenAiCompat.ts +244 -0
- package/types/generators/LlmQualcommAiEngine.ts +247 -0
- package/types/generators/Mcp.ts +637 -0
- package/types/generators/McpServer.ts +289 -0
- package/types/generators/MediaFlow.ts +170 -0
- package/types/generators/MqttBroker.ts +141 -0
- package/types/generators/MqttClient.ts +141 -0
- package/types/generators/Question.ts +408 -0
- package/types/generators/RealtimeTranscription.ts +279 -0
- package/types/generators/RerankerGgml.ts +191 -0
- package/types/generators/SerialPort.ts +151 -0
- package/types/generators/SoundPlayer.ts +94 -0
- package/types/generators/SoundRecorder.ts +130 -0
- package/types/generators/SpeechToTextGgml.ts +415 -0
- package/types/generators/SpeechToTextOnnx.ts +236 -0
- package/types/generators/SpeechToTextPlatform.ts +85 -0
- package/types/generators/SqLite.ts +159 -0
- package/types/generators/Step.ts +107 -0
- package/types/generators/SttAppleBuiltin.ts +130 -0
- package/types/generators/Tcp.ts +126 -0
- package/types/generators/TcpServer.ts +147 -0
- package/types/generators/TextToSpeechAppleBuiltin.ts +127 -0
- package/types/generators/TextToSpeechGgml.ts +221 -0
- package/types/generators/TextToSpeechOnnx.ts +178 -0
- package/types/generators/TextToSpeechOpenAiLike.ts +121 -0
- package/types/generators/ThermalPrinter.ts +191 -0
- package/types/generators/Tick.ts +83 -0
- package/types/generators/Udp.ts +120 -0
- package/types/generators/VadGgml.ts +250 -0
- package/types/generators/VadOnnx.ts +231 -0
- package/types/generators/VadTraditional.ts +138 -0
- package/types/generators/VectorStore.ts +257 -0
- package/types/generators/Watchdog.ts +107 -0
- package/types/generators/WebCrawler.ts +103 -0
- package/types/generators/WebRtc.ts +181 -0
- package/types/generators/WebSocket.ts +148 -0
- package/types/generators/index.ts +57 -0
- package/types/index.ts +13 -0
- package/types/subspace.ts +59 -0
- package/types/switch.ts +51 -0
- package/types/system.ts +707 -0
- package/utils/calc.ts +126 -0
- package/utils/data.ts +497 -0
- package/utils/event-props.ts +836 -0
- package/utils/id.ts +80 -0
package/compile/index.ts
ADDED
|
@@ -0,0 +1,1245 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle -- Uses __typename, __actionName, etc. for type system */
|
|
2
|
+
import camelCase from 'lodash/camelCase'
|
|
3
|
+
import upperFirst from 'lodash/upperFirst'
|
|
4
|
+
import snakeCase from 'lodash/snakeCase'
|
|
5
|
+
import omit from 'lodash/omit'
|
|
6
|
+
import { parse as parseAST } from 'acorn'
|
|
7
|
+
import type { ExportNamedDeclaration, FunctionDeclaration } from 'acorn'
|
|
8
|
+
import escodegen from 'escodegen'
|
|
9
|
+
import { generateCalulationMap } from './util'
|
|
10
|
+
import { templateActionNameMap } from './action-name-map'
|
|
11
|
+
import { templateEventPropsMap } from '../utils/event-props'
|
|
12
|
+
import type {
|
|
13
|
+
Application,
|
|
14
|
+
Data,
|
|
15
|
+
DataAssetKind,
|
|
16
|
+
Animation,
|
|
17
|
+
AnimationDef,
|
|
18
|
+
AnimationComposeDef,
|
|
19
|
+
ActionWithDataParams,
|
|
20
|
+
ActionWithParams,
|
|
21
|
+
BrickItems,
|
|
22
|
+
SwitchCondData,
|
|
23
|
+
SwitchCondInnerStateCurrentCanvas,
|
|
24
|
+
SwitchCondPropertyBankByItemKey,
|
|
25
|
+
DataCalculationMap,
|
|
26
|
+
DataCalculationScript,
|
|
27
|
+
DataCalculationData,
|
|
28
|
+
DataCommand,
|
|
29
|
+
Brick,
|
|
30
|
+
Canvas,
|
|
31
|
+
Subspace,
|
|
32
|
+
AutomationMap,
|
|
33
|
+
AutomationTestMap,
|
|
34
|
+
AutomationTest,
|
|
35
|
+
TestCase,
|
|
36
|
+
TestVariable,
|
|
37
|
+
} from '../types'
|
|
38
|
+
|
|
39
|
+
const uuidPattern = '[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}'
|
|
40
|
+
|
|
41
|
+
const entryIdPatterns = {
|
|
42
|
+
SUBSPACE: new RegExp(`^SUBSPACE_${uuidPattern}$`),
|
|
43
|
+
CANVAS: new RegExp(`^CANVAS_${uuidPattern}$`),
|
|
44
|
+
BRICK: new RegExp(`^BRICK_${uuidPattern}$`),
|
|
45
|
+
GENERATOR: new RegExp(`^(GENERATOR|AUTO_GENERATOR)_${uuidPattern}$`),
|
|
46
|
+
ANIMATION: new RegExp(`^ANIMATION_${uuidPattern}$`),
|
|
47
|
+
PROPERTY_BANK_DATA_NODE: new RegExp(`^PROPERTY_BANK_DATA_NODE_${uuidPattern}$`),
|
|
48
|
+
PROPERTY_BANK_COMMAND_NODE: new RegExp(`^PROPERTY_BANK_COMMAND_NODE_${uuidPattern}$`),
|
|
49
|
+
PROPERTY_BANK_COMMAND_MAP: new RegExp(`^PROPERTY_BANK_COMMAND_MAP_${uuidPattern}$`),
|
|
50
|
+
BRICK_STATE_GROUP: new RegExp(`^BRICK_STATE_GROUP_${uuidPattern}$`),
|
|
51
|
+
TEST: new RegExp(`^TEST_${uuidPattern}$`),
|
|
52
|
+
TEST_CASE: new RegExp(`^TEST_CASE_${uuidPattern}$`),
|
|
53
|
+
TEST_VAR: new RegExp(`^TEST_VAR_${uuidPattern}$`),
|
|
54
|
+
AUTOMATION_MAP: /^AUTOMATION_MAP_.*/,
|
|
55
|
+
} as const
|
|
56
|
+
|
|
57
|
+
type EntryIdPatternKey = keyof typeof entryIdPatterns
|
|
58
|
+
|
|
59
|
+
const assertEntryId = (
|
|
60
|
+
id: unknown,
|
|
61
|
+
patternKey: EntryIdPatternKey,
|
|
62
|
+
errorReference: string = '',
|
|
63
|
+
): string => {
|
|
64
|
+
const pattern = entryIdPatterns[patternKey]
|
|
65
|
+
if (typeof id !== 'string' || !pattern.test(id)) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
`Invalid ${patternKey} id${errorReference ? ` ${errorReference}` : ''}: ${String(id)}`,
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
return id
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const compileProperty = (property, errorReference: string, result = {}) => {
|
|
74
|
+
if (Array.isArray(property)) {
|
|
75
|
+
return property.map((p) => compileProperty(p, errorReference))
|
|
76
|
+
}
|
|
77
|
+
if (property?.__typename === 'DataLink') {
|
|
78
|
+
const data = property.data?.()
|
|
79
|
+
if (!data?.id) throw new Error(`Invalid DataLink reference ${errorReference}`)
|
|
80
|
+
return `PROPERTY_BANK#${data.id}`
|
|
81
|
+
}
|
|
82
|
+
if (typeof property === 'function') {
|
|
83
|
+
const instance = property()
|
|
84
|
+
if (!instance?.id) throw new Error(`Invalid ID reference ${errorReference}`)
|
|
85
|
+
return instance?.id // defined type instance getter
|
|
86
|
+
}
|
|
87
|
+
if (property && typeof property === 'object') {
|
|
88
|
+
return Object.entries(property).reduce((acc, [key, value]) => {
|
|
89
|
+
acc[key] = compileProperty(value, errorReference)
|
|
90
|
+
return acc
|
|
91
|
+
}, result)
|
|
92
|
+
}
|
|
93
|
+
return property
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const compileScriptCalculationCode = (code = '') => {
|
|
97
|
+
try {
|
|
98
|
+
const program = parseAST(code, { sourceType: 'module', ecmaVersion: 2020 })
|
|
99
|
+
// export function main() { ... }
|
|
100
|
+
const declarationBody = (
|
|
101
|
+
(program.body[0] as ExportNamedDeclaration).declaration as FunctionDeclaration
|
|
102
|
+
)?.body
|
|
103
|
+
return escodegen.generate(declarationBody, {
|
|
104
|
+
format: {
|
|
105
|
+
indent: { style: ' ' },
|
|
106
|
+
semicolons: false,
|
|
107
|
+
},
|
|
108
|
+
comment: true,
|
|
109
|
+
})
|
|
110
|
+
} catch {
|
|
111
|
+
return code || ''
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const getTemplateName = (key: string) =>
|
|
116
|
+
upperFirst(camelCase(key.replace(/^(BRICK|GENERATOR)_/, '')))
|
|
117
|
+
|
|
118
|
+
const compileEventActionValue = (templateKey, eventKey, value, errorReference) => {
|
|
119
|
+
const tmplEventProperties = templateEventPropsMap[getTemplateName(templateKey)]
|
|
120
|
+
const props = tmplEventProperties?.[eventKey]
|
|
121
|
+
if (!props) return compileProperty(value, errorReference)
|
|
122
|
+
if (typeof value === 'string' && value in props) {
|
|
123
|
+
const expectedType = props[value]
|
|
124
|
+
if (expectedType) return value
|
|
125
|
+
}
|
|
126
|
+
if (typeof value === 'string' && /^(BRICK|GENERATOR)_/.test(value)) {
|
|
127
|
+
console.warn(
|
|
128
|
+
`[Warning] Event property "${value}" is not compatible with event "${eventKey}" of ${templateKey} ${errorReference}`,
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
return compileProperty(value, errorReference)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const convertOutletKey = (templateKey: string, key: string) =>
|
|
135
|
+
`${templateKey}_${snakeCase(key).toUpperCase()}`
|
|
136
|
+
|
|
137
|
+
const compileOutlets = (
|
|
138
|
+
templateKey: string,
|
|
139
|
+
outlets: { [key: string]: () => Data },
|
|
140
|
+
errorReference: string,
|
|
141
|
+
) =>
|
|
142
|
+
Object.entries(outlets).reduce((acc, [key, data]) => {
|
|
143
|
+
const dataInstance = data?.()
|
|
144
|
+
const dataId = assertEntryId(dataInstance?.id, 'PROPERTY_BANK_DATA_NODE', errorReference)
|
|
145
|
+
acc[convertOutletKey(templateKey, key)] = dataId
|
|
146
|
+
return acc
|
|
147
|
+
}, {})
|
|
148
|
+
|
|
149
|
+
const convertEventKey = (templateKey: string, key: string) =>
|
|
150
|
+
`${templateKey ? `${templateKey}_` : ''}${snakeCase(key).toUpperCase()}`
|
|
151
|
+
|
|
152
|
+
const basicAnimationEvents = ['show', 'standby', 'breatheStart']
|
|
153
|
+
|
|
154
|
+
const compileAnimations = (
|
|
155
|
+
templateKey: string,
|
|
156
|
+
animations: { [key: string]: Animation },
|
|
157
|
+
errorReference: string,
|
|
158
|
+
) =>
|
|
159
|
+
Object.entries(animations).reduce((acc, [key, animation]) => {
|
|
160
|
+
const animationId = assertEntryId(animation?.id, 'ANIMATION', errorReference)
|
|
161
|
+
acc[convertEventKey(basicAnimationEvents.includes(key) ? 'BRICK' : templateKey, key)] =
|
|
162
|
+
`ANIMATION#${animationId}`
|
|
163
|
+
return acc
|
|
164
|
+
}, {})
|
|
165
|
+
|
|
166
|
+
const compileActionParam = (templateKey: string, actionName: string, paramName: string) =>
|
|
167
|
+
templateActionNameMap[templateKey]?.[actionName]?.[paramName] || paramName
|
|
168
|
+
|
|
169
|
+
const compileEvents = (
|
|
170
|
+
templateKey: string,
|
|
171
|
+
eventMap: { [key: string]: Array<any> },
|
|
172
|
+
options = { camelCase: false, errorReference: '' },
|
|
173
|
+
) => {
|
|
174
|
+
const { camelCase, errorReference } = options
|
|
175
|
+
return Object.entries(eventMap).reduce((acc, [key, events]) => {
|
|
176
|
+
acc[convertEventKey(templateKey, key)] = events.map((event) => {
|
|
177
|
+
const { handler, action } = event
|
|
178
|
+
|
|
179
|
+
let handlerKey
|
|
180
|
+
let handlerTemplateKey
|
|
181
|
+
if (handler === 'system' || typeof handler === 'string') {
|
|
182
|
+
if (handler.startsWith('SUBSPACE_')) handlerKey = handler
|
|
183
|
+
else handlerKey = handler.toUpperCase()
|
|
184
|
+
if (handlerKey === 'SYSTEM') handlerTemplateKey = 'SYSTEM'
|
|
185
|
+
} else if (typeof handler === 'function') {
|
|
186
|
+
let instance = handler()
|
|
187
|
+
if (instance?.id) {
|
|
188
|
+
instance = instance as { id: string }
|
|
189
|
+
handlerKey = instance?.id
|
|
190
|
+
} else if (instance?.brickId) {
|
|
191
|
+
instance = instance as { brickId: string; templateKey: string }
|
|
192
|
+
handlerKey = instance.brickId
|
|
193
|
+
}
|
|
194
|
+
handlerTemplateKey = instance?.templateKey
|
|
195
|
+
}
|
|
196
|
+
if (!handlerKey) throw new Error(`Invalid handler: ${handler} ${errorReference}`)
|
|
197
|
+
|
|
198
|
+
const parameterList: Array<object> = []
|
|
199
|
+
if (Object.prototype.hasOwnProperty.call(action, 'params')) {
|
|
200
|
+
const actionDef = action as ActionWithParams
|
|
201
|
+
;(actionDef.params || []).forEach(({ input, value, mapping }) => {
|
|
202
|
+
const param = {
|
|
203
|
+
[camelCase ? 'inputToReceiver' : 'input_to_receiver']: handlerTemplateKey
|
|
204
|
+
? compileActionParam(handlerTemplateKey, action.__actionName, input)
|
|
205
|
+
: input,
|
|
206
|
+
[camelCase ? 'resultFromSender' : 'result_from_sender']:
|
|
207
|
+
mapping || compileEventActionValue(handlerTemplateKey, key, value, errorReference),
|
|
208
|
+
}
|
|
209
|
+
if (mapping) param[camelCase ? 'resultDataMapping' : 'result_data_mapping'] = true
|
|
210
|
+
parameterList.push(param)
|
|
211
|
+
})
|
|
212
|
+
} else if (Object.prototype.hasOwnProperty.call(action, 'dataParams')) {
|
|
213
|
+
const actionDef = action as ActionWithDataParams
|
|
214
|
+
;(actionDef.dataParams || []).forEach(({ input, value, mapping }) => {
|
|
215
|
+
if (!input) return
|
|
216
|
+
const param = {
|
|
217
|
+
[camelCase ? 'inputToReceiver' : 'input_to_receiver']: input().id,
|
|
218
|
+
[camelCase ? 'resultFromSender' : 'result_from_sender']:
|
|
219
|
+
mapping || compileEventActionValue(handlerTemplateKey, key, value, errorReference),
|
|
220
|
+
}
|
|
221
|
+
if (mapping) param[camelCase ? 'resultDataMapping' : 'result_data_mapping'] = true
|
|
222
|
+
parameterList.push(param)
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
handler: handlerKey,
|
|
227
|
+
action: action.__actionName,
|
|
228
|
+
[camelCase ? 'parameterList' : 'parameter_list']: parameterList,
|
|
229
|
+
[camelCase ? 'waitAsync' : 'wait_async']: event.waitAsync,
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
return acc
|
|
233
|
+
}, {})
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const compileSwitchConds = (templateKey, conds, errorReference) =>
|
|
237
|
+
(conds || []).map((item: any, index) => {
|
|
238
|
+
const result: any = { method: item.method }
|
|
239
|
+
if (!item.cond) return result
|
|
240
|
+
if (item.cond.__typename === 'SwitchCondData') {
|
|
241
|
+
const cond = item.cond as SwitchCondData
|
|
242
|
+
result.type = 'property_bank'
|
|
243
|
+
if (!cond.data().id)
|
|
244
|
+
throw new Error(`Invalid data reference in conds index: ${index} ${errorReference}`)
|
|
245
|
+
result.key = cond.data().id
|
|
246
|
+
result.value = cond.value
|
|
247
|
+
} else if (item.cond.__typename === 'SwitchCondPropertyBankByItemKey') {
|
|
248
|
+
const cond = item.cond as SwitchCondPropertyBankByItemKey
|
|
249
|
+
result.type = 'property_bank_by_item_key'
|
|
250
|
+
if (!cond.data().id)
|
|
251
|
+
throw new Error(`Invalid data reference in conds index: ${index} ${errorReference}`)
|
|
252
|
+
result.key = cond.data().id
|
|
253
|
+
result.value = cond.value
|
|
254
|
+
} else if (item.cond.__typename === 'SwitchCondInnerStateOutlet') {
|
|
255
|
+
const { cond } = item
|
|
256
|
+
result.type = 'inner_state'
|
|
257
|
+
result.key = convertOutletKey(templateKey, cond.outlet)
|
|
258
|
+
result.value = cond.value
|
|
259
|
+
} else if (item.cond.__typename === 'SwitchCondInnerStateCurrentCanvas') {
|
|
260
|
+
const cond = item.cond as SwitchCondInnerStateCurrentCanvas
|
|
261
|
+
result.type = 'inner_state'
|
|
262
|
+
result.key = 'current_canvas'
|
|
263
|
+
if (!cond.value().id)
|
|
264
|
+
throw new Error(`Invalid canvas reference in conds index: ${index} ${errorReference}`)
|
|
265
|
+
result.value = cond.value().id
|
|
266
|
+
}
|
|
267
|
+
return result
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
const compileApplicationSettings = (settings: Application['settings']) => ({
|
|
271
|
+
internet_reachability_url: settings?.internetReachabilityUrl,
|
|
272
|
+
enable_data_lock: settings?.enableDataLock,
|
|
273
|
+
show_deprecated_features: settings?.showDeprecatedFeatures,
|
|
274
|
+
enable_unstable_bricks: settings?.enableUnstableFeatures,
|
|
275
|
+
runtime_cache_options: settings?.runtimeCacheOptions
|
|
276
|
+
? {
|
|
277
|
+
disabled: settings.runtimeCacheOptions.disabled,
|
|
278
|
+
behavior: settings.runtimeCacheOptions.behavior,
|
|
279
|
+
retry_attempt_for_failure: settings.runtimeCacheOptions.retryAttemptForFailure,
|
|
280
|
+
}
|
|
281
|
+
: undefined,
|
|
282
|
+
tv_options: settings?.tvOptions
|
|
283
|
+
? {
|
|
284
|
+
disabled_selectable: settings.tvOptions.disabledSelectable,
|
|
285
|
+
selectable_color: settings.tvOptions.selectableColor,
|
|
286
|
+
selectable_border: settings.tvOptions.selectableBorder,
|
|
287
|
+
}
|
|
288
|
+
: undefined,
|
|
289
|
+
ai: settings?.ai
|
|
290
|
+
? {
|
|
291
|
+
use_anthropic_api_key_system_data: settings.ai.useAnthropicApiKeySystemData,
|
|
292
|
+
use_openai_api_key_system_data: settings.ai.useOpenAiApiKeySystemData,
|
|
293
|
+
use_gemini_api_key_system_data: settings.ai.useGeminiApiKeySystemData,
|
|
294
|
+
}
|
|
295
|
+
: undefined,
|
|
296
|
+
hide_short_refs: settings?.hideShortRefs,
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
const animationTypeMap = {
|
|
300
|
+
AnimationTimingConfig: 'timing',
|
|
301
|
+
AnimationSpringConfig: 'spring',
|
|
302
|
+
AnimationDecayConfig: 'decay',
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const compileFrame = (frame: Canvas['items'][number]['frame']) => ({
|
|
306
|
+
x: frame.x,
|
|
307
|
+
y: frame.y,
|
|
308
|
+
width: frame.width,
|
|
309
|
+
height: frame.height,
|
|
310
|
+
standby_mode: frame.standbyMode,
|
|
311
|
+
standby_frame: frame.standbyFrame,
|
|
312
|
+
standby_opacity: frame.standbyOpacity,
|
|
313
|
+
standby_delay: frame.standbyDelay,
|
|
314
|
+
standby_delay_random: frame.standbyDelayRandom,
|
|
315
|
+
standby_easing: frame.standbyEasing,
|
|
316
|
+
showing_delay: frame.showingDelay,
|
|
317
|
+
render_out_of_viewport: frame.renderOutOfViewport,
|
|
318
|
+
})
|
|
319
|
+
|
|
320
|
+
const preloadTypes = [
|
|
321
|
+
'media-resource-image',
|
|
322
|
+
'media-resource-video',
|
|
323
|
+
'media-resource-audio',
|
|
324
|
+
'media-resource-file',
|
|
325
|
+
'lottie-file-uri',
|
|
326
|
+
'ggml-model-asset',
|
|
327
|
+
'gguf-model-asset',
|
|
328
|
+
'binary-asset',
|
|
329
|
+
]
|
|
330
|
+
|
|
331
|
+
const compileKind = (kind: Data['kind']) => {
|
|
332
|
+
const { type, ...rest } = kind || {}
|
|
333
|
+
if (!type) return {}
|
|
334
|
+
if (preloadTypes.includes(type)) {
|
|
335
|
+
const { preload, metadata } = kind as DataAssetKind
|
|
336
|
+
const result: any = { kind: type, ...rest }
|
|
337
|
+
if (preload) {
|
|
338
|
+
result.preload = {
|
|
339
|
+
type: preload.type,
|
|
340
|
+
hashType: preload.hashType,
|
|
341
|
+
}
|
|
342
|
+
if (preload.hashType) result.preload[preload.hashType] = preload.hash
|
|
343
|
+
}
|
|
344
|
+
// Handle metadata
|
|
345
|
+
if (type === 'gguf-model-asset') {
|
|
346
|
+
result._hfRepoInfo = metadata?.hfRepoInfo
|
|
347
|
+
}
|
|
348
|
+
return result
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
return { kind: type, ...rest }
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const compileRemoteUpdate = (remoteUpdate: Data['remoteUpdate']) => {
|
|
355
|
+
if (!remoteUpdate) return {}
|
|
356
|
+
if (remoteUpdate.type === 'auto') return { enable_remote_update: true }
|
|
357
|
+
return {
|
|
358
|
+
enable_remote_update: true,
|
|
359
|
+
...(remoteUpdate.type === 'device-specific' ? { use_remote_id_prefix: true } : {}),
|
|
360
|
+
...(remoteUpdate.type === 'global-data' ? { global_remote_update_prop: remoteUpdate.id } : {}),
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const compileModule = (subspace: Subspace) => {
|
|
365
|
+
if (!subspace.module) return {}
|
|
366
|
+
return {
|
|
367
|
+
module: {
|
|
368
|
+
link: true,
|
|
369
|
+
id: subspace.module.id,
|
|
370
|
+
version: subspace.module.version,
|
|
371
|
+
},
|
|
372
|
+
selected_requirements: subspace.module.selectedRequirements?.reduce((acc, requirement) => {
|
|
373
|
+
acc[requirement.subspace] = {
|
|
374
|
+
id: requirement.id,
|
|
375
|
+
version: requirement.version,
|
|
376
|
+
}
|
|
377
|
+
return acc
|
|
378
|
+
}, {}),
|
|
379
|
+
requirements: subspace.module.requirements?.reduce((acc, requirement) => {
|
|
380
|
+
acc[requirement.subspace] = {
|
|
381
|
+
id: requirement.id,
|
|
382
|
+
version: requirement.version,
|
|
383
|
+
}
|
|
384
|
+
return acc
|
|
385
|
+
}, {}),
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Compile a run array element - if it's a getter function, call it and extract the id
|
|
391
|
+
* Note: All entity ids already include their prefix (e.g., SUBSPACE_xxx, BRICK_xxx, PROPERTY_BANK_DATA_NODE_xxx)
|
|
392
|
+
*/
|
|
393
|
+
function compileRunElement(element: unknown): unknown {
|
|
394
|
+
if (typeof element !== 'function') return element
|
|
395
|
+
|
|
396
|
+
const result = element()
|
|
397
|
+
if (result && typeof result === 'object' && 'id' in result) {
|
|
398
|
+
return (result as { id: string }).id
|
|
399
|
+
}
|
|
400
|
+
return result
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Compile a run array - resolve getter functions and extract ids with prefixes
|
|
405
|
+
*/
|
|
406
|
+
function compileRunArray(run: unknown[]): unknown[] {
|
|
407
|
+
return run.map(compileRunElement)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Compile typed TestCase to raw format (strips __typename)
|
|
412
|
+
*/
|
|
413
|
+
const compileTestCase = (testCase: TestCase) => ({
|
|
414
|
+
id: testCase.id,
|
|
415
|
+
name: testCase.name,
|
|
416
|
+
hide_short_ref: testCase.hideShortRef,
|
|
417
|
+
run: compileRunArray(testCase.run),
|
|
418
|
+
exit_on_failed: testCase.exit_on_failed,
|
|
419
|
+
commented: testCase.commented,
|
|
420
|
+
pre_delay: testCase.pre_delay,
|
|
421
|
+
post_delay: testCase.post_delay,
|
|
422
|
+
post_delay_rule: testCase.post_delay_rule,
|
|
423
|
+
jump_cond: testCase.jump_cond.map((cond) => {
|
|
424
|
+
if (cond.jump_to == null) {
|
|
425
|
+
console.warn(
|
|
426
|
+
`[Warning] jump_cond is missing jump_to in test case "${testCase.name}" (${testCase.id})`,
|
|
427
|
+
)
|
|
428
|
+
}
|
|
429
|
+
return {
|
|
430
|
+
type: cond.type,
|
|
431
|
+
status: cond.status,
|
|
432
|
+
variable: cond.variable,
|
|
433
|
+
operator: cond.operator,
|
|
434
|
+
value: cond.value,
|
|
435
|
+
jump_to: cond.jump_to,
|
|
436
|
+
}
|
|
437
|
+
}),
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Compile typed TestVariable to raw format (strips __typename)
|
|
442
|
+
*/
|
|
443
|
+
const compileTestVariable = (variable: TestVariable) => ({
|
|
444
|
+
id: variable.id,
|
|
445
|
+
name: variable.name,
|
|
446
|
+
type: variable.type,
|
|
447
|
+
value: variable.value,
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Convert an array of items with id property to an id-keyed record
|
|
452
|
+
*/
|
|
453
|
+
const arrayToIdMap = <T extends { id: string }, R>(
|
|
454
|
+
items: T[],
|
|
455
|
+
transform: (item: T, index: number) => R,
|
|
456
|
+
options: {
|
|
457
|
+
patternKey: EntryIdPatternKey
|
|
458
|
+
getErrorReference: (item: T, index: number) => string
|
|
459
|
+
},
|
|
460
|
+
): Record<string, R> =>
|
|
461
|
+
Object.fromEntries(
|
|
462
|
+
items.map((item, index) => {
|
|
463
|
+
const itemId = assertEntryId(
|
|
464
|
+
item.id,
|
|
465
|
+
options.patternKey,
|
|
466
|
+
options.getErrorReference(item, index),
|
|
467
|
+
)
|
|
468
|
+
return [itemId, transform(item, index)]
|
|
469
|
+
}),
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Compile typed AutomationTest to raw format
|
|
474
|
+
*/
|
|
475
|
+
const compileAutomationTest = (
|
|
476
|
+
test: AutomationTest,
|
|
477
|
+
options: { mapId: string; testIndex: number },
|
|
478
|
+
) => {
|
|
479
|
+
const testId = assertEntryId(
|
|
480
|
+
test.id,
|
|
481
|
+
'TEST',
|
|
482
|
+
`(automation map: ${options.mapId}, test index: ${options.testIndex})`,
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
return {
|
|
486
|
+
id: testId,
|
|
487
|
+
title: test.title,
|
|
488
|
+
hide_short_ref: test.hideShortRef,
|
|
489
|
+
timeout: test.timeout,
|
|
490
|
+
trigger_type: test.trigger_type,
|
|
491
|
+
cron: test.cron,
|
|
492
|
+
skip_trigger_type_check: test.skip_trigger_type_check,
|
|
493
|
+
local_sync: test.local_sync,
|
|
494
|
+
meta: test.meta,
|
|
495
|
+
case_map: arrayToIdMap(test.cases, compileTestCase, {
|
|
496
|
+
patternKey: 'TEST_CASE',
|
|
497
|
+
getErrorReference: (_, index) =>
|
|
498
|
+
`(automation map: ${options.mapId}, test: ${testId}, case index: ${index})`,
|
|
499
|
+
}),
|
|
500
|
+
var_map: arrayToIdMap(test.variables, compileTestVariable, {
|
|
501
|
+
patternKey: 'TEST_VAR',
|
|
502
|
+
getErrorReference: (_, index) =>
|
|
503
|
+
`(automation map: ${options.mapId}, test: ${testId}, variable index: ${index})`,
|
|
504
|
+
}),
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Compile typed AutomationTestMap to raw format
|
|
510
|
+
*/
|
|
511
|
+
const compileAutomationTestMap = (testMap: AutomationTestMap, mapId: string) => {
|
|
512
|
+
assertEntryId(testMap.id, 'AUTOMATION_MAP', `(automation map id field: ${mapId})`)
|
|
513
|
+
|
|
514
|
+
return {
|
|
515
|
+
title: testMap.title,
|
|
516
|
+
hide_short_ref: testMap.hideShortRef,
|
|
517
|
+
createdAt: testMap.createdAt,
|
|
518
|
+
map: arrayToIdMap(
|
|
519
|
+
testMap.tests,
|
|
520
|
+
(test, index) => compileAutomationTest(test, { mapId, testIndex: index }),
|
|
521
|
+
{
|
|
522
|
+
patternKey: 'TEST',
|
|
523
|
+
getErrorReference: (_, index) => `(automation map: ${mapId}, test index: ${index})`,
|
|
524
|
+
},
|
|
525
|
+
),
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Compile typed AutomationMap to raw automation_map format
|
|
531
|
+
*/
|
|
532
|
+
const compileAutomation = (automationMap: AutomationMap) =>
|
|
533
|
+
Object.fromEntries(
|
|
534
|
+
Object.entries(automationMap).map(([mapId, testMap]) => {
|
|
535
|
+
const automationMapId = assertEntryId(mapId, 'AUTOMATION_MAP', '(automation map key)')
|
|
536
|
+
return [automationMapId, compileAutomationTestMap(testMap, automationMapId)]
|
|
537
|
+
}),
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
export const compile = async (app: Application) => {
|
|
541
|
+
await new Promise((resolve) => setImmediate(resolve, 0))
|
|
542
|
+
const timestamp = Date.now()
|
|
543
|
+
const config = {
|
|
544
|
+
title: `${app.name || 'Unknown'}(${timestamp})`,
|
|
545
|
+
subspace_map: app.subspaces.reduce((subspaceMap, subspace, subspaceIndex) => {
|
|
546
|
+
const subspaceId = assertEntryId(
|
|
547
|
+
subspace.id,
|
|
548
|
+
'SUBSPACE',
|
|
549
|
+
`(subspace index: ${subspaceIndex})`,
|
|
550
|
+
)
|
|
551
|
+
const rootCanvasId = assertEntryId(
|
|
552
|
+
subspace.rootCanvas?.id,
|
|
553
|
+
'CANVAS',
|
|
554
|
+
`(subspace: ${subspaceId}, root canvas)`,
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
subspaceMap[subspaceId] = {
|
|
558
|
+
title: subspace.title,
|
|
559
|
+
description: subspace.description,
|
|
560
|
+
hide_short_ref: subspace.hideShortRef,
|
|
561
|
+
unused: subspace.unused,
|
|
562
|
+
portal: subspace.portal,
|
|
563
|
+
_expanded: subspace.unexpanded
|
|
564
|
+
? {
|
|
565
|
+
brick: !subspace.unexpanded.brick,
|
|
566
|
+
generator: !subspace.unexpanded.generator,
|
|
567
|
+
canvas: subspace.unexpanded.canvas?.reduce((acc, canvas, canvasIndex) => {
|
|
568
|
+
const unexpandedCanvasId = assertEntryId(
|
|
569
|
+
canvas?.id,
|
|
570
|
+
'CANVAS',
|
|
571
|
+
`(subspace: ${subspaceId}, unexpanded canvas index: ${canvasIndex})`,
|
|
572
|
+
)
|
|
573
|
+
acc[unexpandedCanvasId] = !canvas?.id
|
|
574
|
+
return acc
|
|
575
|
+
}, {}),
|
|
576
|
+
property_bank: !subspace.unexpanded.data,
|
|
577
|
+
property_bank_calc: !subspace.unexpanded.dataCalculation,
|
|
578
|
+
}
|
|
579
|
+
: undefined,
|
|
580
|
+
layout: {
|
|
581
|
+
width: subspace.layout?.width,
|
|
582
|
+
height: subspace.layout?.height,
|
|
583
|
+
resize_mode: subspace.layout?.resizeMode,
|
|
584
|
+
},
|
|
585
|
+
local_sync: subspace.localSyncChangeCanvas
|
|
586
|
+
? {
|
|
587
|
+
change_canvas: subspace.localSyncChangeCanvas,
|
|
588
|
+
}
|
|
589
|
+
: undefined,
|
|
590
|
+
animation_map: subspace.animations.reduce((map, animation, animationIndex) => {
|
|
591
|
+
const animationId = assertEntryId(
|
|
592
|
+
animation?.id,
|
|
593
|
+
'ANIMATION',
|
|
594
|
+
`(animation index: ${animationIndex}, subspace: ${subspaceId})`,
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
if (animation.__typename === 'Animation') {
|
|
598
|
+
const animationDef = animation as AnimationDef
|
|
599
|
+
map[animationId] = {
|
|
600
|
+
alias: animationDef.alias,
|
|
601
|
+
title: animationDef.title,
|
|
602
|
+
description: animationDef.description,
|
|
603
|
+
hide_short_ref: animationDef.hideShortRef,
|
|
604
|
+
animationRunType: animationDef.runType,
|
|
605
|
+
property: animationDef.property,
|
|
606
|
+
type: animationTypeMap[animationDef.config.__type],
|
|
607
|
+
config: compileProperty(
|
|
608
|
+
omit(animationDef.config, '__type'),
|
|
609
|
+
`(animation: ${animationId}, subspace ${subspaceId})`,
|
|
610
|
+
),
|
|
611
|
+
}
|
|
612
|
+
} else if (animation.__typename === 'AnimationCompose') {
|
|
613
|
+
const animationDef = animation as AnimationComposeDef
|
|
614
|
+
map[animationId] = {
|
|
615
|
+
alias: animationDef.alias,
|
|
616
|
+
title: animationDef.title,
|
|
617
|
+
description: animationDef.description,
|
|
618
|
+
hide_short_ref: animationDef.hideShortRef,
|
|
619
|
+
animationRunType: animationDef.runType,
|
|
620
|
+
compose_type: animationDef.composeType,
|
|
621
|
+
item_list: animationDef.items.map((item, index) => {
|
|
622
|
+
const innerAnimation = item()
|
|
623
|
+
if (!innerAnimation?.id)
|
|
624
|
+
throw new Error(
|
|
625
|
+
`Invalid animation index: ${index} (animation: ${innerAnimation.id}, subspace ${subspaceId})`,
|
|
626
|
+
)
|
|
627
|
+
return { animation_id: innerAnimation.id }
|
|
628
|
+
}),
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return map
|
|
632
|
+
}, {}),
|
|
633
|
+
brick_map: subspace.bricks.reduce((map, brick, brickIndex) => {
|
|
634
|
+
const brickId = assertEntryId(
|
|
635
|
+
brick.id,
|
|
636
|
+
'BRICK',
|
|
637
|
+
`(brick index: ${brickIndex}, subspace: ${subspaceId})`,
|
|
638
|
+
)
|
|
639
|
+
const property = compileProperty(
|
|
640
|
+
brick.property || {},
|
|
641
|
+
`(brick: ${brickId}, subspace ${subspaceId})`,
|
|
642
|
+
)
|
|
643
|
+
if (brick.templateKey === 'BRICK_ITEMS') {
|
|
644
|
+
const brickItems = brick as BrickItems
|
|
645
|
+
const buildList = (itemBrick, index, key) => ({
|
|
646
|
+
title: itemBrick.title,
|
|
647
|
+
brickId: itemBrick.brickId,
|
|
648
|
+
brickIdPrefix: itemBrick.brickIdPrefix,
|
|
649
|
+
templateKey: itemBrick.templateKey,
|
|
650
|
+
frame: itemBrick.frame,
|
|
651
|
+
property: compileProperty(
|
|
652
|
+
itemBrick.property,
|
|
653
|
+
`(brick: ${brickId}, ${key}: ${index}, subspace ${subspaceId})`,
|
|
654
|
+
),
|
|
655
|
+
propertyMapping: itemBrick.propertyMapping,
|
|
656
|
+
animation: compileAnimations(
|
|
657
|
+
itemBrick.templateKey,
|
|
658
|
+
itemBrick.animation || {},
|
|
659
|
+
`(brick: ${brickId}, ${key}: ${index}, subspace ${subspaceId})`,
|
|
660
|
+
),
|
|
661
|
+
outlet: compileOutlets(
|
|
662
|
+
itemBrick.templateKey,
|
|
663
|
+
itemBrick.outlets || {},
|
|
664
|
+
`(brick: ${brickId}, ${key}: ${index}, subspace ${subspaceId})`,
|
|
665
|
+
),
|
|
666
|
+
eventMap: compileEvents(itemBrick.templateKey, itemBrick.eventMap || {}, {
|
|
667
|
+
camelCase: true,
|
|
668
|
+
errorReference: `(brick: ${brickId}, ${key}: ${index}, subspace ${subspaceId})`,
|
|
669
|
+
}),
|
|
670
|
+
stateGroup: itemBrick.stateGroup.reduce((acc, stateGroup, stateGroupIndex) => {
|
|
671
|
+
const stateGroupId = assertEntryId(
|
|
672
|
+
stateGroup.id,
|
|
673
|
+
'BRICK_STATE_GROUP',
|
|
674
|
+
`(brick: ${brickId}, ${key}: ${index}, switch index: ${stateGroupIndex}, subspace ${subspaceId})`,
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
acc[stateGroupId] = {
|
|
678
|
+
title: stateGroup.title,
|
|
679
|
+
description: stateGroup.description,
|
|
680
|
+
override: stateGroup.override,
|
|
681
|
+
break: stateGroup.break,
|
|
682
|
+
commented: stateGroup.disabled,
|
|
683
|
+
conds: compileSwitchConds(
|
|
684
|
+
itemBrick.templateKey,
|
|
685
|
+
stateGroup.conds || [],
|
|
686
|
+
`(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
|
|
687
|
+
),
|
|
688
|
+
property: compileProperty(
|
|
689
|
+
stateGroup.property,
|
|
690
|
+
`(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
|
|
691
|
+
),
|
|
692
|
+
animation: compileAnimations(
|
|
693
|
+
itemBrick.templateKey,
|
|
694
|
+
stateGroup.animation || {},
|
|
695
|
+
`(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
|
|
696
|
+
),
|
|
697
|
+
outlet: compileOutlets(
|
|
698
|
+
itemBrick.templateKey,
|
|
699
|
+
stateGroup.outlets || {},
|
|
700
|
+
`(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
|
|
701
|
+
),
|
|
702
|
+
eventMap: compileEvents(itemBrick.templateKey, stateGroup.eventMap || {}, {
|
|
703
|
+
camelCase: true,
|
|
704
|
+
errorReference: `(brick: ${brickId}, ${key}: ${index}, switch: ${stateGroupId}, subspace ${subspaceId})`,
|
|
705
|
+
}),
|
|
706
|
+
}
|
|
707
|
+
return acc
|
|
708
|
+
}, {}),
|
|
709
|
+
show: itemBrick.show,
|
|
710
|
+
pressToOpenDetail: itemBrick.pressToOpenDetail,
|
|
711
|
+
pressToBackList: itemBrick.pressToBackList,
|
|
712
|
+
})
|
|
713
|
+
if (Array.isArray(brickItems.brickList)) {
|
|
714
|
+
const brickList = (brickItems.brickList || []).map((item, index) =>
|
|
715
|
+
buildList(item, index, 'brickList'),
|
|
716
|
+
)
|
|
717
|
+
property.brickList = brickList
|
|
718
|
+
} else if (!brickItems.brickList) {
|
|
719
|
+
property.brickList = []
|
|
720
|
+
} else {
|
|
721
|
+
// Not supported Data for brickList
|
|
722
|
+
throw new TypeError('Not supported Data for brickList directly')
|
|
723
|
+
}
|
|
724
|
+
if (Array.isArray(brickItems.brickDetails)) {
|
|
725
|
+
const brickDetails = (brickItems.brickDetails || []).map((item, index) =>
|
|
726
|
+
buildList(item, index, 'brickDetails'),
|
|
727
|
+
)
|
|
728
|
+
property.brickDetails = brickDetails
|
|
729
|
+
} else if (!brickItems.brickDetails) {
|
|
730
|
+
property.brickDetails = []
|
|
731
|
+
} else {
|
|
732
|
+
// Not supported Data for brickList
|
|
733
|
+
throw new TypeError('Not supported Data for brickList directly')
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
map[brickId] = {
|
|
737
|
+
template_key: brick.templateKey,
|
|
738
|
+
alias: brick.alias,
|
|
739
|
+
title: brick.title,
|
|
740
|
+
description: brick.description,
|
|
741
|
+
hide_short_ref: brick.hideShortRef,
|
|
742
|
+
property,
|
|
743
|
+
animation: compileAnimations(
|
|
744
|
+
brick.templateKey,
|
|
745
|
+
brick.animation || {},
|
|
746
|
+
`(brick: ${brickId}, subspace ${subspaceId})`,
|
|
747
|
+
),
|
|
748
|
+
event_map: compileEvents(brick.templateKey, brick.events || {}, {
|
|
749
|
+
camelCase: false,
|
|
750
|
+
errorReference: `(brick: ${brickId}, subspace ${subspaceId})`,
|
|
751
|
+
}),
|
|
752
|
+
outlet: compileOutlets(
|
|
753
|
+
brick.templateKey,
|
|
754
|
+
brick.outlets || {},
|
|
755
|
+
`(brick: ${brickId}, subspace ${subspaceId})`,
|
|
756
|
+
),
|
|
757
|
+
state_group: brick.switches?.reduce((acc, switchCase, switchIndex) => {
|
|
758
|
+
const switchId = assertEntryId(
|
|
759
|
+
switchCase.id,
|
|
760
|
+
'BRICK_STATE_GROUP',
|
|
761
|
+
`(brick: ${brickId}, switch index: ${switchIndex}, subspace ${subspaceId})`,
|
|
762
|
+
)
|
|
763
|
+
|
|
764
|
+
acc[switchId] = {
|
|
765
|
+
title: switchCase.title,
|
|
766
|
+
description: switchCase.description,
|
|
767
|
+
break: switchCase.break,
|
|
768
|
+
override: switchCase.override,
|
|
769
|
+
commented: switchCase.disabled,
|
|
770
|
+
conds: compileSwitchConds(
|
|
771
|
+
brick.templateKey,
|
|
772
|
+
switchCase.conds || [],
|
|
773
|
+
`(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
774
|
+
),
|
|
775
|
+
property: compileProperty(
|
|
776
|
+
switchCase.property,
|
|
777
|
+
`(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
778
|
+
),
|
|
779
|
+
outlet: compileOutlets(
|
|
780
|
+
brick.templateKey,
|
|
781
|
+
switchCase.outlets || {},
|
|
782
|
+
`(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
783
|
+
),
|
|
784
|
+
event_map: compileEvents(brick.templateKey, switchCase.events || {}, {
|
|
785
|
+
camelCase: false,
|
|
786
|
+
errorReference: `(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
787
|
+
}),
|
|
788
|
+
animation: compileAnimations(
|
|
789
|
+
brick.templateKey,
|
|
790
|
+
switchCase.animation || {},
|
|
791
|
+
`(brick: ${brickId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
792
|
+
),
|
|
793
|
+
}
|
|
794
|
+
return acc
|
|
795
|
+
}, {}),
|
|
796
|
+
}
|
|
797
|
+
return map
|
|
798
|
+
}, {}),
|
|
799
|
+
root_canvas_id: rootCanvasId,
|
|
800
|
+
canvas_map: subspace.canvases.reduce((map, canvas, canvasIndex) => {
|
|
801
|
+
const canvasId = assertEntryId(
|
|
802
|
+
canvas.id,
|
|
803
|
+
'CANVAS',
|
|
804
|
+
`(canvas index: ${canvasIndex}, subspace: ${subspaceId})`,
|
|
805
|
+
)
|
|
806
|
+
|
|
807
|
+
map[canvasId] = {
|
|
808
|
+
alias: canvas.alias,
|
|
809
|
+
title: canvas.title,
|
|
810
|
+
description: canvas.description,
|
|
811
|
+
hide_short_ref: canvas.hideShortRef,
|
|
812
|
+
property: compileProperty(
|
|
813
|
+
canvas.property,
|
|
814
|
+
`(canvas: ${canvasId}, subspace ${subspaceId})`,
|
|
815
|
+
),
|
|
816
|
+
event_map: compileEvents('CANVAS', canvas.events || {}, {
|
|
817
|
+
camelCase: false,
|
|
818
|
+
errorReference: `(canvas: ${canvasId}, subspace ${subspaceId})`,
|
|
819
|
+
}),
|
|
820
|
+
state_group: canvas.switches?.reduce((acc, switchCase, switchIndex) => {
|
|
821
|
+
const switchId = assertEntryId(
|
|
822
|
+
switchCase.id,
|
|
823
|
+
'BRICK_STATE_GROUP',
|
|
824
|
+
`(canvas: ${canvasId}, switch index: ${switchIndex}, subspace ${subspaceId})`,
|
|
825
|
+
)
|
|
826
|
+
|
|
827
|
+
acc[switchId] = {
|
|
828
|
+
title: switchCase.title,
|
|
829
|
+
description: switchCase.description,
|
|
830
|
+
break: switchCase.break,
|
|
831
|
+
override: switchCase.override,
|
|
832
|
+
commented: switchCase.disabled,
|
|
833
|
+
conds: compileSwitchConds(
|
|
834
|
+
'CANVAS',
|
|
835
|
+
switchCase.conds || [],
|
|
836
|
+
`(canvas: ${canvasId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
837
|
+
),
|
|
838
|
+
property: compileProperty(
|
|
839
|
+
switchCase.property,
|
|
840
|
+
`(canvas: ${canvasId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
841
|
+
),
|
|
842
|
+
event_map: compileEvents('CANVAS', switchCase.events || {}, {
|
|
843
|
+
camelCase: false,
|
|
844
|
+
errorReference: `(canvas: ${canvasId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
845
|
+
}),
|
|
846
|
+
animation: compileAnimations(
|
|
847
|
+
'CANVAS',
|
|
848
|
+
switchCase.animation || {},
|
|
849
|
+
`(canvas: ${canvasId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
850
|
+
),
|
|
851
|
+
}
|
|
852
|
+
return acc
|
|
853
|
+
}, {}),
|
|
854
|
+
item_list: canvas.items.map((item, index) => {
|
|
855
|
+
let itemPayload = {}
|
|
856
|
+
if (typeof item.item === 'function') {
|
|
857
|
+
const brick = (item.item as () => Brick)()
|
|
858
|
+
if (!brick?.id)
|
|
859
|
+
throw new Error(
|
|
860
|
+
`Invalid canvas item index: ${index}, brick not found (canvas: ${canvasId}, subspace ${subspaceId})`,
|
|
861
|
+
)
|
|
862
|
+
itemPayload = { brick_id: brick.id }
|
|
863
|
+
} else {
|
|
864
|
+
const targetSubspaceId = item.item
|
|
865
|
+
if (!app.subspaces.some((s) => s.id === targetSubspaceId))
|
|
866
|
+
throw new Error(
|
|
867
|
+
`Invalid canvas item index: ${index}, subspace not found (canvas: ${canvasId}, subspace ${subspaceId})`,
|
|
868
|
+
)
|
|
869
|
+
itemPayload = { subspace_id: targetSubspaceId }
|
|
870
|
+
}
|
|
871
|
+
return {
|
|
872
|
+
type: typeof item.item === 'function' ? 'brick' : 'subspace',
|
|
873
|
+
...itemPayload,
|
|
874
|
+
frame: compileFrame(item.frame),
|
|
875
|
+
hidden: item.hidden,
|
|
876
|
+
}
|
|
877
|
+
}),
|
|
878
|
+
}
|
|
879
|
+
return map
|
|
880
|
+
}, {}),
|
|
881
|
+
generator_map: subspace.generators.reduce((map, generator, generatorIndex) => {
|
|
882
|
+
const generatorId = assertEntryId(
|
|
883
|
+
generator.id,
|
|
884
|
+
'GENERATOR',
|
|
885
|
+
`(generator index: ${generatorIndex}, subspace: ${subspaceId})`,
|
|
886
|
+
)
|
|
887
|
+
|
|
888
|
+
map[generatorId] = {
|
|
889
|
+
template_key: generator.templateKey,
|
|
890
|
+
alias: generator.alias,
|
|
891
|
+
title: generator.title,
|
|
892
|
+
description: generator.description,
|
|
893
|
+
hide_short_ref: generator.hideShortRef,
|
|
894
|
+
local_sync: generator.localSyncRunMode
|
|
895
|
+
? {
|
|
896
|
+
run_mode: generator.localSyncRunMode,
|
|
897
|
+
}
|
|
898
|
+
: undefined,
|
|
899
|
+
property: compileProperty(
|
|
900
|
+
generator.property || {},
|
|
901
|
+
`(generator: ${generatorId}, subspace ${subspaceId})`,
|
|
902
|
+
),
|
|
903
|
+
event_map: compileEvents(generator.templateKey, generator.events || {}, {
|
|
904
|
+
camelCase: false,
|
|
905
|
+
errorReference: `(generator: ${generatorId}, subspace ${subspaceId})`,
|
|
906
|
+
}),
|
|
907
|
+
outlet: compileOutlets(
|
|
908
|
+
generator.templateKey,
|
|
909
|
+
generator.outlets || {},
|
|
910
|
+
`(generator: ${generatorId}, subspace ${subspaceId})`,
|
|
911
|
+
),
|
|
912
|
+
state_group: generator.switches?.reduce((acc, switchCase, switchIndex) => {
|
|
913
|
+
const switchId = assertEntryId(
|
|
914
|
+
switchCase.id,
|
|
915
|
+
'BRICK_STATE_GROUP',
|
|
916
|
+
`(generator: ${generatorId}, switch index: ${switchIndex}, subspace ${subspaceId})`,
|
|
917
|
+
)
|
|
918
|
+
|
|
919
|
+
acc[switchId] = {
|
|
920
|
+
title: switchCase.title,
|
|
921
|
+
description: switchCase.description,
|
|
922
|
+
break: switchCase.break,
|
|
923
|
+
override: switchCase.override,
|
|
924
|
+
commented: switchCase.disabled,
|
|
925
|
+
conds: compileSwitchConds(
|
|
926
|
+
generator.templateKey,
|
|
927
|
+
switchCase.conds || [],
|
|
928
|
+
`(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
929
|
+
),
|
|
930
|
+
property: compileProperty(
|
|
931
|
+
switchCase.property,
|
|
932
|
+
`(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
933
|
+
),
|
|
934
|
+
outlet: compileOutlets(
|
|
935
|
+
generator.templateKey,
|
|
936
|
+
switchCase.outlets || {},
|
|
937
|
+
`(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
938
|
+
),
|
|
939
|
+
event_map: compileEvents(generator.templateKey, switchCase.events || {}, {
|
|
940
|
+
camelCase: false,
|
|
941
|
+
errorReference: `(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
942
|
+
}),
|
|
943
|
+
animation: compileAnimations(
|
|
944
|
+
generator.templateKey,
|
|
945
|
+
switchCase.animation || {},
|
|
946
|
+
`(generator: ${generatorId}, switch: ${switchId}, subspace ${subspaceId})`,
|
|
947
|
+
),
|
|
948
|
+
}
|
|
949
|
+
return acc
|
|
950
|
+
}, {}),
|
|
951
|
+
}
|
|
952
|
+
return map
|
|
953
|
+
}, {}),
|
|
954
|
+
property_bank_map: subspace.data.reduce((map, data, dataIndex) => {
|
|
955
|
+
const dataId = assertEntryId(
|
|
956
|
+
data.id,
|
|
957
|
+
'PROPERTY_BANK_DATA_NODE',
|
|
958
|
+
`(data index: ${dataIndex}, subspace: ${subspaceId})`,
|
|
959
|
+
)
|
|
960
|
+
|
|
961
|
+
map[dataId] = {
|
|
962
|
+
alias: data.alias,
|
|
963
|
+
title: data.title,
|
|
964
|
+
description: data.description,
|
|
965
|
+
hide_short_ref: data.hideShortRef,
|
|
966
|
+
linked: data.metadata?.linked,
|
|
967
|
+
linkedFrom: data.metadata?.linkedFrom,
|
|
968
|
+
local_sync: data.localSyncUpdateMode
|
|
969
|
+
? {
|
|
970
|
+
update_mode: data.localSyncUpdateMode,
|
|
971
|
+
}
|
|
972
|
+
: undefined,
|
|
973
|
+
persist_data: data.persistData,
|
|
974
|
+
...compileRemoteUpdate(data.remoteUpdate),
|
|
975
|
+
routing: data.routing,
|
|
976
|
+
schema: data.schema,
|
|
977
|
+
type: data.type,
|
|
978
|
+
...compileKind(data.kind),
|
|
979
|
+
value: compileProperty(data.value, `(data: ${dataId}, subspace ${subspaceId})`),
|
|
980
|
+
event_map: compileEvents('PROPERTY_BANK', data.events || {}, {
|
|
981
|
+
camelCase: false,
|
|
982
|
+
errorReference: `(data: ${dataId}, subspace ${subspaceId})`,
|
|
983
|
+
}),
|
|
984
|
+
hit_equal: data.hit_equal,
|
|
985
|
+
hit_regex: data.hit_regex,
|
|
986
|
+
}
|
|
987
|
+
return map
|
|
988
|
+
}, {}),
|
|
989
|
+
property_bank_calc_map: subspace.dataCalculation.reduce((map, dataCalc, dataCalcIndex) => {
|
|
990
|
+
const dataCalcId = assertEntryId(
|
|
991
|
+
dataCalc.id,
|
|
992
|
+
'PROPERTY_BANK_COMMAND_MAP',
|
|
993
|
+
`(data calc index: ${dataCalcIndex}, subspace: ${subspaceId})`,
|
|
994
|
+
)
|
|
995
|
+
|
|
996
|
+
const calc: any = {
|
|
997
|
+
title: dataCalc.title,
|
|
998
|
+
description: dataCalc.description,
|
|
999
|
+
hide_short_ref: dataCalc.hideShortRef,
|
|
1000
|
+
}
|
|
1001
|
+
if (dataCalc.triggerMode) calc.trigger_type = dataCalc.triggerMode
|
|
1002
|
+
if (dataCalc.__typename === 'DataCalculationMap') {
|
|
1003
|
+
calc.type = 'general'
|
|
1004
|
+
const mapCalc = dataCalc as DataCalculationMap
|
|
1005
|
+
|
|
1006
|
+
const getNodeId = (
|
|
1007
|
+
node: DataCalculationData | DataCommand,
|
|
1008
|
+
reference = '',
|
|
1009
|
+
nodeIndex?: number,
|
|
1010
|
+
) => {
|
|
1011
|
+
const nodeReference = [
|
|
1012
|
+
`data calc: ${dataCalcId}`,
|
|
1013
|
+
`subspace: ${subspaceId}`,
|
|
1014
|
+
typeof nodeIndex === 'number' ? `node index: ${nodeIndex}` : undefined,
|
|
1015
|
+
reference || undefined,
|
|
1016
|
+
]
|
|
1017
|
+
.filter(Boolean)
|
|
1018
|
+
.join(', ')
|
|
1019
|
+
|
|
1020
|
+
if (node.__typename === 'DataCalculationData') {
|
|
1021
|
+
return assertEntryId(
|
|
1022
|
+
node.data()?.id,
|
|
1023
|
+
'PROPERTY_BANK_DATA_NODE',
|
|
1024
|
+
`(${nodeReference})`,
|
|
1025
|
+
)
|
|
1026
|
+
}
|
|
1027
|
+
if (node.__typename === 'DataCommand') {
|
|
1028
|
+
return assertEntryId(node.id, 'PROPERTY_BANK_COMMAND_NODE', `(${nodeReference})`)
|
|
1029
|
+
}
|
|
1030
|
+
throw new Error(`Invalid node: ${JSON.stringify(node)}`)
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const generateInputPorts = (inputs) =>
|
|
1034
|
+
inputs.reduce((acc, port, portIndex) => {
|
|
1035
|
+
if (!acc[port.key]) acc[port.key] = null
|
|
1036
|
+
|
|
1037
|
+
let sourceId
|
|
1038
|
+
const sourceNode = port.source()
|
|
1039
|
+
if (
|
|
1040
|
+
sourceNode?.__typename === 'DataCalculationData' ||
|
|
1041
|
+
sourceNode?.__typename === 'DataCommand'
|
|
1042
|
+
) {
|
|
1043
|
+
sourceId = getNodeId(sourceNode, `input port index: ${portIndex}`)
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
if (!sourceId) return acc
|
|
1047
|
+
if (!acc[port.key]) acc[port.key] = []
|
|
1048
|
+
|
|
1049
|
+
acc[port.key].push({
|
|
1050
|
+
id: sourceId,
|
|
1051
|
+
port: port.sourceKey,
|
|
1052
|
+
disable_trigger_command: !port.trigger ? true : undefined,
|
|
1053
|
+
})
|
|
1054
|
+
return acc
|
|
1055
|
+
}, {})
|
|
1056
|
+
|
|
1057
|
+
const generateOutputPorts = (outputs) =>
|
|
1058
|
+
outputs.reduce((acc, port, portIndex) => {
|
|
1059
|
+
if (!acc[port.key]) acc[port.key] = null
|
|
1060
|
+
|
|
1061
|
+
let targetId
|
|
1062
|
+
const targetNode = port.target()
|
|
1063
|
+
if (
|
|
1064
|
+
targetNode?.__typename === 'DataCalculationData' ||
|
|
1065
|
+
targetNode?.__typename === 'DataCommand'
|
|
1066
|
+
) {
|
|
1067
|
+
targetId = getNodeId(targetNode, `output port index: ${portIndex}`)
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
if (!targetId) return acc
|
|
1071
|
+
if (!acc[port.key]) acc[port.key] = []
|
|
1072
|
+
|
|
1073
|
+
acc[port.key].push({
|
|
1074
|
+
id: targetId,
|
|
1075
|
+
port: port.targetKey,
|
|
1076
|
+
})
|
|
1077
|
+
return acc
|
|
1078
|
+
}, {})
|
|
1079
|
+
|
|
1080
|
+
calc.map = mapCalc.nodes.reduce((acc, node, nodeIndex) => {
|
|
1081
|
+
if (node.__typename === 'DataCalculationData') {
|
|
1082
|
+
const dataNode = node as DataCalculationData
|
|
1083
|
+
acc[getNodeId(dataNode, 'data node', nodeIndex)] = {
|
|
1084
|
+
title: dataNode.title,
|
|
1085
|
+
description: dataNode.description,
|
|
1086
|
+
hide_short_ref: dataNode.hideShortRef,
|
|
1087
|
+
type: 'data-node',
|
|
1088
|
+
properties: {},
|
|
1089
|
+
in: generateInputPorts(dataNode.inputs),
|
|
1090
|
+
out: generateOutputPorts(dataNode.outputs),
|
|
1091
|
+
}
|
|
1092
|
+
} else if (node.__typename === 'DataCommand') {
|
|
1093
|
+
const commandNode = node as DataCommand
|
|
1094
|
+
const commandName = commandNode.__commandName
|
|
1095
|
+
const type = commandName.split('_')[0].toLowerCase()
|
|
1096
|
+
|
|
1097
|
+
const args = commandNode.inputs.filter(
|
|
1098
|
+
(input) =>
|
|
1099
|
+
typeof input.source !== 'function' ||
|
|
1100
|
+
(input.source()?.__typename !== 'DataCalculationData' &&
|
|
1101
|
+
input.source()?.__typename !== 'DataCommand'),
|
|
1102
|
+
)
|
|
1103
|
+
const inputs = commandNode.inputs.filter(
|
|
1104
|
+
(input) =>
|
|
1105
|
+
typeof input.source === 'function' &&
|
|
1106
|
+
(input.source()?.__typename === 'DataCalculationData' ||
|
|
1107
|
+
input.source()?.__typename === 'DataCommand'),
|
|
1108
|
+
)
|
|
1109
|
+
acc[getNodeId(commandNode, 'command node', nodeIndex)] = {
|
|
1110
|
+
title: commandNode.title,
|
|
1111
|
+
description: commandNode.description,
|
|
1112
|
+
hide_short_ref: commandNode.hideShortRef,
|
|
1113
|
+
type: `command-node-${type}`,
|
|
1114
|
+
properties: {
|
|
1115
|
+
command: commandNode.__commandName,
|
|
1116
|
+
args: args.reduce((argsAcc, input) => {
|
|
1117
|
+
argsAcc[input.key] = input.source
|
|
1118
|
+
return argsAcc
|
|
1119
|
+
}, {}),
|
|
1120
|
+
},
|
|
1121
|
+
in: generateInputPorts(inputs),
|
|
1122
|
+
out: generateOutputPorts(commandNode.outputs),
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
return acc
|
|
1126
|
+
}, {})
|
|
1127
|
+
calc.editor_info = mapCalc.editorInfo.reduce((acc, editorInfo) => {
|
|
1128
|
+
acc[getNodeId(editorInfo.node, 'editor info node')] = {
|
|
1129
|
+
position: editorInfo.position,
|
|
1130
|
+
points: editorInfo.points.reduce((pointsAcc, point) => {
|
|
1131
|
+
const sourceId = getNodeId(point.source, 'editor info point source')
|
|
1132
|
+
const targetId = getNodeId(point.target, 'editor info point target')
|
|
1133
|
+
const key = `${sourceId}-${point.sourceOutputKey}-${targetId}-${point.targetInputKey}`
|
|
1134
|
+
pointsAcc[key] = point.positions
|
|
1135
|
+
return pointsAcc
|
|
1136
|
+
}, {}),
|
|
1137
|
+
}
|
|
1138
|
+
return acc
|
|
1139
|
+
}, {})
|
|
1140
|
+
} else if (dataCalc.__typename === 'DataCalculationScript') {
|
|
1141
|
+
const scriptCalc = dataCalc as DataCalculationScript
|
|
1142
|
+
calc.type = 'script'
|
|
1143
|
+
|
|
1144
|
+
const code = compileScriptCalculationCode(scriptCalc.code)
|
|
1145
|
+
calc.script_config = {
|
|
1146
|
+
title: scriptCalc.title ?? '',
|
|
1147
|
+
note: scriptCalc.note ?? '',
|
|
1148
|
+
code,
|
|
1149
|
+
enable_async: scriptCalc.enableAsync,
|
|
1150
|
+
trigger_mode: scriptCalc.triggerMode,
|
|
1151
|
+
inputs: scriptCalc.inputs.reduce((acc, input) => {
|
|
1152
|
+
const inputId = assertEntryId(
|
|
1153
|
+
input.data()?.id,
|
|
1154
|
+
'PROPERTY_BANK_DATA_NODE',
|
|
1155
|
+
`(data calc: ${dataCalcId}, script input: ${input.key}, subspace: ${subspaceId})`,
|
|
1156
|
+
)
|
|
1157
|
+
acc[inputId] = input.key
|
|
1158
|
+
return acc
|
|
1159
|
+
}, {}),
|
|
1160
|
+
disabled_triggers: scriptCalc.inputs.reduce((acc, input) => {
|
|
1161
|
+
const inputId = assertEntryId(
|
|
1162
|
+
input.data()?.id,
|
|
1163
|
+
'PROPERTY_BANK_DATA_NODE',
|
|
1164
|
+
`(data calc: ${dataCalcId}, script trigger input: ${input.key}, subspace: ${subspaceId})`,
|
|
1165
|
+
)
|
|
1166
|
+
acc[inputId] = !input.trigger
|
|
1167
|
+
return acc
|
|
1168
|
+
}, {}),
|
|
1169
|
+
output: scriptCalc.output
|
|
1170
|
+
? assertEntryId(
|
|
1171
|
+
scriptCalc.output()?.id,
|
|
1172
|
+
'PROPERTY_BANK_DATA_NODE',
|
|
1173
|
+
`(data calc: ${dataCalcId}, script output, subspace: ${subspaceId})`,
|
|
1174
|
+
)
|
|
1175
|
+
: null,
|
|
1176
|
+
outputs: scriptCalc.outputs.reduce((acc, output) => {
|
|
1177
|
+
if (!acc[output.key]) acc[output.key] = []
|
|
1178
|
+
const outputId = assertEntryId(
|
|
1179
|
+
output.data()?.id,
|
|
1180
|
+
'PROPERTY_BANK_DATA_NODE',
|
|
1181
|
+
`(data calc: ${dataCalcId}, script outputs key: ${output.key}, subspace: ${subspaceId})`,
|
|
1182
|
+
)
|
|
1183
|
+
acc[output.key].push(outputId)
|
|
1184
|
+
return acc
|
|
1185
|
+
}, {}),
|
|
1186
|
+
error: scriptCalc.error
|
|
1187
|
+
? assertEntryId(
|
|
1188
|
+
scriptCalc.error()?.id,
|
|
1189
|
+
'PROPERTY_BANK_DATA_NODE',
|
|
1190
|
+
`(data calc: ${dataCalcId}, script error output, subspace: ${subspaceId})`,
|
|
1191
|
+
)
|
|
1192
|
+
: null,
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
Object.assign(
|
|
1196
|
+
calc,
|
|
1197
|
+
generateCalulationMap(calc.script_config, {
|
|
1198
|
+
snapshotMode: process.env.BRICKS_SNAPSHOT_MODE === '1',
|
|
1199
|
+
}),
|
|
1200
|
+
)
|
|
1201
|
+
}
|
|
1202
|
+
map[dataCalcId] = calc
|
|
1203
|
+
return map
|
|
1204
|
+
}, {}),
|
|
1205
|
+
action_map: subspace.actions || undefined,
|
|
1206
|
+
event_map: compileEvents('', subspace.events || {}, {
|
|
1207
|
+
camelCase: false,
|
|
1208
|
+
errorReference: `(subspace ${subspaceId})`,
|
|
1209
|
+
}),
|
|
1210
|
+
routing: subspace.dataRouting.reduce((acc, data, index) => {
|
|
1211
|
+
const dataId = assertEntryId(
|
|
1212
|
+
data?.id,
|
|
1213
|
+
'PROPERTY_BANK_DATA_NODE',
|
|
1214
|
+
`(data routing index: ${index}, subspace ${subspaceId})`,
|
|
1215
|
+
)
|
|
1216
|
+
acc[dataId] = { enabled_routing: true }
|
|
1217
|
+
return acc
|
|
1218
|
+
}, {}),
|
|
1219
|
+
...compileModule(subspace),
|
|
1220
|
+
}
|
|
1221
|
+
return subspaceMap
|
|
1222
|
+
}, {}),
|
|
1223
|
+
root_subspace_id: assertEntryId(
|
|
1224
|
+
app.rootSubspace?.id,
|
|
1225
|
+
'SUBSPACE',
|
|
1226
|
+
'(application root subspace)',
|
|
1227
|
+
),
|
|
1228
|
+
fonts: app.fonts,
|
|
1229
|
+
...compileApplicationSettings(app.settings),
|
|
1230
|
+
// Use typed automationMap if available, otherwise fall back to TEMP metadata
|
|
1231
|
+
test_map: app.automationMap
|
|
1232
|
+
? compileAutomation(app.automationMap)['AUTOMATION_MAP_DEFAULT']?.map || {}
|
|
1233
|
+
: app.metadata?.TEMP_test_map || {},
|
|
1234
|
+
automation_map: app.automationMap
|
|
1235
|
+
? compileAutomation(app.automationMap)
|
|
1236
|
+
: app.metadata?.TEMP_automation_map || {},
|
|
1237
|
+
update_timestamp: timestamp,
|
|
1238
|
+
}
|
|
1239
|
+
return config
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
export const checkConfig = async (configPath: string) => {
|
|
1243
|
+
const { $ } = await import('bun')
|
|
1244
|
+
await $`bricks app check-config ${configPath}`
|
|
1245
|
+
}
|