@dotbep/core 0.2.7 → 0.2.8
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/dist/index.d.ts +7 -5
- package/dist/index.js +604 -596
- package/package.json +4 -1
- package/examples/01-participants.ts +0 -127
- package/examples/02-files.ts +0 -100
- package/examples/03-workflows.ts +0 -149
- package/examples/04-bim-uses.ts +0 -70
- package/examples/05-standards.ts +0 -60
- package/examples/06-schedule.ts +0 -124
- package/examples/07-loin.ts +0 -133
- package/examples/08-deliverables.ts +0 -126
- package/examples/09-notes.ts +0 -73
- package/examples/10-llm.ts +0 -109
- package/examples/11-resolved.ts +0 -133
- package/examples/12-history.ts +0 -166
- package/examples/13-engine.ts +0 -152
- package/examples/bep.d.ts +0 -38
- package/examples/example.bep +0 -0
- package/examples/run-all.ts +0 -38
- package/src/base/entity.ts +0 -148
- package/src/base/history.ts +0 -497
- package/src/base/index.ts +0 -5
- package/src/base/singleton.ts +0 -26
- package/src/entities/actions.ts +0 -25
- package/src/entities/adapters.ts +0 -16
- package/src/entities/annexes.ts +0 -17
- package/src/entities/assetTypes.ts +0 -30
- package/src/entities/automations.ts +0 -24
- package/src/entities/bimUses.ts +0 -50
- package/src/entities/deliverables.ts +0 -66
- package/src/entities/disciplines.ts +0 -21
- package/src/entities/effects.ts +0 -28
- package/src/entities/env.ts +0 -17
- package/src/entities/events.ts +0 -24
- package/src/entities/extensions.ts +0 -16
- package/src/entities/flags.ts +0 -17
- package/src/entities/guides.ts +0 -26
- package/src/entities/index.ts +0 -32
- package/src/entities/lbsNodes.ts +0 -193
- package/src/entities/lods.ts +0 -22
- package/src/entities/loin.ts +0 -127
- package/src/entities/lois.ts +0 -22
- package/src/entities/members.ts +0 -137
- package/src/entities/milestones.ts +0 -32
- package/src/entities/notes.ts +0 -27
- package/src/entities/objectives.ts +0 -17
- package/src/entities/phases.ts +0 -17
- package/src/entities/remoteData.ts +0 -17
- package/src/entities/resolvers.ts +0 -20
- package/src/entities/roles.ts +0 -29
- package/src/entities/softwares.ts +0 -26
- package/src/entities/standards.ts +0 -68
- package/src/entities/teams.ts +0 -42
- package/src/entities/workflows.ts +0 -256
- package/src/index.ts +0 -464
- package/src/runtime/Engine.ts +0 -352
- package/src/runtime/MemoryStorage.ts +0 -31
- package/src/runtime/Runtime.ts +0 -106
- package/src/runtime/index.ts +0 -4
- package/src/runtime/transitions.ts +0 -456
- package/src/runtime/types.ts +0 -279
- package/src/types/history.ts +0 -37
- package/src/types/index.ts +0 -24
- package/src/types/resolved.ts +0 -137
- package/src/types/schema.ts +0 -757
- package/src/utils/diff.ts +0 -109
- package/src/utils/index.ts +0 -9
- package/src/utils/integrity.ts +0 -108
- package/src/utils/lbs.ts +0 -116
- package/src/utils/mermaid.ts +0 -110
- package/src/utils/naming.ts +0 -62
- package/src/utils/nomenclature.ts +0 -107
- package/src/utils/normalize.ts +0 -35
- package/src/utils/raci.ts +0 -25
- package/src/utils/textFile.ts +0 -24
- package/tsconfig.json +0 -12
- package/vite.config.ts +0 -24
package/src/entities/bimUses.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type { BEP, BIMUse, Milestone, Objective } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { BIMUseSchema } from '../types/schema.js'
|
|
4
|
-
import type { BIMUseResolved, MilestoneResolved, WorkflowResolved } from '../types/resolved.js'
|
|
5
|
-
import type { Workflows } from './workflows.js'
|
|
6
|
-
|
|
7
|
-
export class BIMUses extends Entity<BIMUse, true> {
|
|
8
|
-
constructor(getBep: () => BEP, private readonly getWorkflows: () => Workflows) {
|
|
9
|
-
super(
|
|
10
|
-
() => getBep().bimUses,
|
|
11
|
-
getBep,
|
|
12
|
-
{
|
|
13
|
-
key: 'bimUses',
|
|
14
|
-
schema: BIMUseSchema,
|
|
15
|
-
autoId: true,
|
|
16
|
-
validate: (item, bep) => {
|
|
17
|
-
const errors: string[] = []
|
|
18
|
-
for (const id of item.objectiveIds ?? []) {
|
|
19
|
-
if (!bep.objectives.some(o => o.id === id))
|
|
20
|
-
errors.push(`objectives["${id}"] not found`)
|
|
21
|
-
}
|
|
22
|
-
for (const id of item.milestoneIds ?? []) {
|
|
23
|
-
if (!bep.milestones.some(m => m.id === id))
|
|
24
|
-
errors.push(`milestones["${id}"] not found`)
|
|
25
|
-
}
|
|
26
|
-
for (const id of item.workflowIds ?? []) {
|
|
27
|
-
if (!bep.workflows.some(w => w.id === id))
|
|
28
|
-
errors.push(`workflows["${id}"] not found`)
|
|
29
|
-
}
|
|
30
|
-
return errors
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
listResolved(): BIMUseResolved[] {
|
|
37
|
-
const bep = this.getBep()
|
|
38
|
-
const workflowMap = new Map(this.getWorkflows().listResolved().map(w => [w.id, w]))
|
|
39
|
-
return bep.bimUses.map(bu => ({
|
|
40
|
-
...bu,
|
|
41
|
-
objectives: (bu.objectiveIds ?? []).map(id => bep.objectives.find(o => o.id === id)).filter(Boolean) as Objective[],
|
|
42
|
-
milestones: (bu.milestoneIds ?? []).map(id => {
|
|
43
|
-
const m = bep.milestones.find(m => m.id === id)
|
|
44
|
-
if (!m) return null
|
|
45
|
-
return { ...m, phase: bep.phases.find(p => p.id === m.phaseId) ?? null } satisfies MilestoneResolved
|
|
46
|
-
}).filter(Boolean) as MilestoneResolved[],
|
|
47
|
-
workflows: (bu.workflowIds ?? []).map(id => workflowMap.get(id)).filter(Boolean) as WorkflowResolved[],
|
|
48
|
-
}))
|
|
49
|
-
}
|
|
50
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import type { BEP, Deliverable, Discipline, Extension } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { DeliverableSchema } from '../types/schema.js'
|
|
4
|
-
import type { DeliverableResolved, AssetTypeResolved, LBSNodeResolved, TeamResolved } from '../types/resolved.js'
|
|
5
|
-
import { buildCodeMap } from '../utils/nomenclature.js'
|
|
6
|
-
import type { AssetTypes } from './assetTypes.js'
|
|
7
|
-
import type { LBSNodes } from './lbsNodes.js'
|
|
8
|
-
import type { Milestones } from './milestones.js'
|
|
9
|
-
import type { Teams } from './teams.js'
|
|
10
|
-
|
|
11
|
-
export class Deliverables extends Entity<Deliverable, true> {
|
|
12
|
-
constructor(
|
|
13
|
-
getBep: () => BEP,
|
|
14
|
-
private readonly getTeams: () => Teams,
|
|
15
|
-
private readonly getAssetTypes: () => AssetTypes,
|
|
16
|
-
private readonly getLBSNodes: () => LBSNodes,
|
|
17
|
-
private readonly getMilestones: () => Milestones,
|
|
18
|
-
) {
|
|
19
|
-
super(
|
|
20
|
-
() => getBep().deliverables,
|
|
21
|
-
getBep,
|
|
22
|
-
{
|
|
23
|
-
key: 'deliverables',
|
|
24
|
-
schema: DeliverableSchema,
|
|
25
|
-
autoId: true,
|
|
26
|
-
},
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
listResolved(): DeliverableResolved[] {
|
|
31
|
-
const bep = this.getBep()
|
|
32
|
-
const codeMap = buildCodeMap(bep.deliverables, bep.project.code, bep.lbs)
|
|
33
|
-
const teamMap = new Map(this.getTeams().listResolved().map(t => [t.id, t]))
|
|
34
|
-
const assetTypeMap = new Map(this.getAssetTypes().listResolved().map(dt => [dt.id, dt]))
|
|
35
|
-
const lbsNodeMap = new Map(this.getLBSNodes().listResolved().map(n => [n.id, n]))
|
|
36
|
-
const milestoneMap = new Map(this.getMilestones().listResolved().map(m => [m.id, m]))
|
|
37
|
-
|
|
38
|
-
// First pass: resolve everything except predecessor
|
|
39
|
-
const partials = new Map<string, DeliverableResolved>()
|
|
40
|
-
for (const d of bep.deliverables) {
|
|
41
|
-
const milestone = milestoneMap.get(d.milestoneId) ?? null
|
|
42
|
-
partials.set(d.id, {
|
|
43
|
-
...d,
|
|
44
|
-
nomenclatureCode: codeMap.get(d.id) ?? '',
|
|
45
|
-
effectiveDate: d.dueDate ?? milestone?.date ?? '',
|
|
46
|
-
lbsNode: d.lbsNodeId ? (lbsNodeMap.get(d.lbsNodeId) ?? null) : null as LBSNodeResolved | null,
|
|
47
|
-
discipline: bep.disciplines.find(di => di.id === d.disciplineId) ?? null as Discipline | null,
|
|
48
|
-
assetType: assetTypeMap.get(d.assetTypeId) ?? null as AssetTypeResolved | null,
|
|
49
|
-
extensions: (d.extensionIds ?? []).map(id => bep.extensions.find(e => e.id === id)).filter(Boolean) as Extension[],
|
|
50
|
-
responsible: teamMap.get(d.responsibleId) ?? null as TeamResolved | null,
|
|
51
|
-
milestone: milestone,
|
|
52
|
-
predecessor: null,
|
|
53
|
-
})
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Second pass: resolve predecessors using the already-computed partials
|
|
57
|
-
for (const d of bep.deliverables) {
|
|
58
|
-
if (d.predecessorId) {
|
|
59
|
-
const resolved = partials.get(d.id)!
|
|
60
|
-
resolved.predecessor = partials.get(d.predecessorId) ?? null
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return [...partials.values()]
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { BEP, Discipline } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { DisciplineSchema } from '../types/schema.js'
|
|
4
|
-
import { validateTokenValue } from '../utils/naming.js'
|
|
5
|
-
|
|
6
|
-
export class Disciplines extends Entity<Discipline> {
|
|
7
|
-
constructor(getBep: () => BEP) {
|
|
8
|
-
super(
|
|
9
|
-
() => getBep().disciplines,
|
|
10
|
-
getBep,
|
|
11
|
-
{
|
|
12
|
-
key: 'disciplines',
|
|
13
|
-
schema: DisciplineSchema,
|
|
14
|
-
validate: (d, bep) => {
|
|
15
|
-
const err = validateTokenValue('discipline', d.id, bep.deliverableNamingConvention)
|
|
16
|
-
return err ? [err] : []
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
)
|
|
20
|
-
}
|
|
21
|
-
}
|
package/src/entities/effects.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { BEP, FlowEffect } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { FlowEffectSchema } from '../types/schema.js'
|
|
4
|
-
|
|
5
|
-
export class Effects extends Entity<FlowEffect> {
|
|
6
|
-
constructor(getBep: () => BEP) {
|
|
7
|
-
super(
|
|
8
|
-
() => getBep().effects,
|
|
9
|
-
getBep,
|
|
10
|
-
{
|
|
11
|
-
key: 'effects',
|
|
12
|
-
schema: FlowEffectSchema,
|
|
13
|
-
beforeRemove: (id, bep) => {
|
|
14
|
-
for (const wf of bep.workflows) {
|
|
15
|
-
for (const [nodeKey, node] of Object.entries(wf.diagram.nodes)) {
|
|
16
|
-
if ((node.type === 'process' || node.type === 'automation') && node.timeouts?.some(t => t.effectId === id))
|
|
17
|
-
throw new Error(`Referenced by: workflows["${wf.id}"].diagram.nodes["${nodeKey}"].timeouts[].effectId`)
|
|
18
|
-
}
|
|
19
|
-
for (const [edgeKey, edge] of Object.entries(wf.diagram.edges)) {
|
|
20
|
-
if (edge.effectIds?.includes(id))
|
|
21
|
-
throw new Error(`Referenced by: workflows["${wf.id}"].diagram.edges["${edgeKey}"].effectIds`)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
)
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/entities/env.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { BEP, EnvVar } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { EnvVarSchema } from '../types/schema.js'
|
|
4
|
-
|
|
5
|
-
export class Env extends Entity<EnvVar> {
|
|
6
|
-
constructor(getBep: () => BEP) {
|
|
7
|
-
super(
|
|
8
|
-
() => getBep().env,
|
|
9
|
-
getBep,
|
|
10
|
-
{
|
|
11
|
-
key: 'env',
|
|
12
|
-
idField: 'key',
|
|
13
|
-
schema: EnvVarSchema,
|
|
14
|
-
},
|
|
15
|
-
)
|
|
16
|
-
}
|
|
17
|
-
}
|
package/src/entities/events.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { BEP, FlowEvent } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { FlowEventSchema } from '../types/schema.js'
|
|
4
|
-
|
|
5
|
-
export class Events extends Entity<FlowEvent> {
|
|
6
|
-
constructor(getBep: () => BEP) {
|
|
7
|
-
super(
|
|
8
|
-
() => getBep().events,
|
|
9
|
-
getBep,
|
|
10
|
-
{
|
|
11
|
-
key: 'events',
|
|
12
|
-
schema: FlowEventSchema,
|
|
13
|
-
beforeRemove: (id, bep) => {
|
|
14
|
-
for (const wf of bep.workflows) {
|
|
15
|
-
for (const [edgeKey, edge] of Object.entries(wf.diagram.edges)) {
|
|
16
|
-
if ('triggerEventId' in edge && edge.triggerEventId === id)
|
|
17
|
-
throw new Error(`Referenced by: workflows["${wf.id}"].diagram.edges["${edgeKey}"].trigger`)
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { BEP, Extension } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { ExtensionSchema } from '../types/schema.js'
|
|
4
|
-
|
|
5
|
-
export class Extensions extends Entity<Extension> {
|
|
6
|
-
constructor(getBep: () => BEP) {
|
|
7
|
-
super(
|
|
8
|
-
() => getBep().extensions,
|
|
9
|
-
getBep,
|
|
10
|
-
{
|
|
11
|
-
key: 'extensions',
|
|
12
|
-
schema: ExtensionSchema,
|
|
13
|
-
},
|
|
14
|
-
)
|
|
15
|
-
}
|
|
16
|
-
}
|
package/src/entities/flags.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { BEP, Flag } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { FlagSchema } from '../types/schema.js'
|
|
4
|
-
|
|
5
|
-
export class Flags extends Entity<Flag, true> {
|
|
6
|
-
constructor(getBep: () => BEP) {
|
|
7
|
-
super(
|
|
8
|
-
() => getBep().flags,
|
|
9
|
-
getBep,
|
|
10
|
-
{
|
|
11
|
-
key: 'flags',
|
|
12
|
-
schema: FlagSchema,
|
|
13
|
-
autoId: true,
|
|
14
|
-
},
|
|
15
|
-
)
|
|
16
|
-
}
|
|
17
|
-
}
|
package/src/entities/guides.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { Annex, BEP, Guide } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { GuideSchema } from '../types/schema.js'
|
|
4
|
-
import type { GuideResolved } from '../types/resolved.js'
|
|
5
|
-
|
|
6
|
-
export class Guides extends Entity<Guide, true> {
|
|
7
|
-
constructor(getBep: () => BEP) {
|
|
8
|
-
super(
|
|
9
|
-
() => getBep().guides,
|
|
10
|
-
getBep,
|
|
11
|
-
{
|
|
12
|
-
key: 'guides',
|
|
13
|
-
schema: GuideSchema,
|
|
14
|
-
autoId: true,
|
|
15
|
-
},
|
|
16
|
-
)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
listResolved(): GuideResolved[] {
|
|
20
|
-
const bep = this.getBep()
|
|
21
|
-
return bep.guides.map(g => ({
|
|
22
|
-
...g,
|
|
23
|
-
annexes: (g.annexIds ?? []).map(id => bep.annexes.find(a => a.id === id)).filter(Boolean) as Annex[],
|
|
24
|
-
}))
|
|
25
|
-
}
|
|
26
|
-
}
|
package/src/entities/index.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export { Actions } from './actions.js'
|
|
2
|
-
export { Adapters } from './adapters.js'
|
|
3
|
-
export { Automations } from './automations.js'
|
|
4
|
-
export { Env } from './env.js'
|
|
5
|
-
export { Effects } from './effects.js'
|
|
6
|
-
export { Events } from './events.js'
|
|
7
|
-
export { Annexes } from './annexes.js'
|
|
8
|
-
export { BIMUses } from './bimUses.js'
|
|
9
|
-
export { Deliverables } from './deliverables.js'
|
|
10
|
-
export { Disciplines } from './disciplines.js'
|
|
11
|
-
export { AssetTypes } from './assetTypes.js'
|
|
12
|
-
export { Extensions } from './extensions.js'
|
|
13
|
-
export { Flags } from './flags.js'
|
|
14
|
-
export { Roles } from './roles.js'
|
|
15
|
-
export { Guides } from './guides.js'
|
|
16
|
-
export { LBSNodes } from './lbsNodes.js'
|
|
17
|
-
export type { LBSNodeAddInput, LBSNodeUpdateInput } from './lbsNodes.js'
|
|
18
|
-
export { LODs } from './lods.js'
|
|
19
|
-
export { LOIs } from './lois.js'
|
|
20
|
-
export { LOINEntity } from './loin.js'
|
|
21
|
-
export { Members } from './members.js'
|
|
22
|
-
export { Milestones } from './milestones.js'
|
|
23
|
-
export { Notes } from './notes.js'
|
|
24
|
-
export { Objectives } from './objectives.js'
|
|
25
|
-
export { Phases } from './phases.js'
|
|
26
|
-
export { RemoteDataEntity } from './remoteData.js'
|
|
27
|
-
export { Resolvers } from './resolvers.js'
|
|
28
|
-
export { Softwares } from './softwares.js'
|
|
29
|
-
export { Standards } from './standards.js'
|
|
30
|
-
export type { StandardAddInput } from './standards.js'
|
|
31
|
-
export { Teams } from './teams.js'
|
|
32
|
-
export { Workflows } from './workflows.js'
|
package/src/entities/lbsNodes.ts
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import type { BEP, LBSNode } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { LBSNodeSchema } from '../types/schema.js'
|
|
4
|
-
import { buildParentMap, getRootIds, resolveLBSCodes, validateLBS } from '../utils/lbs.js'
|
|
5
|
-
import type { LBSNodeResolved } from '../types/resolved.js'
|
|
6
|
-
import { validateTokenValue } from '../utils/naming.js'
|
|
7
|
-
|
|
8
|
-
export type LBSNodeAddInput = Omit<LBSNode, 'lbsNodeIds'> & { parentId?: string }
|
|
9
|
-
export type LBSNodeUpdateInput = Partial<Omit<LBSNode, 'lbsNodeIds'>> & { id: string; parentId?: string | null }
|
|
10
|
-
|
|
11
|
-
export class LBSNodes extends Entity<LBSNode> {
|
|
12
|
-
constructor(getBep: () => BEP) {
|
|
13
|
-
super(
|
|
14
|
-
() => getBep().lbs,
|
|
15
|
-
getBep,
|
|
16
|
-
{
|
|
17
|
-
key: 'lbs',
|
|
18
|
-
schema: LBSNodeSchema,
|
|
19
|
-
validate: (item, bep) => {
|
|
20
|
-
const errors: string[] = []
|
|
21
|
-
|
|
22
|
-
const token = item.type === 'zone' ? 'lbsZone' : 'lbsLocation'
|
|
23
|
-
const tokenErr = validateTokenValue(token, item.id, bep.deliverableNamingConvention)
|
|
24
|
-
if (tokenErr) errors.push(tokenErr)
|
|
25
|
-
|
|
26
|
-
// Per-node check: location nodes cannot have zone children.
|
|
27
|
-
// Root-must-be-zone and cycle detection are whole-tree invariants
|
|
28
|
-
// — use validateTree() after building the full structure.
|
|
29
|
-
if (item.type === 'location' && item.lbsNodeIds?.length) {
|
|
30
|
-
const nodeMap = new Map(bep.lbs.map(n => [n.id, n]))
|
|
31
|
-
for (const childId of item.lbsNodeIds ?? []) {
|
|
32
|
-
if (nodeMap.get(childId)?.type === 'zone')
|
|
33
|
-
errors.push(`Node "${item.id}" (location) cannot have a zone child ("${childId}").`)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return errors
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
listResolved(): LBSNodeResolved[] {
|
|
44
|
-
const bep = this.getBep()
|
|
45
|
-
const parentMap = buildParentMap(bep.lbs)
|
|
46
|
-
const rootIds = getRootIds(bep.lbs)
|
|
47
|
-
const nodeMap = new Map(bep.lbs.map(n => [n.id, n]))
|
|
48
|
-
return bep.lbs.map(node => {
|
|
49
|
-
const parentId = parentMap.get(node.id)
|
|
50
|
-
const parentNode = parentId ? nodeMap.get(parentId) : undefined
|
|
51
|
-
return {
|
|
52
|
-
...node,
|
|
53
|
-
isRoot: rootIds.has(node.id),
|
|
54
|
-
parent: parentNode ? { id: parentNode.id, name: parentNode.name, type: parentNode.type } : null,
|
|
55
|
-
children: (node.lbsNodeIds ?? []).map(id => nodeMap.get(id)).filter(Boolean) as LBSNode[],
|
|
56
|
-
}
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
addNodes(items: LBSNodeAddInput[]): {
|
|
61
|
-
succeeded: Array<LBSNode & { parentId: string | null }>
|
|
62
|
-
failed: Array<{ input: unknown; error: string }>
|
|
63
|
-
} {
|
|
64
|
-
const bep = this.getBep()
|
|
65
|
-
const succeeded: Array<LBSNode & { parentId: string | null }> = []
|
|
66
|
-
const failed: Array<{ input: unknown; error: string }> = []
|
|
67
|
-
|
|
68
|
-
for (const item of items) {
|
|
69
|
-
if (!item.parentId && item.type !== 'zone') {
|
|
70
|
-
failed.push({ input: item, error: 'Root nodes (no parentId) must be type "zone".' })
|
|
71
|
-
continue
|
|
72
|
-
}
|
|
73
|
-
if (item.parentId && !bep.lbs.find(n => n.id === item.parentId)) {
|
|
74
|
-
failed.push({ input: item, error: `No LBS node found with ID "${item.parentId}".` })
|
|
75
|
-
continue
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const { parentId, ...node } = item
|
|
79
|
-
const addResult = this.add([node])
|
|
80
|
-
if (addResult.failed.length > 0) {
|
|
81
|
-
failed.push({ input: item, error: addResult.failed[0].error })
|
|
82
|
-
continue
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
let parent: LBSNode | undefined
|
|
86
|
-
if (parentId) {
|
|
87
|
-
parent = bep.lbs.find(n => n.id === parentId)
|
|
88
|
-
if (parent) {
|
|
89
|
-
parent.lbsNodeIds ??= []
|
|
90
|
-
parent.lbsNodeIds.push(item.id)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const errors = this.validateTree()
|
|
95
|
-
if (errors.length > 0) {
|
|
96
|
-
bep.lbs.splice(bep.lbs.findIndex(n => n.id === item.id), 1)
|
|
97
|
-
if (parent?.lbsNodeIds) parent.lbsNodeIds = parent.lbsNodeIds.filter(c => c !== item.id)
|
|
98
|
-
failed.push({ input: item, error: errors.join('; ') })
|
|
99
|
-
continue
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
succeeded.push({ ...bep.lbs.find(n => n.id === item.id)!, parentId: parentId ?? null })
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return { succeeded, failed }
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
updateNodes(items: LBSNodeUpdateInput[]): {
|
|
109
|
-
succeeded: Array<{
|
|
110
|
-
id: string
|
|
111
|
-
before: { name: string; type: string; description: string | undefined; parentId: string | null }
|
|
112
|
-
after: { name: string; type: string; description: string | undefined; parentId: string | null }
|
|
113
|
-
}>
|
|
114
|
-
failed: Array<{ id: string; error: string }>
|
|
115
|
-
} {
|
|
116
|
-
const bep = this.getBep()
|
|
117
|
-
const succeeded: Array<{
|
|
118
|
-
id: string
|
|
119
|
-
before: { name: string; type: string; description: string | undefined; parentId: string | null }
|
|
120
|
-
after: { name: string; type: string; description: string | undefined; parentId: string | null }
|
|
121
|
-
}> = []
|
|
122
|
-
const failed: Array<{ id: string; error: string }> = []
|
|
123
|
-
|
|
124
|
-
for (const item of items) {
|
|
125
|
-
if (item.parentId && !bep.lbs.find(n => n.id === item.parentId)) {
|
|
126
|
-
failed.push({ id: item.id, error: `No LBS node found with ID "${item.parentId}".` })
|
|
127
|
-
continue
|
|
128
|
-
}
|
|
129
|
-
if (item.parentId === item.id) {
|
|
130
|
-
failed.push({ id: item.id, error: 'A node cannot be its own parent.' })
|
|
131
|
-
continue
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const beforeNode = bep.lbs.find(n => n.id === item.id)
|
|
135
|
-
const beforeParentId = buildParentMap(bep.lbs).get(item.id) ?? null
|
|
136
|
-
|
|
137
|
-
const { parentId, ...fields } = item
|
|
138
|
-
const updateResult = this.update([fields])
|
|
139
|
-
if (updateResult.failed.length > 0) {
|
|
140
|
-
failed.push({ id: item.id, error: updateResult.failed[0].error })
|
|
141
|
-
continue
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const before = { name: beforeNode!.name, type: beforeNode!.type, description: beforeNode!.description, parentId: beforeParentId }
|
|
145
|
-
const node = bep.lbs.find(n => n.id === item.id)!
|
|
146
|
-
|
|
147
|
-
if (parentId !== undefined) {
|
|
148
|
-
for (const n of bep.lbs) {
|
|
149
|
-
if (n.lbsNodeIds?.includes(item.id)) n.lbsNodeIds = n.lbsNodeIds.filter(c => c !== item.id)
|
|
150
|
-
}
|
|
151
|
-
if (parentId) {
|
|
152
|
-
const newParent = bep.lbs.find(n => n.id === parentId)!
|
|
153
|
-
newParent.lbsNodeIds ??= []
|
|
154
|
-
newParent.lbsNodeIds.push(item.id)
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const errors = this.validateTree()
|
|
159
|
-
if (errors.length > 0) {
|
|
160
|
-
node.name = before.name
|
|
161
|
-
node.type = before.type as 'zone' | 'location'
|
|
162
|
-
if (before.description !== undefined) node.description = before.description
|
|
163
|
-
else delete node.description
|
|
164
|
-
if (parentId !== undefined) {
|
|
165
|
-
for (const n of bep.lbs) {
|
|
166
|
-
if (n.lbsNodeIds?.includes(item.id)) n.lbsNodeIds = n.lbsNodeIds.filter(c => c !== item.id)
|
|
167
|
-
}
|
|
168
|
-
if (before.parentId) {
|
|
169
|
-
const prevParent = bep.lbs.find(n => n.id === before.parentId)
|
|
170
|
-
if (prevParent) { prevParent.lbsNodeIds ??= []; prevParent.lbsNodeIds.push(item.id) }
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
failed.push({ id: item.id, error: errors.join('; ') })
|
|
174
|
-
continue
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const afterParentId = buildParentMap(bep.lbs).get(node.id) ?? null
|
|
178
|
-
succeeded.push({ id: item.id, before, after: { name: node.name, type: node.type, description: node.description, parentId: afterParentId } })
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return { succeeded, failed }
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/** Resolves zone and location codes for nomenclature given a node id. */
|
|
185
|
-
resolveCodes(nodeId: string | undefined): { zoneCode: string; locationCode: string } {
|
|
186
|
-
return resolveLBSCodes(nodeId, this.list())
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/** Validates the full LBS tree and returns a list of structural errors. */
|
|
190
|
-
validateTree(): string[] {
|
|
191
|
-
return validateLBS(this.list())
|
|
192
|
-
}
|
|
193
|
-
}
|
package/src/entities/lods.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { BEP, LOD } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { LODSchema } from '../types/schema.js'
|
|
4
|
-
|
|
5
|
-
export class LODs extends Entity<LOD> {
|
|
6
|
-
constructor(getBep: () => BEP) {
|
|
7
|
-
super(
|
|
8
|
-
() => getBep().lods,
|
|
9
|
-
getBep,
|
|
10
|
-
{
|
|
11
|
-
key: 'lods',
|
|
12
|
-
schema: LODSchema,
|
|
13
|
-
beforeRemove: (id, bep) => {
|
|
14
|
-
for (const loin of bep.loin) {
|
|
15
|
-
const ref = loin.milestones?.find(m => m.lodId === id)
|
|
16
|
-
if (ref) throw new Error(`Referenced by: loin["${loin.id}"].milestones[lodId=${id}]`)
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
}
|
package/src/entities/loin.ts
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import type { BEP, LOIN, LOINMilestone } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { LOINSchema } from '../types/schema.js'
|
|
4
|
-
import type { LOINResolved } from '../types/resolved.js'
|
|
5
|
-
|
|
6
|
-
export class LOINEntity extends Entity<LOIN, true> {
|
|
7
|
-
constructor(getBep: () => BEP) {
|
|
8
|
-
super(
|
|
9
|
-
() => getBep().loin,
|
|
10
|
-
getBep,
|
|
11
|
-
{
|
|
12
|
-
key: 'loin',
|
|
13
|
-
schema: LOINSchema,
|
|
14
|
-
autoId: true,
|
|
15
|
-
validate: (item, bep) => {
|
|
16
|
-
const errors: string[] = []
|
|
17
|
-
for (const loinMilestone of item.milestones ?? []) {
|
|
18
|
-
if (!bep.milestones.some(m => m.id === loinMilestone.milestoneId))
|
|
19
|
-
errors.push(`milestones["${loinMilestone.milestoneId}"] not found`)
|
|
20
|
-
if (!bep.lods.some(l => l.id === loinMilestone.lodId))
|
|
21
|
-
errors.push(`lods[${loinMilestone.lodId}] not found`)
|
|
22
|
-
if (!bep.lois.some(l => l.id === loinMilestone.loiId))
|
|
23
|
-
errors.push(`lois[${loinMilestone.loiId}] not found`)
|
|
24
|
-
}
|
|
25
|
-
return errors
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
addMilestones(items: { loinId: LOIN['id']; milestones: LOINMilestone[] }[]): {
|
|
32
|
-
succeeded: { loinId: LOIN['id']; element: LOIN['element']; addedMilestones: LOINMilestone['milestoneId'][] }[]
|
|
33
|
-
failed: { loinId: LOIN['id']; error: string }[]
|
|
34
|
-
} {
|
|
35
|
-
const succeeded: { loinId: LOIN['id']; element: LOIN['element']; addedMilestones: LOINMilestone['milestoneId'][] }[] = []
|
|
36
|
-
const failed: { loinId: LOIN['id']; error: string }[] = []
|
|
37
|
-
|
|
38
|
-
for (const item of items) {
|
|
39
|
-
const loin = this.getBep().loin.find(l => l.id === item.loinId)
|
|
40
|
-
if (!loin) { failed.push({ loinId: item.loinId, error: `Not found: ${item.loinId}` }); continue }
|
|
41
|
-
|
|
42
|
-
const dup = item.milestones.find(m => (loin.milestones ?? []).some(lm => lm.milestoneId === m.milestoneId))
|
|
43
|
-
if (dup) { failed.push({ loinId: item.loinId, error: `Milestone "${dup.milestoneId}" already exists. Use updateMilestones to modify it.` }); continue }
|
|
44
|
-
|
|
45
|
-
const newMilestones = [...(loin.milestones ?? []), ...item.milestones]
|
|
46
|
-
const result = this.update([{ id: item.loinId, milestones: newMilestones }])
|
|
47
|
-
if (result.failed.length > 0) { failed.push({ loinId: item.loinId, error: result.failed[0].error }); continue }
|
|
48
|
-
|
|
49
|
-
succeeded.push({ loinId: item.loinId, element: loin.element, addedMilestones: item.milestones.map(m => m.milestoneId) })
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return { succeeded, failed }
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
updateMilestones(items: { loinId: LOIN['id']; milestones: (Partial<LOINMilestone> & { milestoneId: LOINMilestone['milestoneId'] })[] }[]): {
|
|
56
|
-
succeeded: { loinId: LOIN['id']; element: LOIN['element']; milestones: { milestoneId: LOINMilestone['milestoneId']; before: Omit<LOINMilestone, 'milestoneId'>; after: Omit<LOINMilestone, 'milestoneId'> }[] }[]
|
|
57
|
-
failed: { loinId: LOIN['id']; error: string }[]
|
|
58
|
-
} {
|
|
59
|
-
const succeeded: { loinId: LOIN['id']; element: LOIN['element']; milestones: { milestoneId: LOINMilestone['milestoneId']; before: Omit<LOINMilestone, 'milestoneId'>; after: Omit<LOINMilestone, 'milestoneId'> }[] }[] = []
|
|
60
|
-
const failed: { loinId: LOIN['id']; error: string }[] = []
|
|
61
|
-
|
|
62
|
-
for (const item of items) {
|
|
63
|
-
const loin = this.getBep().loin.find(l => l.id === item.loinId)
|
|
64
|
-
if (!loin) { failed.push({ loinId: item.loinId, error: `Not found: ${item.loinId}` }); continue }
|
|
65
|
-
|
|
66
|
-
const missing = item.milestones.find(m => !(loin.milestones ?? []).some(lm => lm.milestoneId === m.milestoneId))
|
|
67
|
-
if (missing) { failed.push({ loinId: item.loinId, error: `Milestone "${missing.milestoneId}" not found. Use addMilestones to create it.` }); continue }
|
|
68
|
-
|
|
69
|
-
const befores = new Map(loin.milestones!.map(m => [m.milestoneId, { lodId: m.lodId, loiId: m.loiId, idsPath: m.idsPath }]))
|
|
70
|
-
const newMilestones: LOINMilestone[] = (loin.milestones ?? []).map(lm => {
|
|
71
|
-
const patch = item.milestones.find(m => m.milestoneId === lm.milestoneId)
|
|
72
|
-
return patch ? { ...lm, ...patch } : lm
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
const result = this.update([{ id: item.loinId, milestones: newMilestones }])
|
|
76
|
-
if (result.failed.length > 0) { failed.push({ loinId: item.loinId, error: result.failed[0].error }); continue }
|
|
77
|
-
|
|
78
|
-
const updatedLoin = this.getBep().loin.find(l => l.id === item.loinId)!
|
|
79
|
-
succeeded.push({
|
|
80
|
-
loinId: item.loinId,
|
|
81
|
-
element: loin.element,
|
|
82
|
-
milestones: item.milestones.map(m => {
|
|
83
|
-
const after = updatedLoin.milestones!.find(lm => lm.milestoneId === m.milestoneId)!
|
|
84
|
-
const before = befores.get(m.milestoneId)!
|
|
85
|
-
return { milestoneId: m.milestoneId, before, after: { lodId: after.lodId, loiId: after.loiId, idsPath: after.idsPath } }
|
|
86
|
-
}),
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return { succeeded, failed }
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
removeMilestones(items: { loinId: LOIN['id']; milestoneIds: LOINMilestone['milestoneId'][] }[]): {
|
|
94
|
-
succeeded: { loinId: LOIN['id']; element: LOIN['element']; removedMilestones: LOINMilestone['milestoneId'][] }[]
|
|
95
|
-
failed: { loinId: LOIN['id']; error: string }[]
|
|
96
|
-
} {
|
|
97
|
-
const succeeded: { loinId: LOIN['id']; element: LOIN['element']; removedMilestones: LOINMilestone['milestoneId'][] }[] = []
|
|
98
|
-
const failed: { loinId: LOIN['id']; error: string }[] = []
|
|
99
|
-
|
|
100
|
-
for (const item of items) {
|
|
101
|
-
const loin = this.getBep().loin.find(l => l.id === item.loinId)
|
|
102
|
-
if (!loin) { failed.push({ loinId: item.loinId, error: `Not found: ${item.loinId}` }); continue }
|
|
103
|
-
|
|
104
|
-
const missing = item.milestoneIds.filter(id => !(loin.milestones ?? []).some(m => m.milestoneId === id))
|
|
105
|
-
if (missing.length > 0) { failed.push({ loinId: item.loinId, error: `Milestones not found in this LOIN: ${missing.join(', ')}` }); continue }
|
|
106
|
-
|
|
107
|
-
loin.milestones = (loin.milestones ?? []).filter(m => !item.milestoneIds.includes(m.milestoneId))
|
|
108
|
-
succeeded.push({ loinId: item.loinId, element: loin.element, removedMilestones: item.milestoneIds })
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return { succeeded, failed }
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
listResolved(): LOINResolved[] {
|
|
115
|
-
const bep = this.getBep()
|
|
116
|
-
return bep.loin.map(l => ({
|
|
117
|
-
...l,
|
|
118
|
-
discipline: bep.disciplines.find(d => d.id === l.disciplineId) ?? null,
|
|
119
|
-
milestones: (l.milestones ?? []).map(lm => ({
|
|
120
|
-
...lm,
|
|
121
|
-
milestone: bep.milestones.find(m => m.id === lm.milestoneId) ?? null,
|
|
122
|
-
lod: bep.lods.find(ld => ld.id === lm.lodId) ?? null,
|
|
123
|
-
loi: bep.lois.find(li => li.id === lm.loiId) ?? null,
|
|
124
|
-
})),
|
|
125
|
-
}))
|
|
126
|
-
}
|
|
127
|
-
}
|
package/src/entities/lois.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { BEP, LOI } from '../types/schema.js'
|
|
2
|
-
import { Entity } from '../base/entity.js'
|
|
3
|
-
import { LOISchema } from '../types/schema.js'
|
|
4
|
-
|
|
5
|
-
export class LOIs extends Entity<LOI> {
|
|
6
|
-
constructor(getBep: () => BEP) {
|
|
7
|
-
super(
|
|
8
|
-
() => getBep().lois,
|
|
9
|
-
getBep,
|
|
10
|
-
{
|
|
11
|
-
key: 'lois',
|
|
12
|
-
schema: LOISchema,
|
|
13
|
-
beforeRemove: (id, bep) => {
|
|
14
|
-
for (const loin of bep.loin) {
|
|
15
|
-
const ref = loin.milestones?.find(m => m.loiId === id)
|
|
16
|
-
if (ref) throw new Error(`Referenced by: loin["${loin.id}"].milestones[loiId=${id}]`)
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
}
|