@owlmeans/server-planning 0.1.18-rc.21 → 0.1.18-rc.22
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/README.md +24 -17
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-planning/SKILL.md +28 -28
- package/build/actions/apply-schema-request.d.ts +8 -0
- package/build/actions/apply-schema-request.d.ts.map +1 -0
- package/build/actions/apply-schema-request.js +31 -0
- package/build/actions/apply-schema-request.js.map +1 -0
- package/build/actions/commit.d.ts +3 -3
- package/build/actions/commit.d.ts.map +1 -1
- package/build/actions/commit.js +5 -4
- package/build/actions/commit.js.map +1 -1
- package/build/actions/define-schemas.d.ts +13 -0
- package/build/actions/define-schemas.d.ts.map +1 -0
- package/build/actions/define-schemas.js +28 -0
- package/build/actions/define-schemas.js.map +1 -0
- package/build/actions/execute.d.ts +8 -28
- package/build/actions/execute.d.ts.map +1 -1
- package/build/actions/execute.js +17 -101
- package/build/actions/execute.js.map +1 -1
- package/build/actions/execution/types.d.ts +34 -0
- package/build/actions/execution/types.d.ts.map +1 -0
- package/build/actions/execution/types.js +2 -0
- package/build/actions/execution/types.js.map +1 -0
- package/build/actions/execution.d.ts +4 -0
- package/build/actions/execution.d.ts.map +1 -0
- package/build/actions/execution.js +79 -0
- package/build/actions/execution.js.map +1 -0
- package/build/actions/get-card.d.ts +6 -0
- package/build/actions/get-card.d.ts.map +1 -0
- package/build/actions/get-card.js +9 -0
- package/build/actions/get-card.js.map +1 -0
- package/build/actions/get-specification.d.ts +6 -0
- package/build/actions/get-specification.d.ts.map +1 -0
- package/build/actions/get-specification.js +9 -0
- package/build/actions/get-specification.js.map +1 -0
- package/build/actions/index.d.ts +12 -3
- package/build/actions/index.d.ts.map +1 -1
- package/build/actions/index.js +11 -3
- package/build/actions/index.js.map +1 -1
- package/build/actions/links.d.ts +3 -3
- package/build/actions/links.d.ts.map +1 -1
- package/build/actions/links.js +6 -5
- package/build/actions/links.js.map +1 -1
- package/build/actions/list-card-specifications.d.ts +6 -0
- package/build/actions/list-card-specifications.d.ts.map +1 -0
- package/build/actions/list-card-specifications.js +11 -0
- package/build/actions/list-card-specifications.js.map +1 -0
- package/build/actions/list-card-transitions.d.ts +6 -0
- package/build/actions/list-card-transitions.d.ts.map +1 -0
- package/build/actions/list-card-transitions.js +11 -0
- package/build/actions/list-card-transitions.js.map +1 -0
- package/build/actions/list-cards.d.ts +6 -0
- package/build/actions/list-cards.d.ts.map +1 -0
- package/build/actions/list-cards.js +10 -0
- package/build/actions/list-cards.js.map +1 -0
- package/build/actions/list-schemas.d.ts +13 -0
- package/build/actions/list-schemas.d.ts.map +1 -0
- package/build/actions/list-schemas.js +20 -0
- package/build/actions/list-schemas.js.map +1 -0
- package/build/actions/{specs.d.ts → list-specification-revisions.d.ts} +1 -3
- package/build/actions/list-specification-revisions.d.ts.map +1 -0
- package/build/actions/list-specification-revisions.js +10 -0
- package/build/actions/list-specification-revisions.js.map +1 -0
- package/build/actions/summarize-cards.d.ts +6 -0
- package/build/actions/summarize-cards.d.ts.map +1 -0
- package/build/actions/summarize-cards.js +11 -0
- package/build/actions/summarize-cards.js.map +1 -0
- package/build/actions/transitions.d.ts +3 -3
- package/build/actions/transitions.d.ts.map +1 -1
- package/build/actions/transitions.js +4 -3
- package/build/actions/transitions.js.map +1 -1
- package/build/actions/types.d.ts +5 -3
- package/build/actions/types.d.ts.map +1 -1
- package/build/actions/watch.d.ts +2 -2
- package/build/actions/watch.d.ts.map +1 -1
- package/build/actions/watch.js +2 -2
- package/build/actions/watch.js.map +1 -1
- package/build/conformance/assert/types.d.ts +19 -0
- package/build/conformance/assert/types.d.ts.map +1 -0
- package/build/conformance/assert/types.js +2 -0
- package/build/conformance/assert/types.js.map +1 -0
- package/build/conformance/assert.d.ts +8 -13
- package/build/conformance/assert.d.ts.map +1 -1
- package/build/conformance/assert.js +41 -43
- package/build/conformance/assert.js.map +1 -1
- package/build/conformance/cases.d.ts.map +1 -1
- package/build/conformance/cases.js +86 -67
- package/build/conformance/cases.js.map +1 -1
- package/build/conformance/clock.d.ts +6 -0
- package/build/conformance/clock.d.ts.map +1 -0
- package/build/conformance/clock.js +12 -0
- package/build/conformance/clock.js.map +1 -0
- package/build/conformance/consts.d.ts +3 -1
- package/build/conformance/consts.d.ts.map +1 -1
- package/build/conformance/consts.js +84 -1
- package/build/conformance/consts.js.map +1 -1
- package/build/conformance/errors.d.ts +5 -0
- package/build/conformance/errors.d.ts.map +1 -0
- package/build/conformance/errors.js +8 -0
- package/build/conformance/errors.js.map +1 -0
- package/build/conformance/fixtures/types.d.ts +13 -0
- package/build/conformance/fixtures/types.d.ts.map +1 -0
- package/build/conformance/fixtures/types.js +2 -0
- package/build/conformance/fixtures/types.js.map +1 -0
- package/build/conformance/fixtures.d.ts +8 -8
- package/build/conformance/fixtures.d.ts.map +1 -1
- package/build/conformance/fixtures.js +24 -107
- package/build/conformance/fixtures.js.map +1 -1
- package/build/conformance/index.d.ts +3 -0
- package/build/conformance/index.d.ts.map +1 -1
- package/build/conformance/index.js +1 -0
- package/build/conformance/index.js.map +1 -1
- package/build/definitions.d.ts.map +1 -1
- package/build/definitions.js +9 -9
- package/build/definitions.js.map +1 -1
- package/build/executor/changes/types.d.ts +36 -0
- package/build/executor/changes/types.d.ts.map +1 -0
- package/build/executor/changes/types.js +2 -0
- package/build/executor/changes/types.js.map +1 -0
- package/build/executor/changes.d.ts +3 -30
- package/build/executor/changes.d.ts.map +1 -1
- package/build/executor/changes.js +42 -51
- package/build/executor/changes.js.map +1 -1
- package/build/executor/code/types.d.ts +17 -0
- package/build/executor/code/types.d.ts.map +1 -0
- package/build/executor/code/types.js +2 -0
- package/build/executor/code/types.js.map +1 -0
- package/build/executor/code.d.ts +3 -14
- package/build/executor/code.d.ts.map +1 -1
- package/build/executor/code.js +50 -54
- package/build/executor/code.js.map +1 -1
- package/build/executor/creator/types.d.ts +33 -0
- package/build/executor/creator/types.d.ts.map +1 -0
- package/build/executor/creator/types.js +2 -0
- package/build/executor/creator/types.js.map +1 -0
- package/build/executor/creator.d.ts +6 -25
- package/build/executor/creator.d.ts.map +1 -1
- package/build/executor/creator.js +26 -41
- package/build/executor/creator.js.map +1 -1
- package/build/executor/resolve/types.d.ts +30 -0
- package/build/executor/resolve/types.d.ts.map +1 -0
- package/build/executor/resolve/types.js +2 -0
- package/build/executor/resolve/types.js.map +1 -0
- package/build/executor/resolve.d.ts +4 -41
- package/build/executor/resolve.d.ts.map +1 -1
- package/build/executor/resolve.js +142 -157
- package/build/executor/resolve.js.map +1 -1
- package/build/executor/types.d.ts +0 -2
- package/build/executor/types.d.ts.map +1 -1
- package/build/executor/validate.d.ts +1 -1
- package/build/executor/validate.d.ts.map +1 -1
- package/build/executor/validate.js +16 -15
- package/build/executor/validate.js.map +1 -1
- package/build/executor.d.ts +4 -3
- package/build/executor.d.ts.map +1 -1
- package/build/executor.js +18 -17
- package/build/executor.js.map +1 -1
- package/build/facade.d.ts.map +1 -1
- package/build/facade.js +16 -16
- package/build/facade.js.map +1 -1
- package/build/helper.d.ts +1 -6
- package/build/helper.d.ts.map +1 -1
- package/build/helper.js +3 -8
- package/build/helper.js.map +1 -1
- package/build/projection.d.ts +2 -0
- package/build/projection.d.ts.map +1 -1
- package/build/projection.js +6 -4
- package/build/projection.js.map +1 -1
- package/build/queue/declare.d.ts +5 -0
- package/build/queue/declare.d.ts.map +1 -0
- package/build/queue/declare.js +5 -0
- package/build/queue/declare.js.map +1 -0
- package/build/queue/index.d.ts +1 -4
- package/build/queue/index.d.ts.map +1 -1
- package/build/queue/index.js +1 -4
- package/build/queue/index.js.map +1 -1
- package/build/store/composite.d.ts.map +1 -1
- package/build/store/composite.js +2 -2
- package/build/store/composite.js.map +1 -1
- package/build/store/fold/types.d.ts +43 -0
- package/build/store/fold/types.d.ts.map +1 -0
- package/build/store/fold/types.js +2 -0
- package/build/store/fold/types.js.map +1 -0
- package/build/store/fold.d.ts +7 -30
- package/build/store/fold.d.ts.map +1 -1
- package/build/store/fold.js +185 -203
- package/build/store/fold.js.map +1 -1
- package/build/store/index.d.ts +1 -0
- package/build/store/index.d.ts.map +1 -1
- package/build/store/index.js.map +1 -1
- package/build/store/memory.d.ts.map +1 -1
- package/build/store/memory.js +0 -0
- package/build/store/memory.js.map +1 -1
- package/build/store/types.local.d.ts +3 -1
- package/build/store/types.local.d.ts.map +1 -1
- package/build/types.d.ts +2 -1
- package/build/types.d.ts.map +1 -1
- package/build/utils/access/types.d.ts +30 -0
- package/build/utils/access/types.d.ts.map +1 -0
- package/build/utils/access/types.js +2 -0
- package/build/utils/access/types.js.map +1 -0
- package/build/utils/access.d.ts +4 -0
- package/build/utils/access.d.ts.map +1 -0
- package/build/utils/access.js +28 -0
- package/build/utils/access.js.map +1 -0
- package/build/utils/guard/types.d.ts +21 -0
- package/build/utils/guard/types.d.ts.map +1 -0
- package/build/utils/guard/types.js +2 -0
- package/build/utils/guard/types.js.map +1 -0
- package/build/utils/guard.d.ts +7 -10
- package/build/utils/guard.d.ts.map +1 -1
- package/build/utils/guard.js +33 -31
- package/build/utils/guard.js.map +1 -1
- package/build/utils/handler/types.d.ts +26 -0
- package/build/utils/handler/types.d.ts.map +1 -0
- package/build/utils/handler/types.js +2 -0
- package/build/utils/handler/types.js.map +1 -0
- package/build/utils/handler.d.ts +6 -0
- package/build/utils/handler.d.ts.map +1 -0
- package/build/utils/handler.js +21 -0
- package/build/utils/handler.js.map +1 -0
- package/build/utils/index.d.ts +8 -1
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js +3 -0
- package/build/utils/index.js.map +1 -1
- package/build/utils/request/types.d.ts +23 -0
- package/build/utils/request/types.d.ts.map +1 -0
- package/build/utils/request/types.js +2 -0
- package/build/utils/request/types.js.map +1 -0
- package/build/utils/request.d.ts +4 -0
- package/build/utils/request.d.ts.map +1 -0
- package/build/utils/request.js +27 -0
- package/build/utils/request.js.map +1 -0
- package/build/utils/scope.d.ts +10 -43
- package/build/utils/scope.d.ts.map +1 -1
- package/build/utils/scope.js +21 -99
- package/build/utils/scope.js.map +1 -1
- package/package.json +18 -18
- package/src/actions/apply-schema-request.ts +35 -0
- package/src/actions/commit.ts +7 -5
- package/src/actions/define-schemas.ts +34 -0
- package/src/actions/execute.ts +30 -115
- package/src/actions/execution/types.ts +34 -0
- package/src/actions/execution.ts +96 -0
- package/src/actions/get-card.ts +14 -0
- package/src/actions/get-specification.ts +14 -0
- package/src/actions/index.ts +13 -3
- package/src/actions/links.ts +8 -6
- package/src/actions/list-card-specifications.ts +15 -0
- package/src/actions/list-card-transitions.ts +15 -0
- package/src/actions/list-cards.ts +14 -0
- package/src/actions/list-schemas.ts +29 -0
- package/src/actions/{specs.ts → list-specification-revisions.ts} +4 -11
- package/src/actions/summarize-cards.ts +15 -0
- package/src/actions/transitions.ts +6 -4
- package/src/actions/types.ts +4 -3
- package/src/actions/watch.ts +4 -3
- package/src/conformance/assert/types.ts +16 -0
- package/src/conformance/assert.ts +49 -41
- package/src/conformance/cases.ts +88 -67
- package/src/conformance/clock.ts +11 -0
- package/src/conformance/consts.ts +87 -1
- package/src/conformance/errors.ts +7 -0
- package/src/conformance/fixtures/types.ts +11 -0
- package/src/conformance/fixtures.ts +32 -107
- package/src/conformance/index.ts +3 -0
- package/src/definitions.ts +9 -9
- package/src/executor/changes/types.ts +38 -0
- package/src/executor/changes.ts +48 -63
- package/src/executor/code/types.ts +23 -0
- package/src/executor/code.ts +60 -61
- package/src/executor/creator/types.ts +33 -0
- package/src/executor/creator.ts +33 -41
- package/src/executor/resolve/types.ts +30 -0
- package/src/executor/resolve.ts +153 -167
- package/src/executor/types.ts +0 -3
- package/src/executor/validate.ts +17 -16
- package/src/executor.ts +20 -17
- package/src/facade.ts +16 -16
- package/src/helper.ts +3 -8
- package/src/projection.ts +8 -4
- package/src/queue/declare.ts +7 -0
- package/src/queue/index.ts +1 -8
- package/src/store/composite.ts +2 -2
- package/src/store/fold/types.ts +44 -0
- package/src/store/fold.ts +209 -212
- package/src/store/index.ts +1 -0
- package/src/store/memory.ts +0 -0
- package/src/store/types.local.ts +1 -1
- package/src/types.ts +1 -1
- package/src/utils/access/types.ts +30 -0
- package/src/utils/access.ts +33 -0
- package/src/utils/guard/types.ts +19 -0
- package/src/utils/guard.ts +41 -30
- package/src/utils/handler/types.ts +28 -0
- package/src/utils/handler.ts +35 -0
- package/src/utils/index.ts +9 -1
- package/src/utils/request/types.ts +23 -0
- package/src/utils/request.ts +40 -0
- package/src/utils/scope.ts +25 -108
- package/tests/creator.spec.ts +18 -18
- package/build/actions/cards.d.ts +0 -14
- package/build/actions/cards.d.ts.map +0 -1
- package/build/actions/cards.js +0 -32
- package/build/actions/cards.js.map +0 -1
- package/build/actions/schemas.d.ts +0 -28
- package/build/actions/schemas.d.ts.map +0 -1
- package/build/actions/schemas.js +0 -69
- package/build/actions/schemas.js.map +0 -1
- package/build/actions/specs.d.ts.map +0 -1
- package/build/actions/specs.js +0 -14
- package/build/actions/specs.js.map +0 -1
- package/src/actions/cards.ts +0 -48
- package/src/actions/schemas.ts +0 -87
package/src/executor/resolve.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cardHelper, CardTypeNotAllowed, ParentNotFound, PlanningError, PlanningSchemaKind, PlanningScopeMismatch, SchemaOrigin, specificationHelper, statusHelper, TransitionAction, UnknownStatusFlow, UnknownWorkcardType, WorkcardKind, WorkcardNotFound, type AnyTypeSchema, type PlanningFacade, type PlanningSchemaRegistry, type ProjectTypeSchema, type ScopedSchemaRegistry, type Specification, type TransitionExecution, type Workcard, type WorkcardDraft } from '@owlmeans/planning'
|
|
2
|
+
import { memoHelper } from '@owlmeans/context'
|
|
2
3
|
import type { PlanningRuntime } from '../types.js'
|
|
3
4
|
import { TRIMMED } from './consts.local.js'
|
|
4
5
|
import type { Resolved } from './types.js'
|
|
6
|
+
import type { ResolveUtils } from './resolve/types.js'
|
|
5
7
|
|
|
6
8
|
const isScoped = (schemas: PlanningSchemaRegistry): schemas is ScopedSchemaRegistry =>
|
|
7
9
|
typeof (schemas as Partial<ScopedSchemaRegistry>).originOf === 'function'
|
|
@@ -30,189 +32,173 @@ const trim = <T extends object>(record: T | undefined): T | undefined => {
|
|
|
30
32
|
return copy as T
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
exec.unset = [...new Set(exec.unset)]
|
|
35
|
+
export const makeResolveUtils = (runtime: PlanningRuntime): ResolveUtils => {
|
|
36
|
+
const normalizeExecution = (input: TransitionExecution): TransitionExecution => {
|
|
37
|
+
const exec = structuredClone(input) as TransitionExecution
|
|
38
|
+
if (exec.card != null && typeof exec.card === 'object') {
|
|
39
|
+
const draft = trim(exec.card) as WorkcardDraft
|
|
40
|
+
const parents = cardHelper.normalizeParents(draft.parent, draft.parents)
|
|
41
|
+
exec.card = { ...draft, ...(parents.length > 0 ? { parents, parent: draft.parent ?? parents[0] } : {}) }
|
|
42
|
+
}
|
|
43
|
+
if (exec.changes != null) {
|
|
44
|
+
exec.changes = trim(exec.changes)
|
|
45
|
+
}
|
|
46
|
+
if (exec.unset != null) {
|
|
47
|
+
exec.unset = [...new Set(exec.unset)]
|
|
48
|
+
}
|
|
49
|
+
return exec
|
|
49
50
|
}
|
|
50
|
-
return exec
|
|
51
|
-
}
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
52
|
+
const assertChildAllowed = (
|
|
53
|
+
parent: Workcard, kind: WorkcardKind, type: string, view?: PlanningSchemaRegistry
|
|
54
|
+
): void => {
|
|
55
|
+
if (kind === WorkcardKind.Specification) {
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
if (!cardHelper.isProject(parent)) {
|
|
59
|
+
throw new CardTypeNotAllowed(`${parent.type}:${type}`)
|
|
60
|
+
}
|
|
61
|
+
const parentType = runtime.service().schemas.type(parent.type) as ProjectTypeSchema
|
|
62
|
+
const allowed = kind === WorkcardKind.Project ? parentType.projectTypes ?? [] : parentType.cardTypes ?? []
|
|
63
|
+
if (allowed.includes(type)) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
if (kind === WorkcardKind.Card && parentType.scopedCardTypes === true && dataDefined(view, type)) {
|
|
67
|
+
return
|
|
68
|
+
}
|
|
67
69
|
throw new CardTypeNotAllowed(`${parent.type}:${type}`)
|
|
68
70
|
}
|
|
69
|
-
const parentType = runtime.service().schemas.type(parent.type) as ProjectTypeSchema
|
|
70
|
-
const allowed = kind === WorkcardKind.Project ? parentType.projectTypes ?? [] : parentType.cardTypes ?? []
|
|
71
|
-
if (allowed.includes(type)) {
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
if (kind === WorkcardKind.Card && parentType.scopedCardTypes === true && dataDefined(view, type)) {
|
|
75
|
-
return
|
|
76
|
-
}
|
|
77
|
-
throw new CardTypeNotAllowed(`${parent.type}:${type}`)
|
|
78
|
-
}
|
|
79
71
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
let card: Workcard | undefined
|
|
104
|
-
let type: AnyTypeSchema
|
|
105
|
-
let parent: Workcard | undefined
|
|
106
|
-
|
|
107
|
-
if (create) {
|
|
108
|
-
if (exec.card == null || typeof exec.card !== 'object') {
|
|
109
|
-
throw new PlanningError('malformed:create-without-draft')
|
|
110
|
-
}
|
|
111
|
-
const draft = exec.card
|
|
112
|
-
const parents = normalizeParents(draft.parent, draft.parents)
|
|
113
|
-
const loaded = new Map<string, Workcard>()
|
|
114
|
-
if (layered) {
|
|
115
|
-
// Loaded through the facade, so a parent this scope cannot see is absent here too.
|
|
116
|
-
const primary = parents[0] != null ? await facade.cards.load(parents[0]) : null
|
|
117
|
-
if (parents[0] != null && primary == null) {
|
|
118
|
-
throw new ParentNotFound(parents[0])
|
|
72
|
+
const childViewOf = async (
|
|
73
|
+
entityId: string, parent: Workcard
|
|
74
|
+
): Promise<PlanningSchemaRegistry | undefined> =>
|
|
75
|
+
runtime.schemaStore() == null || !cardHelper.isProject(parent) ? undefined : await runtime.schemasFor(entityId, parent.id)
|
|
76
|
+
|
|
77
|
+
const resolveExecution = async (
|
|
78
|
+
facade: PlanningFacade, exec: TransitionExecution
|
|
79
|
+
): Promise<Resolved> => {
|
|
80
|
+
const service = runtime.service()
|
|
81
|
+
const entityId = facade.scope.entityId
|
|
82
|
+
const create = exec.action === TransitionAction.Create
|
|
83
|
+
// Without a schema port every step reads the code registry itself, in today's order; with one,
|
|
84
|
+
// the card's project is found first and the step reads that project's resolved layer.
|
|
85
|
+
const layered = runtime.schemaStore() != null
|
|
86
|
+
let schemas: PlanningSchemaRegistry = service.schemas
|
|
87
|
+
|
|
88
|
+
let card: Workcard | undefined
|
|
89
|
+
let type: AnyTypeSchema
|
|
90
|
+
let parent: Workcard | undefined
|
|
91
|
+
|
|
92
|
+
if (create) {
|
|
93
|
+
if (exec.card == null || typeof exec.card !== 'object') {
|
|
94
|
+
throw new PlanningError('malformed:create-without-draft')
|
|
119
95
|
}
|
|
120
|
-
|
|
121
|
-
|
|
96
|
+
const draft = exec.card
|
|
97
|
+
const parents = cardHelper.normalizeParents(draft.parent, draft.parents)
|
|
98
|
+
const loaded = new Map<string, Workcard>()
|
|
99
|
+
if (layered) {
|
|
100
|
+
// Loaded through the facade, so a parent this scope cannot see is absent here too.
|
|
101
|
+
const primary = parents[0] != null ? await facade.cards.load(parents[0]) : null
|
|
102
|
+
if (parents[0] != null && primary == null) {
|
|
103
|
+
throw new ParentNotFound(parents[0])
|
|
104
|
+
}
|
|
105
|
+
if (primary != null) {
|
|
106
|
+
loaded.set(parents[0], primary)
|
|
107
|
+
}
|
|
108
|
+
const project = draft.kind === WorkcardKind.Project || primary == null
|
|
109
|
+
? undefined
|
|
110
|
+
: cardHelper.projectOf({ kind: draft.kind, parent: parents[0], parents } as unknown as Workcard, primary)
|
|
111
|
+
schemas = await runtime.schemasFor(entityId, project)
|
|
122
112
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
113
|
+
type = schemas.type(draft.type)
|
|
114
|
+
if (type.kind !== draft.kind) {
|
|
115
|
+
throw new PlanningError(`malformed:kind:${draft.type}:${draft.kind}`)
|
|
116
|
+
}
|
|
117
|
+
if (layered && isScoped(schemas) && schemas.isRetired(PlanningSchemaKind.Type, draft.type)) {
|
|
118
|
+
// Existing cards keep resolving a retired type; nothing new is made of it.
|
|
119
|
+
throw new UnknownWorkcardType(`retired:${draft.type}`)
|
|
120
|
+
}
|
|
121
|
+
// Normalized: the primary parent is first. It must accept the child; so must every project
|
|
122
|
+
// among the secondary parents.
|
|
123
|
+
for (const [index, id] of parents.entries()) {
|
|
124
|
+
const found = loaded.get(id) ?? await facade.cards.load(id)
|
|
125
|
+
if (found == null) {
|
|
126
|
+
throw new ParentNotFound(id)
|
|
127
|
+
}
|
|
128
|
+
if (index === 0) {
|
|
129
|
+
parent = found
|
|
130
|
+
}
|
|
131
|
+
if (index === 0 || cardHelper.isProject(found)) {
|
|
132
|
+
const view = !layered ? undefined : index === 0 && cardHelper.isProject(found) ? schemas : await childViewOf(entityId, found)
|
|
133
|
+
assertChildAllowed(found, draft.kind, draft.type, view)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (draft.kind === WorkcardKind.Specification && parent == null) {
|
|
137
|
+
throw new PlanningError('malformed:specification-without-parent')
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
if (typeof exec.card !== 'string' || exec.card === '') {
|
|
141
|
+
throw new PlanningError(`malformed:${exec.action}-without-card`)
|
|
142
|
+
}
|
|
143
|
+
const found = await runtime.reader().cards.get(exec.card, entityId)
|
|
140
144
|
if (found == null) {
|
|
141
|
-
throw new
|
|
145
|
+
throw new WorkcardNotFound(exec.card)
|
|
142
146
|
}
|
|
143
|
-
if (
|
|
144
|
-
|
|
147
|
+
if (found.entityId !== entityId) {
|
|
148
|
+
throw new PlanningScopeMismatch(exec.card)
|
|
145
149
|
}
|
|
146
|
-
if (
|
|
147
|
-
|
|
148
|
-
|
|
150
|
+
if (facade.scope.projects != null && await facade.cards.load(exec.card) == null) {
|
|
151
|
+
// Outside the scope's projects: absent, exactly like another entity's card.
|
|
152
|
+
throw new WorkcardNotFound(exec.card)
|
|
153
|
+
}
|
|
154
|
+
card = found
|
|
155
|
+
if (layered) {
|
|
156
|
+
parent = card.parent != null ? await facade.cards.load(card.parent) ?? undefined : undefined
|
|
157
|
+
schemas = await runtime.schemasFor(entityId, cardHelper.projectOf(card, parent))
|
|
158
|
+
type = schemas.type(card.type)
|
|
159
|
+
} else {
|
|
160
|
+
type = schemas.type(card.type)
|
|
161
|
+
parent = card.parent != null ? await facade.cards.load(card.parent) ?? undefined : undefined
|
|
149
162
|
}
|
|
150
163
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (typeof exec.card !== 'string' || exec.card === '') {
|
|
156
|
-
throw new PlanningError(`malformed:${exec.action}-without-card`)
|
|
157
|
-
}
|
|
158
|
-
const found = await runtime.reader().cards.get(exec.card, entityId)
|
|
159
|
-
if (found == null) {
|
|
160
|
-
throw new WorkcardNotFound(exec.card)
|
|
161
|
-
}
|
|
162
|
-
if (found.entityId !== entityId) {
|
|
163
|
-
throw new PlanningScopeMismatch(exec.card)
|
|
164
|
-
}
|
|
165
|
-
if (facade.scope.projects != null && await facade.cards.load(exec.card) == null) {
|
|
166
|
-
// Outside the scope's projects: absent, exactly like another entity's card.
|
|
167
|
-
throw new WorkcardNotFound(exec.card)
|
|
168
|
-
}
|
|
169
|
-
card = found
|
|
170
|
-
if (layered) {
|
|
171
|
-
parent = card.parent != null ? await facade.cards.load(card.parent) ?? undefined : undefined
|
|
172
|
-
schemas = await runtime.schemasFor(entityId, projectOf(card, parent))
|
|
173
|
-
type = schemas.type(card.type)
|
|
174
|
-
} else {
|
|
175
|
-
type = schemas.type(card.type)
|
|
176
|
-
parent = card.parent != null ? await facade.cards.load(card.parent) ?? undefined : undefined
|
|
164
|
+
|
|
165
|
+
const flowId = exec.flow ?? statusHelper.primaryFlowOf(type)
|
|
166
|
+
if (!type.flows.includes(flowId)) {
|
|
167
|
+
throw new UnknownStatusFlow(`${type.type}:${flowId}`)
|
|
177
168
|
}
|
|
178
|
-
}
|
|
179
169
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
170
|
+
const kind = create ? (exec.card as WorkcardDraft).kind : card!.kind
|
|
171
|
+
const category = create ? (exec.card as WorkcardDraft).category : (card as Specification | undefined)?.category
|
|
172
|
+
const slot = kind === WorkcardKind.Specification && parent != null && category != null
|
|
173
|
+
? specificationHelper.slotOf(schemas.type(parent.type), category)
|
|
174
|
+
: undefined
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
create,
|
|
178
|
+
...(card != null ? { card } : {}),
|
|
179
|
+
type,
|
|
180
|
+
flowId,
|
|
181
|
+
flow: schemas.flow(flowId),
|
|
182
|
+
...(parent != null ? { parent } : {}),
|
|
183
|
+
...(slot != null ? { slot } : {}),
|
|
184
|
+
store: service.store(type.type),
|
|
185
|
+
schemas,
|
|
186
|
+
}
|
|
183
187
|
}
|
|
184
188
|
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
type,
|
|
195
|
-
flowId,
|
|
196
|
-
flow: schemas.flow(flowId),
|
|
197
|
-
...(parent != null ? { parent } : {}),
|
|
198
|
-
...(slot != null ? { slot } : {}),
|
|
199
|
-
store: service.store(type.type),
|
|
200
|
-
schemas,
|
|
189
|
+
const projectFor = (resolved: Resolved, exec: TransitionExecution, cardId: string): string | undefined => {
|
|
190
|
+
if (resolved.card != null) {
|
|
191
|
+
return cardHelper.isProject(resolved.card) ? resolved.card.id : cardHelper.projectOf(resolved.card, resolved.parent)
|
|
192
|
+
}
|
|
193
|
+
const draft = exec.card as WorkcardDraft
|
|
194
|
+
if (draft.kind === WorkcardKind.Project) {
|
|
195
|
+
return cardId
|
|
196
|
+
}
|
|
197
|
+
return cardHelper.projectOf({ kind: draft.kind, parent: draft.parent, parents: draft.parents ?? [] } as unknown as Workcard, resolved.parent)
|
|
201
198
|
}
|
|
202
|
-
}
|
|
203
199
|
|
|
204
|
-
|
|
205
|
-
const projectFor = (resolved: Resolved, exec: TransitionExecution, cardId: string): string | undefined => {
|
|
206
|
-
if (resolved.card != null) {
|
|
207
|
-
return isProject(resolved.card) ? resolved.card.id : projectOf(resolved.card, resolved.parent)
|
|
208
|
-
}
|
|
209
|
-
const draft = exec.card as WorkcardDraft
|
|
210
|
-
if (draft.kind === WorkcardKind.Project) {
|
|
211
|
-
return cardId
|
|
212
|
-
}
|
|
213
|
-
return projectOf({ kind: draft.kind, parent: draft.parent, parents: draft.parents ?? [] } as unknown as Workcard, resolved.parent)
|
|
200
|
+
return { normalizeExecution, assertChildAllowed, childViewOf, resolveExecution, projectFor }
|
|
214
201
|
}
|
|
215
202
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
export const resolveHelper = createResolveHelper()
|
|
203
|
+
/** The resolution steps of one service runtime — one per runtime. */
|
|
204
|
+
export const resolveUtilsOf = memoHelper.oncePer(makeResolveUtils)
|
package/src/executor/types.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { AnyTypeSchema, PlanningSchemaRegistry, PlanningStore, SpecificationSlot, StatusFlowSchema, Workcard } from '@owlmeans/planning'
|
|
2
|
-
import type { createResolveHelper } from './resolve.js'
|
|
3
2
|
|
|
4
3
|
/** Everything the steps after resolution read about an execution. */
|
|
5
4
|
export interface Resolved {
|
|
@@ -21,5 +20,3 @@ export interface Resolved {
|
|
|
21
20
|
*/
|
|
22
21
|
schemas: PlanningSchemaRegistry
|
|
23
22
|
}
|
|
24
|
-
|
|
25
|
-
export type ResolveHelper = ReturnType<typeof createResolveHelper>
|
package/src/executor/validate.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BODY_MAX, cardHelper, changesHelper, CODE_MAX, DESCRIPTION_MAX, IllegalTransition, LabelNotAllowed, MAX_LABELS, MAX_PARENTS, ParentNotFound, PlanningError, RelationshipRefused, specificationHelper, SpecificationRevisionConflict, SpecificationSlotUnknown, statusHelper, TITLE_MAX, TransitionAction, validateHelper, WorkcardKind, type PlanningFacade, type RelationshipDraft, type Specification, type TransitionExecution, type WorkcardDraft } from '@owlmeans/planning'
|
|
2
2
|
import type { PlanningRuntime } from '../types.js'
|
|
3
|
-
import {
|
|
3
|
+
import { creatorHelper } from './creator.js'
|
|
4
4
|
import type { Resolved } from './types.js'
|
|
5
5
|
import { ACTIONS } from './consts.local.js'
|
|
6
|
-
import {
|
|
6
|
+
import { resolveUtilsOf } from './resolve.js'
|
|
7
7
|
|
|
8
8
|
const malformed = (what: string): PlanningError => new PlanningError(`malformed:${what}`)
|
|
9
9
|
|
|
@@ -64,7 +64,7 @@ const assertFlow = (exec: TransitionExecution, resolved: Resolved): void => {
|
|
|
64
64
|
}
|
|
65
65
|
const card = resolved.card!
|
|
66
66
|
const from = card.flows[resolved.flowId] ?? card.status
|
|
67
|
-
if (ruleOf(resolved.flow, exec.transition!, from) == null) {
|
|
67
|
+
if (statusHelper.ruleOf(resolved.flow, exec.transition!, from) == null) {
|
|
68
68
|
throw new IllegalTransition(`${resolved.flowId}:${exec.transition}:${from}`)
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -73,15 +73,15 @@ const assertFields = (exec: TransitionExecution, resolved: Resolved): void => {
|
|
|
73
73
|
const schemas = resolved.schemas
|
|
74
74
|
if (resolved.create) {
|
|
75
75
|
const draft = exec.card as WorkcardDraft
|
|
76
|
-
validateFields(schemas, resolved.type.type, mergeFields(draft.fields, exec.changes?.fields))
|
|
76
|
+
validateHelper.validateFields(schemas, resolved.type.type, changesHelper.mergeFields(draft.fields, exec.changes?.fields))
|
|
77
77
|
return
|
|
78
78
|
}
|
|
79
79
|
const clears = (exec.unset ?? []).filter(path => path.startsWith('fields.'))
|
|
80
80
|
if (exec.changes?.fields == null && clears.length === 0) {
|
|
81
81
|
return
|
|
82
82
|
}
|
|
83
|
-
const merged = applyUnset({ fields: mergeFields(resolved.card!.fields, exec.changes?.fields) }, clears)
|
|
84
|
-
validateFields(schemas, resolved.type.type, merged.fields)
|
|
83
|
+
const merged = changesHelper.applyUnset({ fields: changesHelper.mergeFields(resolved.card!.fields, exec.changes?.fields) }, clears)
|
|
84
|
+
validateHelper.validateFields(schemas, resolved.type.type, merged.fields)
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
const assertLabels = (exec: TransitionExecution, resolved: Resolved): void => {
|
|
@@ -109,7 +109,8 @@ const assertParentMove = async (
|
|
|
109
109
|
return
|
|
110
110
|
}
|
|
111
111
|
const changes = exec.changes ?? {}
|
|
112
|
-
const
|
|
112
|
+
const resolve = resolveUtilsOf(runtime)
|
|
113
|
+
const moved = [...new Set(cardHelper.normalizeParents(changes.parent, changes.parents))]
|
|
113
114
|
.filter(id => id !== resolved.card!.parent && !resolved.card!.parents.includes(id))
|
|
114
115
|
for (const id of moved) {
|
|
115
116
|
if (id === resolved.card!.id) {
|
|
@@ -119,8 +120,8 @@ const assertParentMove = async (
|
|
|
119
120
|
if (found == null) {
|
|
120
121
|
throw new ParentNotFound(id)
|
|
121
122
|
}
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
resolve.assertChildAllowed(
|
|
124
|
+
found, resolved.card!.kind, resolved.card!.type, await resolve.childViewOf(facade.scope.entityId, found)
|
|
124
125
|
)
|
|
125
126
|
}
|
|
126
127
|
}
|
|
@@ -140,7 +141,7 @@ const assertSpecification = async (
|
|
|
140
141
|
if (draft.category == null || draft.category === '') {
|
|
141
142
|
throw malformed('specification-without-category')
|
|
142
143
|
}
|
|
143
|
-
const slot = slotOf(schemas.type(parent.type), draft.category)
|
|
144
|
+
const slot = specificationHelper.slotOf(schemas.type(parent.type), draft.category)
|
|
144
145
|
if (slot == null) {
|
|
145
146
|
throw new SpecificationSlotUnknown(`${parent.type}:${draft.category}`)
|
|
146
147
|
}
|
|
@@ -148,7 +149,7 @@ const assertSpecification = async (
|
|
|
148
149
|
throw malformed(`format:${draft.category}:${draft.format}`)
|
|
149
150
|
}
|
|
150
151
|
assertText('body', draft.body, BODY_MAX, false)
|
|
151
|
-
validateSpecificationBody(slot, draft.body)
|
|
152
|
+
validateHelper.validateSpecificationBody(slot, draft.body)
|
|
152
153
|
if (slot.multiple !== true && await facade.specifications.current(parent.id!, draft.category) != null) {
|
|
153
154
|
throw new SpecificationRevisionConflict(`${parent.id}:${draft.category}`)
|
|
154
155
|
}
|
|
@@ -169,7 +170,7 @@ const assertSpecification = async (
|
|
|
169
170
|
}
|
|
170
171
|
if (changes.body != null) {
|
|
171
172
|
assertText('body', changes.body, BODY_MAX, false)
|
|
172
|
-
validateSpecificationBody(slot, changes.body)
|
|
173
|
+
validateHelper.validateSpecificationBody(slot, changes.body)
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
|
|
@@ -226,7 +227,7 @@ const assertRelationships = async (
|
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
/**
|
|
229
|
-
* Step 6: shape, flow rule, immutables (`createdBy` among them,
|
|
230
|
+
* Step 6: shape, flow rule, immutables (`createdBy` among them, `creatorHelper.assertCreatorFixed`),
|
|
230
231
|
* `fields`, labels, parent moves, the specification slot and relationships — in that order.
|
|
231
232
|
* Nothing is written by a refusal here.
|
|
232
233
|
*
|
|
@@ -239,8 +240,8 @@ export const validateExecution = async (
|
|
|
239
240
|
): Promise<void> => {
|
|
240
241
|
assertShape(exec, resolved)
|
|
241
242
|
assertFlow(exec, resolved)
|
|
242
|
-
assertMutable(exec, resolved.type)
|
|
243
|
-
assertCreatorFixed(exec)
|
|
243
|
+
changesHelper.assertMutable(exec, resolved.type)
|
|
244
|
+
creatorHelper.assertCreatorFixed(exec)
|
|
244
245
|
assertFields(exec, resolved)
|
|
245
246
|
assertLabels(exec, resolved)
|
|
246
247
|
await assertParentMove(exec, resolved, runtime, facade)
|
package/src/executor.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
2
|
import type { BasicConfig, BasicContext } from '@owlmeans/context'
|
|
3
3
|
import { PlanningError, PlanningUnsupported, WorkcardConflict, type ExecuteOptions, type PlanningExecContext, type PlanningFacade, type PlanningPlugin, type PlanningStore, type Transition, type TransitionExecution, type TransitionReceipt } from '@owlmeans/planning'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { changesUtils } from './executor/changes.js'
|
|
5
|
+
import { codeUtils } from './executor/code.js'
|
|
6
|
+
import { creatorHelper } from './executor/creator.js'
|
|
7
7
|
import { makeReceipt } from './executor/receipt.js'
|
|
8
8
|
import type { Resolved } from './executor/types.js'
|
|
9
9
|
import { validateExecution } from './executor/validate.js'
|
|
10
10
|
import type { PlanningRuntime } from './types.js'
|
|
11
|
-
import {
|
|
11
|
+
import { resolveUtilsOf } from './executor/resolve.js'
|
|
12
|
+
import { idHelper } from '@owlmeans/basic-ids'
|
|
12
13
|
|
|
13
|
-
export { assertCreatorFixed, creatorOf, withCreator } from './executor/creator.js'
|
|
14
|
+
export { assertCreatorFixed, createCreatorHelper, creatorHelper, creatorOf, withCreator } from './executor/creator.js'
|
|
15
|
+
export type * from './executor/creator/types.js'
|
|
14
16
|
|
|
15
17
|
const isoNow = (): string => new Date().toISOString()
|
|
16
18
|
|
|
@@ -63,10 +65,10 @@ const currentReceipt = async (
|
|
|
63
65
|
/**
|
|
64
66
|
* THE write path. Nothing is appended before step 11, so every refusal leaves the log untouched.
|
|
65
67
|
*
|
|
66
|
-
* 1 normalize (a create's `createdBy` defaults to the scope's subject —
|
|
68
|
+
* 1 normalize (a create's `createdBy` defaults to the scope's subject — `creatorHelper.withCreator`) →
|
|
67
69
|
* 2 scope → 3 idempotency (a known `key` answers its first receipt, before any validation) →
|
|
68
70
|
* 4 resolve → 5 the plugins' `before` chain (re-resolved once when it moved the type or the parent)
|
|
69
|
-
* → 6 validate (a `createdBy` in `changes`/`unset` is refused —
|
|
71
|
+
* → 6 validate (a `createdBy` in `changes`/`unset` is refused — `creatorHelper.assertCreatorFixed`) →
|
|
70
72
|
* 7 allocate the card id → 8 code → 9 changes (an update changing nothing answers
|
|
71
73
|
* the current receipt and appends nothing) → 10 seq, a CAS against the head → 11 append →
|
|
72
74
|
* 12 request the projection → 13 receipt → 14 `wait`.
|
|
@@ -78,8 +80,9 @@ export const executeTransition = async (
|
|
|
78
80
|
): Promise<TransitionReceipt> => {
|
|
79
81
|
const scope = facade.scope
|
|
80
82
|
const at = (runtime.options.now ?? isoNow)()
|
|
83
|
+
const resolve = resolveUtilsOf(runtime)
|
|
81
84
|
|
|
82
|
-
let exec = withCreator(
|
|
85
|
+
let exec = creatorHelper.withCreator(resolve.normalizeExecution(input), scope)
|
|
83
86
|
|
|
84
87
|
if (scope.entityId == null || scope.entityId === '') {
|
|
85
88
|
throw new PlanningError('malformed:scope-without-entity')
|
|
@@ -92,12 +95,12 @@ export const executeTransition = async (
|
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
let resolved = await
|
|
98
|
+
let resolved = await resolve.resolveExecution(facade, exec)
|
|
96
99
|
|
|
97
100
|
const before = identityOf(exec)
|
|
98
|
-
exec =
|
|
101
|
+
exec = resolve.normalizeExecution(await runtime.registry.before(exec, execContextOf(runtime, facade, resolved)))
|
|
99
102
|
if (identityOf(exec) !== before) {
|
|
100
|
-
resolved = await
|
|
103
|
+
resolved = await resolve.resolveExecution(facade, exec)
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
await validateExecution(runtime, facade, exec, resolved)
|
|
@@ -109,12 +112,12 @@ export const executeTransition = async (
|
|
|
109
112
|
}
|
|
110
113
|
|
|
111
114
|
const cardId = resolved.create
|
|
112
|
-
? store.newId?.() ?? runtime.options.ids?.() ?? uuid()
|
|
115
|
+
? store.newId?.() ?? runtime.options.ids?.() ?? idHelper.uuid()
|
|
113
116
|
: resolved.card!.id!
|
|
114
117
|
|
|
115
|
-
exec = await assignCode(exec, resolved, scope, runtime.registry, execContextOf(runtime, facade, resolved))
|
|
118
|
+
exec = await codeUtils.assignCode(exec, resolved, scope, runtime.registry, execContextOf(runtime, facade, resolved))
|
|
116
119
|
|
|
117
|
-
const { set, empty } = changeSetOf(exec, resolved, resolved.schemas, at)
|
|
120
|
+
const { set, empty } = changesUtils.changeSetOf(exec, resolved, resolved.schemas, at)
|
|
118
121
|
if (empty) {
|
|
119
122
|
return await currentReceipt(store, resolved, scope.entityId, opts)
|
|
120
123
|
}
|
|
@@ -124,9 +127,9 @@ export const executeTransition = async (
|
|
|
124
127
|
throw new WorkcardConflict(`${cardId}:create:${seq}`)
|
|
125
128
|
}
|
|
126
129
|
|
|
127
|
-
const transition = transitionOf({
|
|
130
|
+
const transition = changesUtils.transitionOf({
|
|
128
131
|
exec, resolved, scope, set, cardId, seq, at,
|
|
129
|
-
project:
|
|
132
|
+
project: resolve.projectFor(resolved, exec, cardId),
|
|
130
133
|
})
|
|
131
134
|
|
|
132
135
|
let appended: Transition
|