mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-17 18:05:42 +02:00
Fix slots (#10898)
* fix: ensure attribute slot resolution correctly references parent membership in exporter Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * fix: update resolveParentSlot to correctly propagate memberOf references and add regression test for attribute slot scoping Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> * style: reformat testResultClassDoc for readability in detectSlotsRefined test suite Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com> --------- Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
@@ -1138,4 +1138,84 @@ describe('detectSlots refined', () => {
|
||||
expect(subProcSlot).toBeDefined()
|
||||
expect(subProcSlot.memberOf).toBeDefined() // It should refer to slot created for ClassB
|
||||
})
|
||||
|
||||
test('Test 24: User Example (Execute-2.json simulation)', async () => {
|
||||
const mainClassId = 'ClassA'
|
||||
const testResultClassId = '69e8d19c618de58dbaf9ecf2'
|
||||
const attemptsAttrId = 'custom6a00914a295035d76ab16e1d'
|
||||
const attemptNumAttrId = 'custom69eb7f41889a0214e41368cb'
|
||||
|
||||
const mainClassDoc = { _id: mainClassId, _class: 'core:class:Class', name: 'ClassA', label: 'Main Entity' }
|
||||
const testResultClassDoc = {
|
||||
_id: testResultClassId,
|
||||
_class: 'core:class:Class',
|
||||
name: 'TestResult',
|
||||
label: '(T) Test Result'
|
||||
}
|
||||
|
||||
const attemptsAttrDoc = {
|
||||
_id: attemptsAttrId,
|
||||
_class: 'core:class:Attribute',
|
||||
name: 'attempts',
|
||||
label: 'Attempts',
|
||||
attributeOf: mainClassId,
|
||||
type: 'core:class:TypeNumber'
|
||||
}
|
||||
const attemptNumAttrDoc = {
|
||||
_id: attemptNumAttrId,
|
||||
_class: 'core:class:Attribute',
|
||||
name: 'attemptNumber',
|
||||
label: 'Attempt number',
|
||||
attributeOf: testResultClassId,
|
||||
type: 'core:class:TypeNumber'
|
||||
}
|
||||
|
||||
m.findObject = jest.fn().mockImplementation((id) => {
|
||||
if (id === mainClassId) return mainClassDoc
|
||||
if (id === testResultClassId) return testResultClassDoc
|
||||
if (id === attemptsAttrId) return attemptsAttrDoc
|
||||
if (id === attemptNumAttrId) return attemptNumAttrDoc
|
||||
if (id === 'process:method:CreateCard') return { _id: 'process:method:CreateCard', requiredParams: ['_class'] }
|
||||
return undefined
|
||||
})
|
||||
|
||||
h.findAttribute = jest.fn().mockImplementation((tag, attrId) => {
|
||||
if (tag === mainClassId && attrId === attemptsAttrId) return attemptsAttrDoc
|
||||
if (tag === testResultClassId && attrId === attemptNumAttrId) return attemptNumAttrDoc
|
||||
return undefined
|
||||
})
|
||||
|
||||
const transitions = [
|
||||
{
|
||||
_id: 'tr1',
|
||||
actions: [
|
||||
{
|
||||
_id: 'act1',
|
||||
methodId: 'process:method:CreateCard',
|
||||
params: {
|
||||
_class: testResultClassId,
|
||||
[attemptNumAttrId]: `\${@${attemptsAttrId}}`
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const slots: Record<string, any> = {}
|
||||
const bindings: Record<string, string> = {}
|
||||
detectSlots({ masterTag: mainClassId } as any, transitions as any[], slots, bindings, m, h)
|
||||
|
||||
// attempts (attemptsAttrId) belongs to mainClassId (masterTag), so its memberOf must be undefined.
|
||||
// attemptNumber (attemptNumAttrId) belongs to testResultClassId, so its memberOf must point to the testResultClassId slot.
|
||||
const attemptsSlotName = 'attempts'
|
||||
const attemptNumSlotName = 'attemptNumber'
|
||||
const testResultSlotName = '(T) Test Result'
|
||||
|
||||
expect(slots[attemptsSlotName]).toBeDefined()
|
||||
expect(slots[attemptNumSlotName]).toBeDefined()
|
||||
expect(slots[testResultSlotName]).toBeDefined()
|
||||
|
||||
expect(slots[attemptsSlotName].memberOf).toBeUndefined()
|
||||
expect(slots[attemptNumSlotName].memberOf).toBe(`__SLOT_${testResultSlotName}__`)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -552,15 +552,18 @@ function resolveActionContext (
|
||||
* its `__SLOT_name__` reference for use as `memberOf`.
|
||||
*/
|
||||
function resolveParentSlot (
|
||||
targetTag: Ref<MasterTag>,
|
||||
targetTag: Ref<MasterTag> | undefined,
|
||||
masterTag: Ref<MasterTag>,
|
||||
memberOfRef: string | undefined,
|
||||
getOrAddSlot: (id: string, model: DetailedSlotModel) => string,
|
||||
m: ModelDb
|
||||
): string | undefined {
|
||||
if (targetTag === undefined || targetTag === '' || normalizeId(targetTag) === normalizeId(masterTag)) {
|
||||
if (targetTag === undefined || targetTag === '') {
|
||||
return memberOfRef
|
||||
}
|
||||
if (normalizeId(targetTag) === normalizeId(masterTag)) {
|
||||
return undefined
|
||||
}
|
||||
const targetDoc = m.findObject(targetTag) as Class<any> | undefined
|
||||
const parentSlotId = getOrAddSlot(
|
||||
targetTag,
|
||||
@@ -807,7 +810,8 @@ function scanParamKey (
|
||||
if (isSystemId(parentClassId) && !isContextualValue(val, activeTag, masterTag, h, m)) {
|
||||
return
|
||||
}
|
||||
getOrAddSlot(key, attributeToSlot(keyAttr, memberOfRef))
|
||||
const attrMemberOf = resolveParentSlot(keyAttr.attributeOf, masterTag, memberOfRef, getOrAddSlot, m)
|
||||
getOrAddSlot(key, attributeToSlot(keyAttr, attrMemberOf))
|
||||
} else if (key.length >= 24) {
|
||||
getOrAddSlot(key, unknownToSlot(key, memberOfRef))
|
||||
}
|
||||
@@ -872,7 +876,9 @@ function classifyAndRegisterSlot (
|
||||
const assocMemberOf = resolveParentSlot(targetClass, masterTag, memberOfRef, getOrAddSlot, m)
|
||||
getOrAddSlot(id, associationToSlot(assoc, direction, assocMemberOf))
|
||||
} else if (classId === normalizeId(core.class.Attribute)) {
|
||||
getOrAddSlot(id, attributeToSlot(obj as Attribute<any>, memberOfRef))
|
||||
const attr = obj as Attribute<any>
|
||||
const attrMemberOf = resolveParentSlot(attr.attributeOf, masterTag, memberOfRef, getOrAddSlot, m)
|
||||
getOrAddSlot(id, attributeToSlot(attr, attrMemberOf))
|
||||
} else if (classId === normalizeId(core.class.Class) || h.isDerived(obj._class, core.class.Class)) {
|
||||
getOrAddSlot(id, classToSlot(obj as any as Class<any>, memberOfRef))
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user