@api-client/core 0.18.16 → 0.18.18
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/build/src/{modeling → decorators}/observed.d.ts +3 -3
- package/build/src/decorators/observed.d.ts.map +1 -0
- package/build/src/{modeling → decorators}/observed.js +4 -4
- package/build/src/decorators/observed.js.map +1 -0
- package/build/src/modeling/ApiModel.js +1 -1
- package/build/src/modeling/ApiModel.js.map +1 -1
- package/build/src/modeling/DataDomain.d.ts +7 -2
- package/build/src/modeling/DataDomain.d.ts.map +1 -1
- package/build/src/modeling/DataDomain.js +15 -2
- package/build/src/modeling/DataDomain.js.map +1 -1
- package/build/src/modeling/DomainAssociation.d.ts +7 -0
- package/build/src/modeling/DomainAssociation.d.ts.map +1 -1
- package/build/src/modeling/DomainAssociation.js +44 -1
- package/build/src/modeling/DomainAssociation.js.map +1 -1
- package/build/src/modeling/DomainEntity.d.ts +6 -0
- package/build/src/modeling/DomainEntity.d.ts.map +1 -1
- package/build/src/modeling/DomainEntity.js +21 -1
- package/build/src/modeling/DomainEntity.js.map +1 -1
- package/build/src/modeling/DomainModel.js +1 -1
- package/build/src/modeling/DomainModel.js.map +1 -1
- package/build/src/modeling/DomainNamespace.js +1 -1
- package/build/src/modeling/DomainNamespace.js.map +1 -1
- package/build/src/modeling/DomainProperty.d.ts +5 -0
- package/build/src/modeling/DomainProperty.d.ts.map +1 -1
- package/build/src/modeling/DomainProperty.js +38 -1
- package/build/src/modeling/DomainProperty.js.map +1 -1
- package/build/src/modeling/DomainSerialization.d.ts +6 -3
- package/build/src/modeling/DomainSerialization.d.ts.map +1 -1
- package/build/src/modeling/DomainSerialization.js +374 -52
- package/build/src/modeling/DomainSerialization.js.map +1 -1
- package/build/src/modeling/types.d.ts +69 -2
- package/build/src/modeling/types.d.ts.map +1 -1
- package/build/src/modeling/types.js.map +1 -1
- package/build/src/models/Thing.js +1 -1
- package/build/src/models/Thing.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/data/models/example-generator-api.json +10 -10
- package/package.json +2 -1
- package/src/{modeling → decorators}/observed.ts +5 -5
- package/src/modeling/ApiModel.ts +1 -1
- package/src/modeling/DataDomain.ts +24 -3
- package/src/modeling/DomainAssociation.ts +51 -1
- package/src/modeling/DomainEntity.ts +24 -1
- package/src/modeling/DomainModel.ts +1 -1
- package/src/modeling/DomainNamespace.ts +1 -1
- package/src/modeling/DomainProperty.ts +43 -1
- package/src/modeling/DomainSerialization.ts +440 -56
- package/src/modeling/types.ts +73 -2
- package/src/models/Thing.ts +1 -1
- package/tests/unit/decorators/observed.spec.ts +527 -0
- package/tests/unit/modeling/data_domain_serialization.spec.ts +508 -0
- package/tests/unit/modeling/domain_asociation.spec.ts +376 -0
- package/tests/unit/modeling/domain_entity.spec.ts +147 -0
- package/tests/unit/modeling/domain_property.spec.ts +273 -0
- package/build/src/modeling/observed.d.ts.map +0 -1
- package/build/src/modeling/observed.js.map +0 -1
|
@@ -1377,3 +1377,276 @@ test.group('DomainProperty.toExample()', () => {
|
|
|
1377
1377
|
assert.match(result as string, emailRegex)
|
|
1378
1378
|
})
|
|
1379
1379
|
})
|
|
1380
|
+
|
|
1381
|
+
test.group('DomainProperty.duplicate()', () => {
|
|
1382
|
+
test('duplicates a property successfully', ({ assert }) => {
|
|
1383
|
+
const dataDomain = new DataDomain()
|
|
1384
|
+
const model = dataDomain.addModel()
|
|
1385
|
+
const entity = model.addEntity()
|
|
1386
|
+
const property = entity.addProperty({
|
|
1387
|
+
info: { name: 'originalProperty' },
|
|
1388
|
+
type: 'string',
|
|
1389
|
+
required: true,
|
|
1390
|
+
multiple: false,
|
|
1391
|
+
})
|
|
1392
|
+
|
|
1393
|
+
const duplicate = property.duplicate()
|
|
1394
|
+
|
|
1395
|
+
assert.isDefined(duplicate)
|
|
1396
|
+
assert.notEqual(duplicate.key, property.key)
|
|
1397
|
+
assert.equal(duplicate.info.name, 'originalProperty_copy')
|
|
1398
|
+
assert.equal(duplicate.type, 'string')
|
|
1399
|
+
assert.equal(duplicate.required, true)
|
|
1400
|
+
assert.equal(duplicate.multiple, false)
|
|
1401
|
+
})
|
|
1402
|
+
|
|
1403
|
+
test('places duplicate right after original property in fields list', ({ assert }) => {
|
|
1404
|
+
const dataDomain = new DataDomain()
|
|
1405
|
+
const model = dataDomain.addModel()
|
|
1406
|
+
const entity = model.addEntity()
|
|
1407
|
+
|
|
1408
|
+
// Add multiple properties to test ordering
|
|
1409
|
+
const property1 = entity.addProperty({ info: { name: 'first' } })
|
|
1410
|
+
const property2 = entity.addProperty({ info: { name: 'second' } })
|
|
1411
|
+
const property3 = entity.addProperty({ info: { name: 'third' } })
|
|
1412
|
+
|
|
1413
|
+
const duplicate = property2.duplicate()
|
|
1414
|
+
|
|
1415
|
+
// Check that duplicate is placed right after property2
|
|
1416
|
+
const fieldKeys = entity.fields.map((f) => f.key)
|
|
1417
|
+
const property2Index = fieldKeys.indexOf(property2.key)
|
|
1418
|
+
const duplicateIndex = fieldKeys.indexOf(duplicate.key)
|
|
1419
|
+
|
|
1420
|
+
assert.equal(duplicateIndex, property2Index + 1)
|
|
1421
|
+
assert.deepEqual(fieldKeys, [property1.key, property2.key, duplicate.key, property3.key])
|
|
1422
|
+
})
|
|
1423
|
+
|
|
1424
|
+
test('generates unique name when base name conflicts', ({ assert }) => {
|
|
1425
|
+
const dataDomain = new DataDomain()
|
|
1426
|
+
const model = dataDomain.addModel()
|
|
1427
|
+
const entity = model.addEntity()
|
|
1428
|
+
|
|
1429
|
+
const property = entity.addProperty({ info: { name: 'test' } })
|
|
1430
|
+
// Add a property that conflicts with the first generated name
|
|
1431
|
+
entity.addProperty({ info: { name: 'test_copy' } })
|
|
1432
|
+
|
|
1433
|
+
const duplicate = property.duplicate()
|
|
1434
|
+
|
|
1435
|
+
assert.equal(duplicate.info.name, 'test_copy_2')
|
|
1436
|
+
})
|
|
1437
|
+
|
|
1438
|
+
test('uses fallback name when original property has no name', ({ assert }) => {
|
|
1439
|
+
const dataDomain = new DataDomain()
|
|
1440
|
+
const model = dataDomain.addModel()
|
|
1441
|
+
const entity = model.addEntity()
|
|
1442
|
+
|
|
1443
|
+
const property = entity.addProperty({ info: {} }) // No name
|
|
1444
|
+
|
|
1445
|
+
// The property gets the default name "new_property" from schema creation
|
|
1446
|
+
assert.equal(property.info.name, 'new_property')
|
|
1447
|
+
|
|
1448
|
+
const duplicate = property.duplicate()
|
|
1449
|
+
|
|
1450
|
+
assert.equal(duplicate.info.name, 'new_property_copy')
|
|
1451
|
+
})
|
|
1452
|
+
|
|
1453
|
+
test('uses field fallback when property name is explicitly undefined', ({ assert }) => {
|
|
1454
|
+
const dataDomain = new DataDomain()
|
|
1455
|
+
const model = dataDomain.addModel()
|
|
1456
|
+
const entity = model.addEntity()
|
|
1457
|
+
|
|
1458
|
+
const property = entity.addProperty({ info: { name: 'test' } })
|
|
1459
|
+
// Manually set name to undefined to test the fallback logic
|
|
1460
|
+
property.info.name = undefined
|
|
1461
|
+
|
|
1462
|
+
const duplicate = property.duplicate()
|
|
1463
|
+
|
|
1464
|
+
assert.equal(duplicate.info.name, 'field_copy')
|
|
1465
|
+
})
|
|
1466
|
+
|
|
1467
|
+
test('does not copy key property', ({ assert }) => {
|
|
1468
|
+
const dataDomain = new DataDomain()
|
|
1469
|
+
const model = dataDomain.addModel()
|
|
1470
|
+
const entity = model.addEntity()
|
|
1471
|
+
|
|
1472
|
+
const property = entity.addProperty({
|
|
1473
|
+
key: 'custom-key',
|
|
1474
|
+
info: { name: 'testProperty' },
|
|
1475
|
+
})
|
|
1476
|
+
|
|
1477
|
+
const duplicate = property.duplicate()
|
|
1478
|
+
|
|
1479
|
+
assert.notEqual(duplicate.key, property.key)
|
|
1480
|
+
assert.notEqual(duplicate.key, 'custom-key')
|
|
1481
|
+
})
|
|
1482
|
+
|
|
1483
|
+
test('does not copy primary key flag', ({ assert }) => {
|
|
1484
|
+
const dataDomain = new DataDomain()
|
|
1485
|
+
const model = dataDomain.addModel()
|
|
1486
|
+
const entity = model.addEntity()
|
|
1487
|
+
|
|
1488
|
+
const property = entity.addProperty({
|
|
1489
|
+
info: { name: 'id' },
|
|
1490
|
+
primary: true,
|
|
1491
|
+
})
|
|
1492
|
+
|
|
1493
|
+
const duplicate = property.duplicate()
|
|
1494
|
+
|
|
1495
|
+
assert.isTrue(property.primary)
|
|
1496
|
+
assert.isUndefined(duplicate.primary)
|
|
1497
|
+
})
|
|
1498
|
+
|
|
1499
|
+
test('copies all other property attributes', ({ assert }) => {
|
|
1500
|
+
const dataDomain = new DataDomain()
|
|
1501
|
+
const model = dataDomain.addModel()
|
|
1502
|
+
const entity = model.addEntity()
|
|
1503
|
+
|
|
1504
|
+
const property = entity.addProperty({
|
|
1505
|
+
info: { name: 'complexProperty', description: 'A complex property' },
|
|
1506
|
+
type: 'number',
|
|
1507
|
+
required: true,
|
|
1508
|
+
multiple: true,
|
|
1509
|
+
index: true,
|
|
1510
|
+
readOnly: true,
|
|
1511
|
+
writeOnly: false,
|
|
1512
|
+
deprecated: true,
|
|
1513
|
+
tags: ['tag1', 'tag2'],
|
|
1514
|
+
semantics: [{ id: SemanticType.CreatedTimestamp }],
|
|
1515
|
+
schema: { minimum: 0, maximum: 100 },
|
|
1516
|
+
bindings: [{ type: 'web', schema: { format: 'float' } }],
|
|
1517
|
+
})
|
|
1518
|
+
|
|
1519
|
+
const duplicate = property.duplicate()
|
|
1520
|
+
|
|
1521
|
+
assert.equal(duplicate.info.name, 'complexProperty_copy')
|
|
1522
|
+
assert.equal(duplicate.info.description, 'A complex property')
|
|
1523
|
+
assert.equal(duplicate.type, 'number')
|
|
1524
|
+
assert.equal(duplicate.required, true)
|
|
1525
|
+
assert.equal(duplicate.multiple, true)
|
|
1526
|
+
assert.equal(duplicate.index, true)
|
|
1527
|
+
assert.equal(duplicate.readOnly, true)
|
|
1528
|
+
assert.equal(duplicate.writeOnly, false)
|
|
1529
|
+
assert.equal(duplicate.deprecated, true)
|
|
1530
|
+
assert.deepEqual(duplicate.tags, ['tag1', 'tag2'])
|
|
1531
|
+
assert.deepEqual(duplicate.semantics, [{ id: SemanticType.CreatedTimestamp }])
|
|
1532
|
+
assert.deepEqual(duplicate.schema, { minimum: 0, maximum: 100 })
|
|
1533
|
+
assert.deepEqual(duplicate.bindings, [{ type: 'web', schema: { format: 'float' } }])
|
|
1534
|
+
})
|
|
1535
|
+
|
|
1536
|
+
test('creates independent copy of schema and bindings', ({ assert }) => {
|
|
1537
|
+
const dataDomain = new DataDomain()
|
|
1538
|
+
const model = dataDomain.addModel()
|
|
1539
|
+
const entity = model.addEntity()
|
|
1540
|
+
|
|
1541
|
+
const property = entity.addProperty({
|
|
1542
|
+
info: { name: 'original' },
|
|
1543
|
+
schema: { minimum: 0 },
|
|
1544
|
+
bindings: [{ type: 'web', schema: { format: 'float' } }],
|
|
1545
|
+
})
|
|
1546
|
+
|
|
1547
|
+
const duplicate = property.duplicate()
|
|
1548
|
+
|
|
1549
|
+
// Modify original schema and bindings
|
|
1550
|
+
property.schema!.minimum = 10
|
|
1551
|
+
property.bindings[0].schema = { format: 'double' }
|
|
1552
|
+
|
|
1553
|
+
// Duplicate should be unaffected
|
|
1554
|
+
assert.equal(duplicate.schema!.minimum, 0)
|
|
1555
|
+
assert.deepEqual(duplicate.bindings[0].schema, { format: 'float' })
|
|
1556
|
+
})
|
|
1557
|
+
|
|
1558
|
+
test('notifies domain of changes', ({ assert }) => {
|
|
1559
|
+
const dataDomain = new DataDomain()
|
|
1560
|
+
const model = dataDomain.addModel()
|
|
1561
|
+
const entity = model.addEntity()
|
|
1562
|
+
const property = entity.addProperty({ info: { name: 'test' } })
|
|
1563
|
+
|
|
1564
|
+
let notificationCalled = false
|
|
1565
|
+
const originalNotify = dataDomain.notifyChange
|
|
1566
|
+
dataDomain.notifyChange = () => {
|
|
1567
|
+
notificationCalled = true
|
|
1568
|
+
originalNotify.call(dataDomain)
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
property.duplicate()
|
|
1572
|
+
|
|
1573
|
+
assert.isTrue(notificationCalled)
|
|
1574
|
+
|
|
1575
|
+
// Restore original method
|
|
1576
|
+
dataDomain.notifyChange = originalNotify
|
|
1577
|
+
})
|
|
1578
|
+
|
|
1579
|
+
test('throws error when property has no parent entity', ({ assert }) => {
|
|
1580
|
+
const dataDomain = new DataDomain()
|
|
1581
|
+
const property = new DomainProperty(dataDomain, 'non-existent-parent', {
|
|
1582
|
+
info: { name: 'orphan' },
|
|
1583
|
+
})
|
|
1584
|
+
|
|
1585
|
+
assert.throws(() => {
|
|
1586
|
+
property.duplicate()
|
|
1587
|
+
}, 'Cannot duplicate property')
|
|
1588
|
+
})
|
|
1589
|
+
|
|
1590
|
+
test('throws error when property is not in parent entity fields list', ({ assert }) => {
|
|
1591
|
+
const dataDomain = new DataDomain()
|
|
1592
|
+
const model = dataDomain.addModel()
|
|
1593
|
+
const entity = model.addEntity()
|
|
1594
|
+
const property = new DomainProperty(dataDomain, entity.key, {
|
|
1595
|
+
info: { name: 'detached' },
|
|
1596
|
+
})
|
|
1597
|
+
|
|
1598
|
+
// Add property to graph but not to entity fields
|
|
1599
|
+
dataDomain.graph.setNode(property.key, property)
|
|
1600
|
+
|
|
1601
|
+
assert.throws(() => {
|
|
1602
|
+
property.duplicate()
|
|
1603
|
+
}, 'does not exist on the parent entity fields list')
|
|
1604
|
+
})
|
|
1605
|
+
|
|
1606
|
+
test('works with empty entity fields list', ({ assert }) => {
|
|
1607
|
+
const dataDomain = new DataDomain()
|
|
1608
|
+
const model = dataDomain.addModel()
|
|
1609
|
+
const entity = model.addEntity()
|
|
1610
|
+
const property = entity.addProperty({ info: { name: 'only' } })
|
|
1611
|
+
|
|
1612
|
+
const duplicate = property.duplicate()
|
|
1613
|
+
|
|
1614
|
+
assert.equal(entity.fields.length, 2)
|
|
1615
|
+
assert.equal(entity.fields[0].key, property.key)
|
|
1616
|
+
assert.equal(entity.fields[1].key, duplicate.key)
|
|
1617
|
+
})
|
|
1618
|
+
|
|
1619
|
+
test('handles duplication of property with associations in between', ({ assert }) => {
|
|
1620
|
+
const dataDomain = new DataDomain()
|
|
1621
|
+
const model = dataDomain.addModel()
|
|
1622
|
+
const entity = model.addEntity()
|
|
1623
|
+
const targetEntity = model.addEntity()
|
|
1624
|
+
|
|
1625
|
+
const property1 = entity.addProperty({ info: { name: 'prop1' } })
|
|
1626
|
+
const association = entity.addAssociation({ key: targetEntity.key })
|
|
1627
|
+
association.info.name = 'assoc1'
|
|
1628
|
+
const property2 = entity.addProperty({ info: { name: 'prop2' } })
|
|
1629
|
+
|
|
1630
|
+
const duplicate = property1.duplicate()
|
|
1631
|
+
|
|
1632
|
+
// Should maintain correct order
|
|
1633
|
+
const fieldKeys = entity.fields.map((f) => f.key)
|
|
1634
|
+
assert.deepEqual(fieldKeys, [property1.key, duplicate.key, association.key, property2.key])
|
|
1635
|
+
})
|
|
1636
|
+
|
|
1637
|
+
test('preserves field types correctly', ({ assert }) => {
|
|
1638
|
+
const dataDomain = new DataDomain()
|
|
1639
|
+
const model = dataDomain.addModel()
|
|
1640
|
+
const entity = model.addEntity()
|
|
1641
|
+
const property = entity.addProperty({ info: { name: 'test' } })
|
|
1642
|
+
|
|
1643
|
+
const duplicate = property.duplicate()
|
|
1644
|
+
|
|
1645
|
+
// Check that both original and duplicate have correct field type
|
|
1646
|
+
const originalField = entity.fields.find((f) => f.key === property.key)
|
|
1647
|
+
const duplicateField = entity.fields.find((f) => f.key === duplicate.key)
|
|
1648
|
+
|
|
1649
|
+
assert.equal(originalField?.type, 'property')
|
|
1650
|
+
assert.equal(duplicateField?.type, 'property')
|
|
1651
|
+
})
|
|
1652
|
+
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observed.d.ts","sourceRoot":"","sources":["../../../src/modeling/observed.ts"],"names":[],"mappings":"AAIA,UAAU,cAAc;IACtB,MAAM,CAAC,EAAE;QAAE,YAAY,IAAI,IAAI,CAAA;KAAE,CAAA;IACjC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAEhC,CAAC,CAAC,SAAS,cAAc,EAAE,CAAC,EAC1B,MAAM,EAAE,4BAA4B,CAAC,CAAC,EAAE,CAAC,CAAC,EAC1C,OAAO,EAAE,6BAA6B,CAAC,CAAC,EAAE,CAAC,CAAC,GAC3C,4BAA4B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAErC,CAAC,CAAC,SAAS,cAAc,EAAE,CAAC,EAC1B,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,EAC1B,OAAO,EAAE,2BAA2B,CAAC,CAAC,EAAE,CAAC,CAAC,GACzC,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,IAAI,CAAA;CAC/B;AAED,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,IAAI,6BAA6B,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,2BAA2B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAC5G,KAAK,sBAAsB,CAAC,CAAC,EAAE,CAAC,IAAI,4BAA4B,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC,CAAA;AAE7F,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;;;;GAKG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAUzF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,QAAQ,CAAC,MAAM,GAAE,aAAkB,GAAG,iBAAiB,CA2GtE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,KACpB,CAAC,SAAS,cAAc,EAAE,CAAC,SAAS,WAAW,EACrD,QAAQ,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,EACpC,SAAS,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC,KACrC,GAAG,CAiEP"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"observed.js","sourceRoot":"","sources":["../../../src/modeling/observed.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nconst reactiveSymbol = Symbol('reactive')\nconst proxySymbol = Symbol('proxy')\n\ninterface DomainInstance {\n domain?: { notifyChange(): void }\n notifyChange?: () => void\n}\n\nexport interface PropertyDecorator {\n // accessor decorator signature\n <C extends DomainInstance, V>(\n target: ClassAccessorDecoratorTarget<C, V>,\n context: ClassAccessorDecoratorContext<C, V>\n ): ClassAccessorDecoratorResult<C, V>\n // setter decorator signature\n <C extends DomainInstance, V>(\n target: (value: V) => void,\n context: ClassSetterDecoratorContext<C, V>\n ): (this: C, value: V) => void\n}\n\ntype StandardPropertyContext<C, V> = ClassAccessorDecoratorContext<C, V> | ClassSetterDecoratorContext<C, V>\ntype StandardPropertyTarget<C, V> = ClassAccessorDecoratorTarget<C, V> | ((value: V) => void)\n\nexport interface ObserveConfig {\n /**\n * To be used when observing an object and not a primitive.\n * It creates a proxy that observes changes in the object.\n */\n deep?: boolean\n}\n\n/**\n * Reads the raw value of the object, that is, not proxied object.\n * @param source The source object that contains the object\n * @param target The target object set on the source object\n * @returns The not proxied object or undefined\n */\nexport function toRaw<T extends object = object>(source: object, target: T): T | undefined {\n const proxies = Reflect.get(source, proxySymbol) as Map<object, object>\n if (!proxies) {\n return undefined\n }\n for (const [key, value] of proxies.entries()) {\n if (value === target) {\n return key as T\n }\n }\n}\n\n/**\n * Turns a class property or a setter into an observed property\n * that notifies the root domain when changed.\n *\n * A property has to be declared with the `accessor` type to be\n * observed.\n *\n * ```typescript\n * @observed() accessor name: string | undefined\n *\n * @observed()\n * set height(value: number) {\n * this.#height = value\n * }\n *\n * get height(): number {\n * return this.#height\n * }\n * ```\n *\n * The decorator can be used in the following ways:\n * - As a class property decorator\n * - As a class setter decorator\n *\n * The property class either has to have a `root` property\n * or a `notifyChange` method. The decorator will call the\n * `notifyChange` method if it exists. Otherwise, it will\n * call the `notifyChange` method of the root domain.\n */\nexport function observed(config: ObserveConfig = {}): PropertyDecorator {\n return <C extends DomainInstance, V>(\n target: StandardPropertyTarget<C, V>,\n context: StandardPropertyContext<C, V>\n ): any => {\n const { kind } = context\n const { deep } = config\n\n function createDeepProxy(this: DomainInstance, obj: unknown, notifyChange: () => void): any {\n if (typeof obj !== 'object' || obj === null) {\n return obj\n }\n // instead of using the target object to store the proxy info, we\n // reflect the proxy info to the object itself. This way we can\n // keep the stored values clean, which helps with testing (deep equal would include symbols)\n // Keys are original objects, values are proxies\n let proxies = Reflect.get(this, proxySymbol) as Map<object, object>\n if (!proxies) {\n proxies = new Map()\n Reflect.set(this, proxySymbol, proxies)\n }\n\n if (proxies.has(obj)) {\n return obj\n }\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const targetObject = this\n\n const proxy = new Proxy(obj, {\n get(target, prop) {\n const value = Reflect.get(target, prop)\n return createDeepProxy.bind(targetObject)(value, notifyChange)\n },\n set(target, prop, value) {\n const oldValue = Reflect.get(target, prop)\n if (oldValue !== value) {\n Reflect.set(target, prop, value)\n notifyChange()\n }\n return true\n },\n deleteProperty(target, prop) {\n Reflect.deleteProperty(target, prop)\n notifyChange()\n return true\n },\n })\n proxies.set(obj, proxy)\n return proxy\n }\n\n if (kind === 'accessor') {\n return {\n set(this: DomainInstance, value: V): void {\n let map = Reflect.get(this, reactiveSymbol)\n if (!map) {\n map = {}\n Reflect.set(this, reactiveSymbol, map)\n }\n if (map[context.name] === context.name) {\n return\n }\n const notify = () => {\n if (this.domain) {\n this.domain.notifyChange()\n } else if (this.notifyChange) {\n this.notifyChange()\n }\n }\n if (deep) {\n value = createDeepProxy.bind(this)(value, notify)\n }\n if (value === undefined) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete map[context.name]\n } else {\n map[context.name] = value\n }\n notify()\n },\n\n get(): V {\n const map = Reflect.get(this, reactiveSymbol) || {}\n return map[context.name]\n },\n }\n } else if (kind === 'setter') {\n const { name } = context\n return function (this: DomainInstance, value: V): void {\n const oldValue = this[name as keyof DomainInstance]\n if (value === oldValue) {\n return\n }\n const notify = () => {\n if (this.domain) {\n this.domain.notifyChange()\n } else if (this.notifyChange) {\n this.notifyChange()\n }\n }\n ;(target as (value: V) => void).call(this, value)\n notify()\n }\n }\n throw new Error(`Unsupported decorator location: ${kind}`)\n }\n}\n\n/**\n * A decorator that can be used to retarget the change event\n * of a property to the root domain.\n *\n * This decorator should not be used with the `observed` decorator.\n * It does the same thing. It will notify about a change to the\n * property itself.\n */\nexport function retargetChange() {\n return <C extends DomainInstance, V extends EventTarget>(\n target: StandardPropertyTarget<C, V>,\n context: StandardPropertyContext<C, V>\n ): any => {\n const { kind } = context\n function observer(this: DomainInstance) {\n if (this.domain) {\n this.domain.notifyChange()\n }\n }\n let binding: ((this: DomainInstance) => void) | undefined\n if (kind === 'accessor') {\n return {\n set(this: DomainInstance, value: V): void {\n let map = Reflect.get(this, reactiveSymbol)\n if (!map) {\n map = {}\n Reflect.set(this, reactiveSymbol, map)\n }\n if (map[context.name] === context.name) {\n return\n }\n const oldValue = map[context.name]\n if (oldValue === value) {\n return\n }\n if (value === undefined) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete map[context.name]\n } else {\n map[context.name] = value\n }\n if (oldValue && binding) {\n oldValue.removeEventListener('change', binding)\n }\n if (value) {\n binding = observer.bind(this)\n value.addEventListener('change', binding)\n }\n if (this.domain) {\n this.domain.notifyChange()\n }\n },\n\n get(): V {\n const map = Reflect.get(this, reactiveSymbol) || {}\n return map[context.name]\n },\n }\n } else if (kind === 'setter') {\n const { name } = context\n return function (this: DomainInstance, value: V): void {\n const oldValue = this[name as keyof DomainInstance] as unknown as V\n if (value === oldValue) {\n return\n }\n ;(target as (value: V) => void).call(this, value)\n if (oldValue && binding) {\n oldValue.removeEventListener('change', binding)\n }\n if (value) {\n binding = observer.bind(this)\n value.addEventListener('change', binding)\n }\n }\n }\n throw new Error(`Unsupported decorator location: ${kind}`)\n }\n}\n"]}
|