@fugood/bricks-ctor 2.25.0-beta.60 → 2.25.0-beta.61
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/package.json +4 -28
- package/tools/deploy.ts +19 -176
- package/tools/mcp-server.ts +16 -33
- package/tools/postinstall.ts +21 -292
- package/tools/pull.ts +15 -195
- package/tools/push-config.ts +18 -113
- package/tools/simulator.ts +19 -148
- package/compile/__tests__/config-diff.test.js +0 -100
- package/compile/__tests__/index.test.js +0 -461
- package/compile/__tests__/util.test.js +0 -450
- package/compile/action-name-map.ts +0 -1079
- package/compile/config-diff.ts +0 -155
- package/compile/index.ts +0 -1594
- package/compile/util.ts +0 -482
- package/index.ts +0 -6
- package/skills/bricks-ctor/SKILL.md +0 -38
- package/skills/bricks-ctor/references/animation.md +0 -160
- package/skills/bricks-ctor/references/architecture-patterns.md +0 -88
- package/skills/bricks-ctor/references/automations.md +0 -232
- package/skills/bricks-ctor/references/buttress.md +0 -245
- package/skills/bricks-ctor/references/data-calculation.md +0 -252
- package/skills/bricks-ctor/references/local-sync.md +0 -129
- package/skills/bricks-ctor/references/media-flow.md +0 -165
- package/skills/bricks-ctor/references/remote-data-bank.md +0 -196
- package/skills/bricks-ctor/references/simulator.md +0 -132
- package/skills/bricks-ctor/references/source-editing-tools.md +0 -81
- package/skills/bricks-ctor/references/standby-transition.md +0 -124
- package/skills/bricks-ctor/references/verification-toolchain.md +0 -200
- package/skills/bricks-design/SKILL.md +0 -171
- package/skills/bricks-design/references/architecture-truths.md +0 -132
- package/skills/bricks-design/references/avoiding-complexity.md +0 -91
- package/skills/bricks-design/references/design-critique.md +0 -195
- package/skills/bricks-design/references/design-languages.md +0 -265
- package/skills/bricks-design/references/performance.md +0 -116
- package/skills/bricks-design/references/presentation-and-slideshow.md +0 -137
- package/skills/bricks-design/references/translating-inputs.md +0 -152
- package/skills/bricks-design/references/variations-and-tweaks.md +0 -124
- package/skills/bricks-design/references/when-the-brief-is-branded.md +0 -284
- package/skills/bricks-design/references/when-the-brief-is-vague.md +0 -85
- package/skills/bricks-design/references/workflow.md +0 -134
- package/skills/bricks-ux/SKILL.md +0 -114
- package/skills/bricks-ux/references/accessibility.md +0 -162
- package/skills/bricks-ux/references/flow-states.md +0 -175
- package/skills/bricks-ux/references/interaction-archetypes.md +0 -189
- package/skills/bricks-ux/references/monitoring-screens.md +0 -153
- package/skills/bricks-ux/references/pressable-composition.md +0 -126
- package/skills/bricks-ux/references/user-journey.md +0 -168
- package/skills/bricks-ux/references/ux-critique.md +0 -256
- package/skills/rive-marketplace/SKILL.md +0 -99
- package/tools/__tests__/_cli-error.test.ts +0 -35
- package/tools/__tests__/_mcp-config.test.ts +0 -67
- package/tools/__tests__/pull.test.ts +0 -108
- package/tools/_cli-error.ts +0 -17
- package/tools/_edits-log.ts +0 -41
- package/tools/_git-author.ts +0 -37
- package/tools/_last-pushed-commit.ts +0 -28
- package/tools/_mcp-config.ts +0 -42
- package/tools/_shell.ts +0 -180
- package/tools/icons/.gitattributes +0 -1
- package/tools/icons/fa6pro-glyphmap.json +0 -4686
- package/tools/icons/fa6pro-meta.json +0 -1
- package/tools/mcp-env.ts +0 -13
- package/tools/mcp-tools/__tests__/data-calc-editing.test.js +0 -516
- package/tools/mcp-tools/__tests__/entry-editing.test.js +0 -866
- package/tools/mcp-tools/__tests__/huggingface.test.ts +0 -49
- package/tools/mcp-tools/__tests__/icons.test.ts +0 -21
- package/tools/mcp-tools/__tests__/mcp-env.test.js +0 -19
- package/tools/mcp-tools/_editing-helpers.ts +0 -98
- package/tools/mcp-tools/_verify.ts +0 -50
- package/tools/mcp-tools/compile.ts +0 -104
- package/tools/mcp-tools/data-calc-editing.ts +0 -1311
- package/tools/mcp-tools/entry-editing.ts +0 -2297
- package/tools/mcp-tools/huggingface.ts +0 -772
- package/tools/mcp-tools/icons.ts +0 -97
- package/tools/mcp-tools/lottie.ts +0 -102
- package/tools/mcp-tools/media.ts +0 -113
- package/tools/simulator-main.mjs +0 -488
- package/tools/simulator-preload.cjs +0 -16
- package/types/animation.d.ts +0 -116
- package/types/automation.d.ts +0 -231
- package/types/brick-base.d.ts +0 -80
- package/types/bricks/Camera.d.ts +0 -246
- package/types/bricks/Chart.d.ts +0 -372
- package/types/bricks/GenerativeMedia.d.ts +0 -290
- package/types/bricks/Icon.d.ts +0 -98
- package/types/bricks/Image.d.ts +0 -126
- package/types/bricks/Items.d.ts +0 -480
- package/types/bricks/Lottie.d.ts +0 -168
- package/types/bricks/Maps.d.ts +0 -262
- package/types/bricks/QrCode.d.ts +0 -117
- package/types/bricks/Rect.d.ts +0 -150
- package/types/bricks/RichText.d.ts +0 -131
- package/types/bricks/Rive.d.ts +0 -220
- package/types/bricks/Scene3D.d.ts +0 -676
- package/types/bricks/Sketch.d.ts +0 -256
- package/types/bricks/Slideshow.d.ts +0 -201
- package/types/bricks/Svg.d.ts +0 -99
- package/types/bricks/Text.d.ts +0 -148
- package/types/bricks/TextInput.d.ts +0 -242
- package/types/bricks/Video.d.ts +0 -242
- package/types/bricks/VideoStreaming.d.ts +0 -112
- package/types/bricks/WebRtcStream.d.ts +0 -65
- package/types/bricks/WebView.d.ts +0 -168
- package/types/bricks/index.d.ts +0 -23
- package/types/canvas.d.ts +0 -82
- package/types/common.d.ts +0 -141
- package/types/data-calc-command/base.d.ts +0 -57
- package/types/data-calc-command/collection.d.ts +0 -418
- package/types/data-calc-command/color.d.ts +0 -432
- package/types/data-calc-command/constant.d.ts +0 -50
- package/types/data-calc-command/datetime.d.ts +0 -147
- package/types/data-calc-command/file.d.ts +0 -129
- package/types/data-calc-command/index.d.ts +0 -13
- package/types/data-calc-command/iteratee.d.ts +0 -23
- package/types/data-calc-command/logictype.d.ts +0 -190
- package/types/data-calc-command/math.d.ts +0 -275
- package/types/data-calc-command/object.d.ts +0 -119
- package/types/data-calc-command/sandbox.d.ts +0 -66
- package/types/data-calc-command/string.d.ts +0 -407
- package/types/data-calc-script.d.ts +0 -21
- package/types/data-calc.d.ts +0 -12
- package/types/data.d.ts +0 -97
- package/types/generators/AlarmClock.d.ts +0 -110
- package/types/generators/Assistant.d.ts +0 -640
- package/types/generators/BleCentral.d.ts +0 -247
- package/types/generators/BlePeripheral.d.ts +0 -208
- package/types/generators/CanvasMap.d.ts +0 -74
- package/types/generators/CastlesPay.d.ts +0 -87
- package/types/generators/DataBank.d.ts +0 -160
- package/types/generators/File.d.ts +0 -432
- package/types/generators/GraphQl.d.ts +0 -132
- package/types/generators/Http.d.ts +0 -222
- package/types/generators/HttpServer.d.ts +0 -230
- package/types/generators/Information.d.ts +0 -103
- package/types/generators/Intent.d.ts +0 -168
- package/types/generators/Iterator.d.ts +0 -108
- package/types/generators/Keyboard.d.ts +0 -105
- package/types/generators/LlmAnthropicCompat.d.ts +0 -212
- package/types/generators/LlmAppleBuiltin.d.ts +0 -159
- package/types/generators/LlmGgml.d.ts +0 -903
- package/types/generators/LlmMediaTekNeuroPilot.d.ts +0 -235
- package/types/generators/LlmMlx.d.ts +0 -228
- package/types/generators/LlmOnnx.d.ts +0 -213
- package/types/generators/LlmOpenAiCompat.d.ts +0 -312
- package/types/generators/LlmQualcommAiEngine.d.ts +0 -247
- package/types/generators/Mcp.d.ts +0 -637
- package/types/generators/McpServer.d.ts +0 -289
- package/types/generators/MediaFlow.d.ts +0 -170
- package/types/generators/MqttBroker.d.ts +0 -141
- package/types/generators/MqttClient.d.ts +0 -141
- package/types/generators/Question.d.ts +0 -408
- package/types/generators/RealtimeTranscription.d.ts +0 -287
- package/types/generators/RerankerGgml.d.ts +0 -195
- package/types/generators/SerialPort.d.ts +0 -151
- package/types/generators/SoundPlayer.d.ts +0 -94
- package/types/generators/SoundRecorder.d.ts +0 -139
- package/types/generators/SpeechToTextGgml.d.ts +0 -424
- package/types/generators/SpeechToTextOnnx.d.ts +0 -236
- package/types/generators/SpeechToTextPlatform.d.ts +0 -85
- package/types/generators/SqLite.d.ts +0 -159
- package/types/generators/Step.d.ts +0 -107
- package/types/generators/SttAppleBuiltin.d.ts +0 -153
- package/types/generators/Tcp.d.ts +0 -126
- package/types/generators/TcpServer.d.ts +0 -147
- package/types/generators/TextToSpeechAppleBuiltin.d.ts +0 -127
- package/types/generators/TextToSpeechGgml.d.ts +0 -221
- package/types/generators/TextToSpeechOnnx.d.ts +0 -178
- package/types/generators/TextToSpeechOpenAiLike.d.ts +0 -121
- package/types/generators/ThermalPrinter.d.ts +0 -193
- package/types/generators/Tick.d.ts +0 -83
- package/types/generators/Udp.d.ts +0 -120
- package/types/generators/VadGgml.d.ts +0 -260
- package/types/generators/VadOnnx.d.ts +0 -231
- package/types/generators/VadTraditional.d.ts +0 -138
- package/types/generators/VectorStore.d.ts +0 -257
- package/types/generators/Watchdog.d.ts +0 -107
- package/types/generators/WebCrawler.d.ts +0 -103
- package/types/generators/WebRtc.d.ts +0 -181
- package/types/generators/WebSocket.d.ts +0 -148
- package/types/generators/index.d.ts +0 -57
- package/types/index.d.ts +0 -13
- package/types/subspace.d.ts +0 -60
- package/types/switch.d.ts +0 -51
- package/types/system.d.ts +0 -707
- package/utils/__tests__/calc.test.js +0 -25
- package/utils/__tests__/id.test.js +0 -154
- package/utils/calc.ts +0 -130
- package/utils/data.ts +0 -495
- package/utils/event-props.ts +0 -912
- package/utils/id.ts +0 -133
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { generateDataCalculationMapEditorInfo } from '../calc'
|
|
2
|
-
|
|
3
|
-
describe('generateDataCalculationMapEditorInfo', () => {
|
|
4
|
-
test('indexes source nodes while resolving array input connections', () => {
|
|
5
|
-
const firstSource = { id: 'PROPERTY_BANK_DATA_NODE_first', title: 'First source' }
|
|
6
|
-
const secondSource = { id: 'PROPERTY_BANK_DATA_NODE_second', title: 'Second source' }
|
|
7
|
-
const command = {
|
|
8
|
-
id: 'PROPERTY_BANK_COMMAND_NODE_merge',
|
|
9
|
-
title: 'Merge values',
|
|
10
|
-
inputs: [
|
|
11
|
-
[
|
|
12
|
-
{ id: firstSource.id, port: 'value' },
|
|
13
|
-
{ id: secondSource.id, port: 'value' },
|
|
14
|
-
{ id: 'PROPERTY_BANK_DATA_NODE_missing', port: 'value' },
|
|
15
|
-
],
|
|
16
|
-
],
|
|
17
|
-
outputs: [[{ id: firstSource.id, port: 'value' }]],
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const editorInfo = generateDataCalculationMapEditorInfo([firstSource, secondSource, command])
|
|
21
|
-
const commandInfo = editorInfo.find((info) => info.node === command)
|
|
22
|
-
|
|
23
|
-
expect(commandInfo?.position.x).toBe(615)
|
|
24
|
-
})
|
|
25
|
-
})
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
2
|
-
import { tmpdir } from 'node:os'
|
|
3
|
-
import { join } from 'node:path'
|
|
4
|
-
import { makeId } from '../id'
|
|
5
|
-
|
|
6
|
-
const UUID = '[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}'
|
|
7
|
-
const UUID_ONLY_RE = new RegExp(`^${UUID}$`)
|
|
8
|
-
|
|
9
|
-
const withProjectDir = (app, fn) => {
|
|
10
|
-
const previousCwd = process.cwd()
|
|
11
|
-
const dir = mkdtempSync(join(tmpdir(), 'make-id-'))
|
|
12
|
-
try {
|
|
13
|
-
if (app) writeFileSync(join(dir, 'application.json'), JSON.stringify(app))
|
|
14
|
-
process.chdir(dir)
|
|
15
|
-
return fn()
|
|
16
|
-
} finally {
|
|
17
|
-
process.chdir(previousCwd)
|
|
18
|
-
rmSync(dir, { recursive: true, force: true })
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
describe('makeId', () => {
|
|
23
|
-
describe('type prefixes', () => {
|
|
24
|
-
const cases = [
|
|
25
|
-
['animation', 'ANIMATION_'],
|
|
26
|
-
['brick', 'BRICK_'],
|
|
27
|
-
['dynamic-brick', 'DYNAMIC_BRICK_'],
|
|
28
|
-
['canvas', 'CANVAS_'],
|
|
29
|
-
['generator', 'GENERATOR_'],
|
|
30
|
-
['data', 'PROPERTY_BANK_DATA_NODE_'],
|
|
31
|
-
['switch', 'BRICK_STATE_GROUP_'],
|
|
32
|
-
['property_bank_command', 'PROPERTY_BANK_COMMAND_NODE_'],
|
|
33
|
-
['property_bank_calc', 'PROPERTY_BANK_COMMAND_MAP_'],
|
|
34
|
-
['automation_map', 'AUTOMATION_MAP_'],
|
|
35
|
-
['test', 'TEST_'],
|
|
36
|
-
['test_case', 'TEST_CASE_'],
|
|
37
|
-
['test_var', 'TEST_VAR_'],
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
test.each(cases)('produces %p prefix', (type, prefix) => {
|
|
41
|
-
expect(makeId(type)).toMatch(new RegExp(`^${prefix}${UUID}$`))
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
test('uses generated count fallback when no alias is provided', () => {
|
|
45
|
-
const first = withProjectDir({ id: 'count-fallback-app' }, () => {
|
|
46
|
-
jest.resetModules()
|
|
47
|
-
const { makeId: makeFreshId } = require('../id')
|
|
48
|
-
return [makeFreshId('brick'), makeFreshId('brick')]
|
|
49
|
-
})
|
|
50
|
-
const second = withProjectDir({ id: 'count-fallback-app' }, () => {
|
|
51
|
-
jest.resetModules()
|
|
52
|
-
const { makeId: makeFreshId } = require('../id')
|
|
53
|
-
return [makeFreshId('brick'), makeFreshId('brick')]
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
expect(first[0]).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
57
|
-
expect(first[1]).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
58
|
-
expect(first[0]).not.toBe(first[1])
|
|
59
|
-
expect(second).toEqual(first)
|
|
60
|
-
jest.resetModules()
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
test('unknown type falls through to an unprefixed uuid', () => {
|
|
64
|
-
expect(makeId('not-a-real-type')).toMatch(UUID_ONLY_RE)
|
|
65
|
-
})
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
describe('subspace', () => {
|
|
69
|
-
test('throws because subspace IDs must be fixed', () => {
|
|
70
|
-
expect(() => makeId('subspace')).toThrow(/subspace is not supported/)
|
|
71
|
-
})
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
describe('snapshotMode', () => {
|
|
75
|
-
test('produces deterministic v4 uuids from the generated count', () => {
|
|
76
|
-
const previousCwd = process.cwd()
|
|
77
|
-
const dir = mkdtempSync(join(tmpdir(), 'make-id-snapshot-'))
|
|
78
|
-
writeFileSync(join(dir, 'application.json'), JSON.stringify({ id: 'snapshot-app' }))
|
|
79
|
-
try {
|
|
80
|
-
process.chdir(dir)
|
|
81
|
-
jest.resetModules()
|
|
82
|
-
const { makeId: makeFreshId } = require('../id')
|
|
83
|
-
const a = makeFreshId('brick', { snapshotMode: true })
|
|
84
|
-
const b = makeFreshId('brick', { snapshotMode: true })
|
|
85
|
-
|
|
86
|
-
jest.resetModules()
|
|
87
|
-
const { makeId: makeFreshIdAgain } = require('../id')
|
|
88
|
-
expect(makeFreshIdAgain('brick', { snapshotMode: true })).toBe(a)
|
|
89
|
-
expect(makeFreshIdAgain('brick', { snapshotMode: true })).toBe(b)
|
|
90
|
-
expect(a).not.toBe(b)
|
|
91
|
-
expect(a).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
92
|
-
expect(b).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
93
|
-
} finally {
|
|
94
|
-
process.chdir(previousCwd)
|
|
95
|
-
rmSync(dir, { recursive: true, force: true })
|
|
96
|
-
jest.resetModules()
|
|
97
|
-
}
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
test('snapshotMode false falls back to random uuid', () => {
|
|
101
|
-
const id = makeId('canvas', { snapshotMode: false })
|
|
102
|
-
expect(id).toMatch(new RegExp(`^CANVAS_${UUID}$`))
|
|
103
|
-
})
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
describe('stable aliases', () => {
|
|
107
|
-
test('produces the same id for the same application id, type, and alias', () => {
|
|
108
|
-
const first = withProjectDir({ id: 'stable-app' }, () => {
|
|
109
|
-
jest.resetModules()
|
|
110
|
-
return require('../id').makeId('brick', 'stable-hero')
|
|
111
|
-
})
|
|
112
|
-
const second = withProjectDir({ id: 'stable-app' }, () => {
|
|
113
|
-
jest.resetModules()
|
|
114
|
-
return require('../id').makeId('brick', 'stable-hero')
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
expect(second).toBe(first)
|
|
118
|
-
expect(first).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
119
|
-
jest.resetModules()
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
test('uses the application id when hashing stable aliases', () => {
|
|
123
|
-
const idA = withProjectDir({ id: 'app-a' }, () => makeId('brick', 'hero'))
|
|
124
|
-
const idB = withProjectDir({ id: 'app-b' }, () => makeId('brick', 'hero'))
|
|
125
|
-
|
|
126
|
-
expect(idA).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
127
|
-
expect(idB).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
128
|
-
expect(idA).not.toBe(idB)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
test('rejects duplicate aliases for the same application id and entry type', () => {
|
|
132
|
-
withProjectDir({ id: 'duplicate-app' }, () => {
|
|
133
|
-
expect(makeId('brick', 'shared')).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
134
|
-
expect(() => makeId('brick', 'shared')).toThrow(/Duplicate makeId alias 'shared'/)
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
test('allows the same alias for different entry types', () => {
|
|
139
|
-
withProjectDir({ id: 'shared-alias-app' }, () => {
|
|
140
|
-
const brick = makeId('brick', 'shared')
|
|
141
|
-
const canvas = makeId('canvas', 'shared')
|
|
142
|
-
|
|
143
|
-
expect(brick).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
144
|
-
expect(canvas).toMatch(new RegExp(`^CANVAS_${UUID}$`))
|
|
145
|
-
expect(brick).not.toBe(canvas)
|
|
146
|
-
})
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
test('falls back when application.json is not present', () => {
|
|
150
|
-
const id = withProjectDir(null, () => makeId('brick', 'fallback-app-id'))
|
|
151
|
-
expect(id).toMatch(new RegExp(`^BRICK_${UUID}$`))
|
|
152
|
-
})
|
|
153
|
-
})
|
|
154
|
-
})
|
package/utils/calc.ts
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
DataCommand,
|
|
3
|
-
DataCalculationMap,
|
|
4
|
-
DataCalculationData,
|
|
5
|
-
} from '../types/data-calc-command'
|
|
6
|
-
|
|
7
|
-
const GRID = {
|
|
8
|
-
WIDTH: 300, // Distance between columns
|
|
9
|
-
HEIGHT: 150, // Distance between rows
|
|
10
|
-
PADDING: 15, // Edge padding
|
|
11
|
-
COLUMNS: 4, // Max columns in grid
|
|
12
|
-
ROWS: 3, // Max rows in grid
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// TODO: Improve the algorithm to minimize crossing lines
|
|
16
|
-
|
|
17
|
-
// If we are too lazy to describe nodes in the editing interface,
|
|
18
|
-
// we can let it generate it automatically
|
|
19
|
-
export const generateDataCalculationMapEditorInfo = (
|
|
20
|
-
nodes: Array<DataCalculationData | DataCommand>,
|
|
21
|
-
) => {
|
|
22
|
-
const editorInfo: DataCalculationMap['editorInfo'] = []
|
|
23
|
-
|
|
24
|
-
// Track node relationships
|
|
25
|
-
const inputCounts = new Map<DataCalculationData | DataCommand, number>()
|
|
26
|
-
const outputCounts = new Map<DataCalculationData | DataCommand, number>()
|
|
27
|
-
const connectedTo = new Map<
|
|
28
|
-
DataCalculationData | DataCommand,
|
|
29
|
-
Set<DataCalculationData | DataCommand>
|
|
30
|
-
>()
|
|
31
|
-
const nodeById = new Map<string, DataCalculationData | DataCommand>()
|
|
32
|
-
for (const node of nodes) {
|
|
33
|
-
if ('id' in node) nodeById.set(node.id, node)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Analyze node connections
|
|
37
|
-
nodes.forEach((node) => {
|
|
38
|
-
// Count and track inputs
|
|
39
|
-
if ('inputs' in node) {
|
|
40
|
-
let inputs = 0
|
|
41
|
-
for (const input of node.inputs) {
|
|
42
|
-
if (input === null) continue
|
|
43
|
-
if (Array.isArray(input)) inputs += input.length
|
|
44
|
-
else inputs += 1
|
|
45
|
-
}
|
|
46
|
-
inputCounts.set(node, inputs)
|
|
47
|
-
|
|
48
|
-
// Track connections
|
|
49
|
-
node.inputs.forEach((input) => {
|
|
50
|
-
if (Array.isArray(input)) {
|
|
51
|
-
input.forEach((conn) => {
|
|
52
|
-
if (!connectedTo.has(node)) {
|
|
53
|
-
connectedTo.set(node, new Set())
|
|
54
|
-
}
|
|
55
|
-
const sourceNode = nodeById.get(conn.id)
|
|
56
|
-
if (sourceNode) {
|
|
57
|
-
connectedTo.get(node)!.add(sourceNode)
|
|
58
|
-
}
|
|
59
|
-
})
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
} else {
|
|
63
|
-
inputCounts.set(node, 0)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Count outputs
|
|
67
|
-
if ('outputs' in node) {
|
|
68
|
-
let outputs = 0
|
|
69
|
-
for (const output of node.outputs) {
|
|
70
|
-
if (output === null) continue
|
|
71
|
-
if (Array.isArray(output)) outputs += output.length
|
|
72
|
-
else outputs += 1
|
|
73
|
-
}
|
|
74
|
-
outputCounts.set(node, outputs)
|
|
75
|
-
} else {
|
|
76
|
-
outputCounts.set(node, 0)
|
|
77
|
-
}
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
// Calculate layers
|
|
81
|
-
const layers: Array<Array<DataCalculationData | DataCommand>> = [[], [], [], []]
|
|
82
|
-
|
|
83
|
-
nodes.forEach((node) => {
|
|
84
|
-
const inputs = inputCounts.get(node) || 0
|
|
85
|
-
const outputs = outputCounts.get(node) || 0
|
|
86
|
-
const connections = connectedTo.get(node)?.size || 0
|
|
87
|
-
|
|
88
|
-
if (inputs === 0) {
|
|
89
|
-
// Input nodes (leftmost)
|
|
90
|
-
layers[0].push(node)
|
|
91
|
-
} else if (outputs === 0) {
|
|
92
|
-
// Output nodes (rightmost)
|
|
93
|
-
layers[3].push(node)
|
|
94
|
-
} else if (connections > 1) {
|
|
95
|
-
// Nodes with multiple connections (middle-right)
|
|
96
|
-
layers[2].push(node)
|
|
97
|
-
} else {
|
|
98
|
-
// Processing nodes (middle-left)
|
|
99
|
-
layers[1].push(node)
|
|
100
|
-
}
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
// Position nodes in each layer
|
|
104
|
-
layers.forEach((layerNodes, layerIndex) => {
|
|
105
|
-
// Sort nodes by their connections to try to minimize crossing lines
|
|
106
|
-
layerNodes.sort((a, b) => {
|
|
107
|
-
const aConns = connectedTo.get(a)?.size || 0
|
|
108
|
-
const bConns = connectedTo.get(b)?.size || 0
|
|
109
|
-
return bConns - aConns
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
// Position nodes in the layer
|
|
113
|
-
layerNodes.forEach((node, nodeIndex) => {
|
|
114
|
-
// Distribute nodes evenly within their layer
|
|
115
|
-
const row = nodeIndex % GRID.ROWS
|
|
116
|
-
const offset = Math.floor(nodeIndex / GRID.ROWS) * (GRID.HEIGHT / 2)
|
|
117
|
-
|
|
118
|
-
editorInfo.push({
|
|
119
|
-
node,
|
|
120
|
-
position: {
|
|
121
|
-
x: GRID.PADDING + layerIndex * GRID.WIDTH,
|
|
122
|
-
y: GRID.PADDING + row * GRID.HEIGHT + offset,
|
|
123
|
-
},
|
|
124
|
-
points: [],
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
return editorInfo
|
|
130
|
-
}
|