@trioforge/crucible 0.0.0-stage → 0.1.0

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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/client/package.json +4 -0
  3. package/emit/package.json +4 -0
  4. package/out/all.d.ts +7 -0
  5. package/out/all.luau +2 -0
  6. package/out/attribute.d.ts +7 -0
  7. package/out/attribute.luau +7 -0
  8. package/out/client/index.d.ts +3 -0
  9. package/out/client/init.luau +20 -0
  10. package/out/crucible-behaviour.d.ts +16 -0
  11. package/out/crucible-behaviour.luau +78 -0
  12. package/out/crucible-object.d.ts +10 -0
  13. package/out/crucible-object.luau +69 -0
  14. package/out/emit/index.d.ts +41 -0
  15. package/out/emit/init.luau +85 -0
  16. package/out/index.d.ts +12 -0
  17. package/out/init.luau +11 -0
  18. package/out/inject.d.ts +1 -0
  19. package/out/inject.luau +7 -0
  20. package/out/internal/binding.d.ts +1 -0
  21. package/out/internal/binding.luau +610 -0
  22. package/out/internal/boot.d.ts +1 -0
  23. package/out/internal/boot.luau +463 -0
  24. package/out/internal/construction-claim.d.ts +1 -0
  25. package/out/internal/construction-claim.luau +26 -0
  26. package/out/internal/dense-list.d.ts +1 -0
  27. package/out/internal/dense-list.luau +155 -0
  28. package/out/internal/diagnostics.d.ts +1 -0
  29. package/out/internal/diagnostics.luau +29 -0
  30. package/out/internal/hooks.d.ts +1 -0
  31. package/out/internal/hooks.luau +53 -0
  32. package/out/internal/implementers.d.ts +1 -0
  33. package/out/internal/implementers.luau +119 -0
  34. package/out/internal/lifecycle.d.ts +1 -0
  35. package/out/internal/lifecycle.luau +867 -0
  36. package/out/internal/log-output.d.ts +1 -0
  37. package/out/internal/log-output.luau +106 -0
  38. package/out/internal/port.d.ts +1 -0
  39. package/out/internal/port.luau +12 -0
  40. package/out/internal/registry.d.ts +1 -0
  41. package/out/internal/registry.luau +446 -0
  42. package/out/internal/roblox-port.d.ts +1 -0
  43. package/out/internal/roblox-port.luau +117 -0
  44. package/out/internal/runner.d.ts +1 -0
  45. package/out/internal/runner.luau +86 -0
  46. package/out/internal/scheduler.d.ts +1 -0
  47. package/out/internal/scheduler.luau +207 -0
  48. package/out/internal/state.d.ts +1 -0
  49. package/out/internal/state.luau +41 -0
  50. package/out/log-level.d.ts +7 -0
  51. package/out/log-level.luau +21 -0
  52. package/out/logging.d.ts +34 -0
  53. package/out/logging.luau +233 -0
  54. package/out/server/index.d.ts +2 -0
  55. package/out/server/init.luau +16 -0
  56. package/out/subsystem.d.ts +4 -0
  57. package/out/subsystem.luau +30 -0
  58. package/package.json +41 -5
  59. package/server/package.json +4 -0
  60. package/transformer/diagnostics.cjs +19 -0
  61. package/transformer/index.js +715 -0
  62. package/transformer/type-id.cjs +80 -0
  63. package/README.md +0 -3
@@ -0,0 +1,610 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local runtimeDiagnostic = TS.import(script, script.Parent, "diagnostics").runtimeDiagnostic
4
+ local _construction_claim = TS.import(script, script.Parent, "construction-claim")
5
+ local clearClaim = _construction_claim.clearClaim
6
+ local setClaim = _construction_claim.setClaim
7
+ local _lifecycle = TS.import(script, script.Parent, "lifecycle")
8
+ local drain = _lifecycle.drain
9
+ local fault = _lifecycle.fault
10
+ local hasEnded = _lifecycle.hasEnded
11
+ local isDraining = _lifecycle.isDraining
12
+ local isLive = _lifecycle.isLive
13
+ local notePairs = _lifecycle.notePairs
14
+ local request = _lifecycle.request
15
+ local track = _lifecycle.track
16
+ local recordOf = TS.import(script, script.Parent, "registry").recordOf
17
+ local call = TS.import(script, script.Parent, "runner").call
18
+ local installed
19
+ local pairsByRecord = {}
20
+ local wrongClasses = {}
21
+ local byTag = {}
22
+ local queued = {}
23
+ local scheduled = false
24
+ local getWarnings = {}
25
+ local scopeRejected = false
26
+ local scopeTarget
27
+ local function port()
28
+ return installed or error("Crucible binding used before boot")
29
+ end
30
+ --* @internal
31
+ local function useEngine(engine)
32
+ installed = engine
33
+ end
34
+ --* @internal
35
+ local function defaultAccepts(instance)
36
+ local ok = port().bindingScope(instance)
37
+ if not ok and instance == scopeTarget then
38
+ scopeRejected = true
39
+ end
40
+ return ok
41
+ end
42
+ --* @internal
43
+ local function construct(state)
44
+ local record = state.record
45
+ local _exp = record.resolved
46
+ -- ▼ ReadonlyArray.map ▼
47
+ local _newValue = table.create(#_exp)
48
+ local _callback = function(dep)
49
+ local _result
50
+ if dep.all then
51
+ _result = dep.set
52
+ else
53
+ local _result_1 = dep.record.state
54
+ if _result_1 ~= nil then
55
+ _result_1 = _result_1.object
56
+ end
57
+ _result = _result_1
58
+ end
59
+ return _result
60
+ end
61
+ for _k, _v in _exp do
62
+ _newValue[_k] = _callback(_v, _k - 1, _exp)
63
+ end
64
+ -- ▲ ReadonlyArray.map ▲
65
+ local args = _newValue
66
+ local worker
67
+ local result, value = call(function()
68
+ worker = coroutine.running()
69
+ setClaim(state)
70
+ return record.klass.new(unpack(args))
71
+ end, nil, nil, state)
72
+ -- The constructor worker can be cancelled before its own cleanup runs.
73
+ if worker ~= nil then
74
+ clearClaim(worker)
75
+ end
76
+ if result ~= 0 then
77
+ error(value, 0)
78
+ end
79
+ return value
80
+ end
81
+ local function pairFor(record, instance)
82
+ local _record = record
83
+ local instances = pairsByRecord[_record]
84
+ if instances == nil then
85
+ instances = {}
86
+ local _record_1 = record
87
+ local _instances = instances
88
+ pairsByRecord[_record_1] = _instances
89
+ end
90
+ local _instances = instances
91
+ local _instance = instance
92
+ local pair = _instances[_instance]
93
+ if pair == nil then
94
+ local _object = {
95
+ record = record,
96
+ instance = instance,
97
+ queued = false,
98
+ parked = false,
99
+ running = false,
100
+ reset = false,
101
+ rejected = nil,
102
+ }
103
+ local _left = "wrongClass"
104
+ local _record_1 = record
105
+ local _result = wrongClasses[_record_1]
106
+ if _result ~= nil then
107
+ local _instance_1 = instance
108
+ _result = _result[_instance_1] ~= nil
109
+ end
110
+ local _condition = _result
111
+ if _condition == nil then
112
+ _condition = false
113
+ end
114
+ _object[_left] = _condition
115
+ _object.warnings = {}
116
+ pair = _object
117
+ local _instances_1 = instances
118
+ local _instance_1 = instance
119
+ local _pair = pair
120
+ _instances_1[_instance_1] = _pair
121
+ end
122
+ return pair
123
+ end
124
+ local function queue(pair)
125
+ if pair.running then
126
+ return nil
127
+ end
128
+ if pair.rejected == "accepts" then
129
+ pair.rejected = nil
130
+ end
131
+ if pair.parked then
132
+ pair.parked = false
133
+ pair.queued = false
134
+ end
135
+ if not pair.queued then
136
+ pair.queued = true
137
+ local _queued = queued
138
+ local _pair = pair
139
+ table.insert(_queued, _pair)
140
+ end
141
+ notePairs()
142
+ end
143
+ local function schedule()
144
+ if scheduled then
145
+ return nil
146
+ end
147
+ scheduled = true
148
+ port().defer(function()
149
+ scheduled = false
150
+ drain()
151
+ end)
152
+ end
153
+ local function disconnect(pair)
154
+ local connections = pair.connections
155
+ pair.connections = nil
156
+ if connections ~= nil then
157
+ for _, stop in connections do
158
+ stop()
159
+ end
160
+ end
161
+ end
162
+ local function warning(pair, field, condition, message)
163
+ local _warnings = pair.warnings
164
+ local _field = field
165
+ if _warnings[_field] == condition then
166
+ return nil
167
+ end
168
+ local _warnings_1 = pair.warnings
169
+ local _field_1 = field
170
+ local _condition = condition
171
+ _warnings_1[_field_1] = _condition
172
+ runtimeDiagnostic("warning", message)
173
+ end
174
+ local function valueFor(pair, field, state)
175
+ local _descriptor = pair.record.attributes
176
+ if _descriptor ~= nil then
177
+ local _field = field
178
+ _descriptor = _descriptor[_field]
179
+ end
180
+ local descriptor = _descriptor
181
+ if descriptor == nil then
182
+ return true, nil
183
+ end
184
+ local value = port().getAttribute(pair.instance, descriptor.name)
185
+ local valid = if value == nil then not descriptor.required else descriptor.check(value)
186
+ if valid then
187
+ local _warnings = pair.warnings
188
+ local _field = field
189
+ _warnings[_field] = nil
190
+ return true, value
191
+ end
192
+ local condition = typeof(value)
193
+ warning(pair, field, condition, `{pair.record.id} on {port().describe(pair.instance)}: attribute {descriptor.name} is invalid ({condition}); {if state == nil then "not bound" else "keeping the last valid value"}`)
194
+ return false, value
195
+ end
196
+ --* @internal
197
+ local function applyAttribute(state, field)
198
+ local record = state.record
199
+ if record.kind ~= 1 or state.instance == nil or state.attributes == nil then
200
+ return nil
201
+ end
202
+ local pair = pairFor(record, state.instance)
203
+ local valid, value = valueFor(pair, field, state)
204
+ if not valid then
205
+ return nil
206
+ end
207
+ state.attributes[field] = value
208
+ if state.object ~= nil then
209
+ (state.object)[field] = value
210
+ end
211
+ end
212
+ local reset
213
+ local function connect(pair)
214
+ if pair.connections ~= nil then
215
+ return nil
216
+ end
217
+ local _binding = pair
218
+ local record = _binding.record
219
+ local instance = _binding.instance
220
+ pair.connections = { port().onAncestryChanged(instance, function()
221
+ if not port().inWorld(instance) then
222
+ reset(pair)
223
+ end
224
+ queue(pair)
225
+ schedule()
226
+ end) }
227
+ for field, descriptor in record.attributes or {} do
228
+ local _connections = pair.connections
229
+ local _arg0 = port().onAttributeChanged(instance, descriptor.name, function()
230
+ local state = record.bound[instance]
231
+ if state ~= nil and not hasEnded(state) then
232
+ applyAttribute(state, field)
233
+ else
234
+ queue(pair)
235
+ schedule()
236
+ end
237
+ end)
238
+ table.insert(_connections, _arg0)
239
+ end
240
+ local state = record.bound[instance]
241
+ if state ~= nil then
242
+ for field in record.attributes or {} do
243
+ applyAttribute(state, field)
244
+ end
245
+ end
246
+ end
247
+ function reset(pair)
248
+ pair.reset = true
249
+ local _suppressed = pair.record.suppressed
250
+ local _instance = pair.instance
251
+ _suppressed[_instance] = nil
252
+ table.clear(pair.warnings)
253
+ disconnect(pair)
254
+ end
255
+ local function callAccepts(klass, instance)
256
+ return klass:accepts(instance)
257
+ end
258
+ local function accepted(pair, state)
259
+ local result, value = call(callAccepts, pair.record.klass, pair.instance, state)
260
+ if result == 0 then
261
+ return value == true
262
+ end
263
+ local _suppressed = pair.record.suppressed
264
+ local _instance = pair.instance
265
+ _suppressed[_instance] = true
266
+ if state ~= nil then
267
+ fault(state, 7, value)
268
+ else
269
+ runtimeDiagnostic("error", `{pair.record.id}.accepts failed on {port().describe(pair.instance)}: {value}`)
270
+ end
271
+ return false
272
+ end
273
+ local function evaluate(pair)
274
+ local _binding = pair
275
+ local record = _binding.record
276
+ local instance = _binding.instance
277
+ local engine = port()
278
+ pair.rejected = nil
279
+ local present = engine.inWorld(instance) and engine.hasTag(instance, record.tag)
280
+ if not present then
281
+ reset(pair)
282
+ end
283
+ local have = record.bound[instance]
284
+ if have ~= nil then
285
+ if present then
286
+ connect(pair)
287
+ end
288
+ if pair.reset or not present or record.suppressed[instance] ~= nil then
289
+ request(have, 2)
290
+ return nil
291
+ end
292
+ scopeRejected = false
293
+ scopeTarget = instance
294
+ local ok = accepted(pair, have)
295
+ if not ok then
296
+ pair.rejected = if scopeRejected then "scope" else "accepts"
297
+ end
298
+ if not ok or pair.reset or not engine.inWorld(instance) or not engine.hasTag(instance, record.tag) or record.suppressed[instance] ~= nil then
299
+ request(have, 2)
300
+ end
301
+ return nil
302
+ end
303
+ if pair.reset then
304
+ pair.reset = false
305
+ record.suppressed[instance] = nil
306
+ end
307
+ if not present then
308
+ local _result = pairsByRecord[record]
309
+ if _result ~= nil then
310
+ _result[instance] = nil
311
+ end
312
+ return nil
313
+ end
314
+ connect(pair)
315
+ if record.suppressed[instance] ~= nil then
316
+ return nil
317
+ end
318
+ local _exp = record.instanceClasses
319
+ -- ▼ ReadonlyArray.some ▼
320
+ local _result = false
321
+ local _callback = function(name)
322
+ return engine.isA(instance, name)
323
+ end
324
+ for _k, _v in _exp do
325
+ if _callback(_v, _k - 1, _exp) then
326
+ _result = true
327
+ break
328
+ end
329
+ end
330
+ -- ▲ ReadonlyArray.some ▲
331
+ if not _result then
332
+ pair.rejected = "class"
333
+ if not pair.wrongClass then
334
+ pair.wrongClass = true
335
+ local warned = wrongClasses[record]
336
+ if warned == nil then
337
+ warned = setmetatable({}, {
338
+ __mode = "k",
339
+ })
340
+ local _warned = warned
341
+ wrongClasses[record] = _warned
342
+ end
343
+ warned[instance] = true
344
+ local _exp_1 = string.split(record.id, ":")
345
+ -- ▼ Array.pop ▼
346
+ local _length = #_exp_1
347
+ local _result_1 = _exp_1[_length]
348
+ _exp_1[_length] = nil
349
+ -- ▲ Array.pop ▲
350
+ local _condition = _result_1
351
+ if _condition == nil then
352
+ _condition = record.id
353
+ end
354
+ local className = _condition
355
+ runtimeDiagnostic("warning", `{engine.describe(instance)} is a {instance.ClassName}; {className} needs a {table.concat(record.instanceClasses, " or ")}`)
356
+ end
357
+ return nil
358
+ end
359
+ local attributes = {}
360
+ local valid = true
361
+ for field in record.attributes or {} do
362
+ local ok, value = valueFor(pair, field)
363
+ if not ok then
364
+ valid = false
365
+ end
366
+ attributes[field] = value
367
+ end
368
+ if not valid then
369
+ pair.rejected = "attributes"
370
+ return nil
371
+ end
372
+ scopeRejected = false
373
+ scopeTarget = instance
374
+ if not accepted(pair) then
375
+ pair.rejected = if scopeRejected then "scope" else "accepts"
376
+ return nil
377
+ end
378
+ if pair.reset or not engine.inWorld(instance) or not engine.hasTag(instance, record.tag) or record.suppressed[instance] ~= nil then
379
+ return nil
380
+ end
381
+ local state = track(record, instance, attributes)
382
+ record.bound[instance] = state
383
+ return state
384
+ end
385
+ --* @internal
386
+ local function reconcile()
387
+ local taken = queued
388
+ queued = {}
389
+ local created = {}
390
+ for _, pair in taken do
391
+ pair.queued = false
392
+ pair.running = true
393
+ local state = evaluate(pair)
394
+ pair.running = false
395
+ local _condition = pair.reset
396
+ if _condition then
397
+ local _bound = pair.record.bound
398
+ local _instance = pair.instance
399
+ _condition = not (_bound[_instance] ~= nil)
400
+ end
401
+ if _condition then
402
+ queue(pair)
403
+ end
404
+ if state ~= nil then
405
+ table.insert(created, state)
406
+ end
407
+ end
408
+ return created
409
+ end
410
+ --* @internal
411
+ local function watch(records)
412
+ local connections = {}
413
+ for _, record in records do
414
+ local _tag = record.tag
415
+ local list = byTag[_tag]
416
+ if list == nil then
417
+ local _tag_1 = record.tag
418
+ local _arg1 = { record }
419
+ byTag[_tag_1] = _arg1
420
+ else
421
+ table.insert(list, record)
422
+ end
423
+ end
424
+ for tag, records in byTag do
425
+ local _arg0 = port().onTagAdded(tag, function(instance)
426
+ for _, record in records do
427
+ queue(pairFor(record, instance))
428
+ end
429
+ schedule()
430
+ end)
431
+ table.insert(connections, _arg0)
432
+ local _arg0_1 = port().onTagRemoved(tag, function(instance)
433
+ for _, record in records do
434
+ local pair = pairFor(record, instance)
435
+ reset(pair)
436
+ queue(pair)
437
+ end
438
+ schedule()
439
+ end)
440
+ table.insert(connections, _arg0_1)
441
+ for _, instance in port().tagged(tag) do
442
+ for _1, record in records do
443
+ queue(pairFor(record, instance))
444
+ end
445
+ end
446
+ end
447
+ return function()
448
+ for _, stop in connections do
449
+ stop()
450
+ end
451
+ for _, instances in pairsByRecord do
452
+ for _1, pair in instances do
453
+ disconnect(pair)
454
+ end
455
+ end
456
+ table.clear(byTag)
457
+ end
458
+ end
459
+ --* @internal
460
+ local function refresh(instance)
461
+ for tag, records in byTag do
462
+ for _, record in records do
463
+ local _condition = port().hasTag(instance, tag)
464
+ if not _condition then
465
+ local _bound = record.bound
466
+ local _instance = instance
467
+ _condition = _bound[_instance] ~= nil
468
+ end
469
+ if _condition then
470
+ queue(pairFor(record, instance))
471
+ end
472
+ end
473
+ end
474
+ drain()
475
+ end
476
+ --* @internal
477
+ local function boundTo(klass, instance)
478
+ local record = recordOf(klass)
479
+ if record == nil or record.kind ~= 1 then
480
+ return nil
481
+ end
482
+ local pair = pairFor(record, instance)
483
+ if isDraining() then
484
+ local _bound = record.bound
485
+ local _instance = instance
486
+ local state = _bound[_instance]
487
+ local attributesValid = true
488
+ if pair.rejected == "attributes" then
489
+ for _, descriptor in record.attributes or {} do
490
+ local value = port().getAttribute(instance, descriptor.name)
491
+ if if value == nil then descriptor.required else not descriptor.check(value) then
492
+ attributesValid = false
493
+ end
494
+ end
495
+ end
496
+ local _condition = (state == nil or not isLive(state)) and (pair.rejected == nil or (pair.rejected == "attributes" and attributesValid) or (pair.rejected == "scope" and port().bindingScope(instance))) and port().inWorld(instance) and port().hasTag(instance, record.tag)
497
+ if _condition then
498
+ local _suppressed = record.suppressed
499
+ local _instance_1 = instance
500
+ _condition = not (_suppressed[_instance_1] ~= nil)
501
+ end
502
+ if _condition then
503
+ local source, line = debug.info(3, "sl")
504
+ local site = `{source}:{line}`
505
+ if not (getWarnings[site] ~= nil) then
506
+ getWarnings[site] = true
507
+ runtimeDiagnostic("warning", `Crucible get pending at {site}`)
508
+ end
509
+ end
510
+ local rejected = pair.rejected
511
+ queue(pair)
512
+ pair.rejected = rejected
513
+ else
514
+ queue(pair)
515
+ -- ▼ ReadonlyArray.filter ▼
516
+ local _newValue = {}
517
+ local _callback = function(other)
518
+ return other ~= pair
519
+ end
520
+ local _length = 0
521
+ for _k, _v in queued do
522
+ if _callback(_v, _k - 1, queued) == true then
523
+ _length += 1
524
+ _newValue[_length] = _v
525
+ end
526
+ end
527
+ -- ▲ ReadonlyArray.filter ▲
528
+ local held = _newValue
529
+ for _, other in held do
530
+ other.parked = true
531
+ end
532
+ queued = { pair }
533
+ drain()
534
+ local _array = {}
535
+ local _length_1 = #_array
536
+ -- ▼ ReadonlyArray.filter ▼
537
+ local _newValue_1 = {}
538
+ local _callback_1 = function(other)
539
+ return other.parked
540
+ end
541
+ local _length_2 = 0
542
+ for _k, _v in held do
543
+ if _callback_1(_v, _k - 1, held) == true then
544
+ _length_2 += 1
545
+ _newValue_1[_length_2] = _v
546
+ end
547
+ end
548
+ -- ▲ ReadonlyArray.filter ▲
549
+ local _Length = #_newValue_1
550
+ table.move(_newValue_1, 1, _Length, _length_1 + 1, _array)
551
+ _length_1 += _Length
552
+ table.move(queued, 1, #queued, _length_1 + 1, _array)
553
+ queued = _array
554
+ for _, other in held do
555
+ other.parked = false
556
+ end
557
+ if #queued > 0 then
558
+ notePairs()
559
+ schedule()
560
+ end
561
+ end
562
+ local _bound = record.bound
563
+ local _instance = instance
564
+ return _bound[_instance]
565
+ end
566
+ --* @internal
567
+ local function remove(state)
568
+ local record = state.record
569
+ if record.kind == 1 and state.instance ~= nil and not hasEnded(state) then
570
+ local _suppressed = record.suppressed
571
+ local _instance = state.instance
572
+ _suppressed[_instance] = true
573
+ end
574
+ request(state, 2)
575
+ end
576
+ --* @internal
577
+ local function forget(state)
578
+ local record = state.record
579
+ if record.kind ~= 1 or state.instance == nil then
580
+ return nil
581
+ end
582
+ local _bound = record.bound
583
+ local _instance = state.instance
584
+ if _bound[_instance] == state then
585
+ local _bound_1 = record.bound
586
+ local _instance_1 = state.instance
587
+ _bound_1[_instance_1] = nil
588
+ end
589
+ local pair = pairFor(record, state.instance)
590
+ if state.phase == 5 and not pair.reset then
591
+ local _suppressed = record.suppressed
592
+ local _instance_1 = state.instance
593
+ _suppressed[_instance_1] = true
594
+ end
595
+ if pair.reset then
596
+ queue(pair)
597
+ end
598
+ end
599
+ return {
600
+ useEngine = useEngine,
601
+ defaultAccepts = defaultAccepts,
602
+ construct = construct,
603
+ applyAttribute = applyAttribute,
604
+ reconcile = reconcile,
605
+ watch = watch,
606
+ refresh = refresh,
607
+ boundTo = boundTo,
608
+ remove = remove,
609
+ forget = forget,
610
+ }
@@ -0,0 +1 @@
1
+ export {};