Skip to content

Commit

Permalink
Add containment ref support (#36)
Browse files Browse the repository at this point in the history
* Add containment ref support

* Switch to search for singular containment ref

* Ensure parent must have id

* Switch to find

* Improve trio support
  • Loading branch information
garethj2 authored Nov 27, 2024
1 parent 781f3c9 commit be38523
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 2 deletions.
17 changes: 17 additions & 0 deletions spec/core/HNamespace.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1926,4 +1926,21 @@ describe('HNamespace', function (): void {
expect(tags).toEqual(['vav', 'equip'])
})
}) // #newDict()

describe('#getContainmentRefs()', function (): void {
it('returns a list of all the containment refs for a dict', function (): void {
expect(
defs
.getContainmentRefs()
.map((def) => def.defName)
.sort()
).toEqual(['equipRef', 'siteRef', 'spaceRef'])
})
}) // #getContainmentRefs()

describe('#findContainmentRef()', function (): void {
it('returns the containment ref for a def', function (): void {
expect(defs.findContainmentRef('site')?.defName).toEqual('siteRef')
})
}) // #findContainmentRef()
})
13 changes: 13 additions & 0 deletions spec/core/TrioWriter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,19 @@ describe('TrioWriter', function (): void {
})
}) // #toTrio()

describe('.toTrioDict()', function (): void {
it('writes a dict file to trio', function (): void {
const trio = TrioWriter.toTrioDict(makeDict())

expect(trio).toBe(
'marker\n' +
'str: "A string"\n' +
'list: [T]\n' +
'dict: {foo:"bar"}'
)
})
}) // .toTrioDict()

describe('#toString()', function (): void {
it('calls #toTrio()', function (): void {
jest.spyOn(writer, 'toTrio').mockReturnValue('')
Expand Down
78 changes: 78 additions & 0 deletions spec/core/Util.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
disKey,
makeDefaultValue,
toKind,
addContainmentRefs,
} from '../../src/core/util'
import { Kind } from '../../src/core/Kind'
import { HBool } from '../../src/core/HBool'
Expand All @@ -32,6 +33,9 @@ import { HDict } from '../../src/core/HDict'
import { HVal } from '../../src/core/HVal'
import { HNa } from '../../src/core/HNa'
import { HGrid } from '../../src/core/HGrid'
import { HNamespace } from '../../src/core/HNamespace'
import { ZincReader } from '../../src/core/ZincReader'
import { readFile } from './file'

describe('util', function (): void {
describe('makeValue()', function (): void {
Expand Down Expand Up @@ -763,4 +767,78 @@ describe('util', function (): void {
expect(disKey('pod:key', i18n)).toBeUndefined()
})
}) // disKey()

describe('addContainmentRefs()', () => {
let defs: HNamespace

beforeAll(() => {
const zinc = readFile('./defsWithFeatures.zinc')
const grid = ZincReader.readValue(zinc) as HGrid
defs = new HNamespace(grid)
})

it('adds a siteRef to a floor', () => {
const dict = new HDict()

const refName = addContainmentRefs(
dict,
new HDict({
id: HRef.make('site'),
site: HMarker.make(),
}),
defs
)

expect(refName).toBe('siteRef')

expect(dict.toJSON()).toEqual({
siteRef: { _kind: Kind.Ref, val: 'site' },
})
})

it('adds a siteRef and an equipRef to a floor', () => {
const dict = new HDict()

const refName = addContainmentRefs(
dict,
new HDict({
id: HRef.make('equip'),
siteRef: HRef.make('site'),
equip: HMarker.make(),
}),
defs
)

expect(refName).toBe('equipRef')

expect(dict.toJSON()).toEqual({
siteRef: { _kind: Kind.Ref, val: 'site' },
equipRef: { _kind: Kind.Ref, val: 'equip' },
})
})

it('adds a siteRef, equipRef and a spaceRef to a floor', () => {
const dict = new HDict()

const refName = addContainmentRefs(
dict,
new HDict({
id: HRef.make('floor'),
siteRef: HRef.make('site'),
equipRef: HRef.make('equip'),
space: HMarker.make(),
floor: HMarker.make(),
}),
defs
)

expect(refName).toBe('spaceRef')

expect(dict.toJSON()).toEqual({
siteRef: { _kind: Kind.Ref, val: 'site' },
equipRef: { _kind: Kind.Ref, val: 'equip' },
spaceRef: { _kind: Kind.Ref, val: 'floor' },
})
})
}) // addContainmentRefs()
})
26 changes: 26 additions & 0 deletions src/core/HNamespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1647,4 +1647,30 @@ export class HNamespace {

return dict
}

/**
* Return all the containment refs available.
*
* @returns A list of all the containment refs.
*/
@memoize()
public getContainmentRefs(): HDict[] {
return this.allSubTypesOf('ref').filter((def) => def.has('containedBy'))
}

/**
* Return the first containment ref def that matches the specified name.
*
* Please note, this will filter out any defs that are marked as deprecated.
*
* @param name The name of the def to search the ref for.
* @returns The containment ref def.
*/
public findContainmentRef(name: string | HSymbol): HDict | undefined {
return this.getContainmentRefs().find(
(def) =>
!def.has('deprecated') &&
this.fits(name, def.get('containedBy') as HSymbol)
)
}
}
4 changes: 2 additions & 2 deletions src/core/TrioWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class TrioWriter {
trio += item.text ? `// ${item.text}` : '//'
break
case ItemType.Dict:
trio += this.toTrioDict(item.dict || HDict.make())
trio += TrioWriter.toTrioDict(item.dict || HDict.make())
trio += '\n---'
break
}
Expand All @@ -120,7 +120,7 @@ export class TrioWriter {
* @param dict The dict to encode.
* @returns The trio encoded dict.
*/
private toTrioDict(dict: HDict): string {
public static toTrioDict(dict: HDict): string {
return dict.keys
.map((name: string): string => {
const value = dict.get(name)
Expand Down
57 changes: 57 additions & 0 deletions src/core/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { HSymbol } from './HSymbol'
import { HList } from './HList'
import { HGrid } from './HGrid'
import { Scanner } from '../util/Scanner'
import { HNamespace } from './HNamespace'

/**
* Make the haystack value based on the supplied data.
Expand Down Expand Up @@ -526,3 +527,59 @@ export function disKey(
const [, pod, disKey] = /^([^:]+)::([^:]+)$/.exec(key.trim()) ?? []
return pod && disKey ? i18n(pod, disKey) : undefined
}

/**
* Add the containment refs to a record.
*
* This ensures all the containment refs are set up accordingly to the project haystack
* specification as well as additional refs that are defined in the defs namespace.
*
* - https://project-haystack.org/doc/docHaystack/Equips
* - https://project-haystack.org/doc/docHaystack/Points
* - https://project-haystack.org/doc/docHaystack/Spaces
*
* @param dict The new record.
* @param parent The parent record.
* @param namespace The defs namespace.
* @returns The primary containment ref name.
*/
export function addContainmentRefs(
dict: HDict,
parent: HDict,
namespace: HNamespace
): string {
const siteRef = parent.has('site')
? parent.get<HRef>('id')
: parent.get<HRef>('siteRef')

if (siteRef) {
dict.set('siteRef', siteRef)
}

const equipRef = parent.has('equip')
? parent.get<HRef>('id')
: parent.get<HRef>('equipRef')

if (equipRef) {
dict.set('equipRef', equipRef)
}

const spaceRef =
parent.has('space') || parent.has('floor')
? parent.get<HRef>('id')
: parent.get<HRef>('spaceRef')

if (spaceRef) {
dict.set('spaceRef', spaceRef)
}

const refName =
namespace.findContainmentRef(namespace.reflect(parent).type.defName)
?.defName ?? ''

if (refName && !dict.has(refName) && parent.has('id')) {
dict.set(refName, parent.get('id') as HRef)
}

return refName
}

0 comments on commit be38523

Please sign in to comment.