@owlmeans/planning 0.1.18-rc.29 → 0.1.18-rc.30
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 +1 -1
- package/agent-meta/manifest.json +9 -4
- package/agent-meta/skills/planning/SKILL.md +7 -4
- package/agent-meta/skills/planning/parts/mounting.md +3 -0
- package/agent-meta/skills/planning/parts/types.md +55 -11
- package/build/helpers/app/consts.local.d.ts +5 -0
- package/build/helpers/app/consts.local.d.ts.map +1 -0
- package/build/helpers/app/consts.local.js +5 -0
- package/build/helpers/app/consts.local.js.map +1 -0
- package/build/helpers/app/types.d.ts +51 -0
- package/build/helpers/app/types.d.ts.map +1 -0
- package/build/helpers/app/types.js +2 -0
- package/build/helpers/app/types.js.map +1 -0
- package/build/helpers/app.d.ts +4 -0
- package/build/helpers/app.d.ts.map +1 -0
- package/build/helpers/app.js +134 -0
- package/build/helpers/app.js.map +1 -0
- package/build/helpers/index.d.ts +2 -0
- package/build/helpers/index.d.ts.map +1 -1
- package/build/helpers/index.js +1 -0
- package/build/helpers/index.js.map +1 -1
- package/build/helpers/scoped/types.d.ts +19 -7
- package/build/helpers/scoped/types.d.ts.map +1 -1
- package/build/helpers/scoped.d.ts +3 -3
- package/build/helpers/scoped.d.ts.map +1 -1
- package/build/helpers/scoped.js +10 -5
- package/build/helpers/scoped.js.map +1 -1
- package/build/registry.d.ts +3 -2
- package/build/registry.d.ts.map +1 -1
- package/build/registry.js +25 -3
- package/build/registry.js.map +1 -1
- package/build/schemas.d.ts +6 -1
- package/build/schemas.d.ts.map +1 -1
- package/build/schemas.js +16 -0
- package/build/schemas.js.map +1 -1
- package/build/types.d.ts +64 -1
- package/build/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/helpers/app/consts.local.ts +5 -0
- package/src/helpers/app/types.ts +52 -0
- package/src/helpers/app.ts +152 -0
- package/src/helpers/index.ts +2 -0
- package/src/helpers/scoped/types.ts +19 -7
- package/src/helpers/scoped.ts +12 -7
- package/src/registry.ts +29 -4
- package/src/schemas.ts +18 -1
- package/src/types.ts +66 -2
- package/tests/app.spec.ts +188 -0
package/README.md
CHANGED
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 3,
|
|
3
3
|
"package": "@owlmeans/planning",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.30",
|
|
5
|
+
"generatedAt": "2026-10-24T21:07:16.900Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -109,7 +109,7 @@
|
|
|
109
109
|
{
|
|
110
110
|
"name": "types",
|
|
111
111
|
"file": "skills/planning/parts/types.md",
|
|
112
|
-
"description": "Declaring card, project and specification types and status flows as closed data, the data-defined layers (code, entity, project) and retirement, and the rules every record schema keeps.",
|
|
112
|
+
"description": "Declaring card, project and specification types and status flows as closed data, the application's own definition properties and base card fields (`app`), the data-defined layers (code, entity, project) and retirement, and the rules every record schema keeps.",
|
|
113
113
|
"purposes": [
|
|
114
114
|
"data"
|
|
115
115
|
],
|
|
@@ -129,7 +129,12 @@
|
|
|
129
129
|
"putFlow",
|
|
130
130
|
"putAssigneeType",
|
|
131
131
|
"scopedCardTypes",
|
|
132
|
-
"overridable"
|
|
132
|
+
"overridable",
|
|
133
|
+
"appSchemaHelper",
|
|
134
|
+
"PlanningAppDeclarations",
|
|
135
|
+
"PlanningAppSchema",
|
|
136
|
+
"registerApp",
|
|
137
|
+
"fieldsSchema"
|
|
133
138
|
]
|
|
134
139
|
}
|
|
135
140
|
]
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/planning
|
|
9
9
|
|
|
10
10
|
**Layer:** Cross-cutting domain
|
|
11
|
-
**Install:** `"@owlmeans/planning": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/planning": "^0.1.18-rc.30"` in `dependencies` (`ajv` and `ajv-formats` are peers)
|
|
12
12
|
|
|
13
13
|
The contracts of project planning: record shapes, schemas, refusals, the protocol tree, the pure
|
|
14
14
|
fold and the models. No database, no fastify, no React. The executor, the plugin registry, the
|
|
@@ -46,6 +46,7 @@ forms generated code keeps writing are `server-planning` → Creating and readin
|
|
|
46
46
|
|---|---|
|
|
47
47
|
| `Workcard`, `Card`, `Project`, `Specification`, `Relationship`, `Transition` | The records |
|
|
48
48
|
| `StatusFlowSchema`, `WorkcardTypeSchema`, `ProjectTypeSchema`, `SpecificationSlot`, `CodePolicy`, `RelationshipType`, `PlanningSchemaBundle` | Type declarations — data, not code |
|
|
49
|
+
| `PlanningAppDeclarations`, `PlanningAppSchema`, `PlanningAppBagKind` | The application's own type/flow properties (`app` bags) and base card fields, declared in code |
|
|
49
50
|
| `TransitionExecution`, `WorkcardDraft`, `TransitionReceipt`, `CommitEvent`, `CommitSource` | The write path and its commit feed |
|
|
50
51
|
| `TransitionStore`, `ProjectionStore`, `SpecificationStore`, `RelationshipStore`, `SchemaStore`, `PlanningStore` | Ports a store implements (only `cards` is required) |
|
|
51
52
|
| `PlanningPlugin`, `PlanningScope`, `PlanningFacade`, `PlanningService`, `PlanningDefinitions` | The plugin seam and the facade, typed here so a plugin and a client can name them |
|
|
@@ -61,7 +62,8 @@ forms generated code keeps writing are `server-planning` → Creating and readin
|
|
|
61
62
|
| `codeHelper` — `mintCode`, `codeScopeOf`, `slugOf` | Codes |
|
|
62
63
|
| `specificationHelper` — `slotOf`, `currentSpecification`, `nextRevision`, `specificationTypeOf`, `bodyCharsOf` | Specifications |
|
|
63
64
|
| `makeAjv`, `validateHelper` — `validateFields`, `validateCard`, `validateSpecificationBody`, `invalidFieldKeys`, `ajvErrorText` | Validation |
|
|
64
|
-
| `makeSchemaRegistry(bundle?)` | Types, flows, cached
|
|
65
|
+
| `makeSchemaRegistry(bundle?)` | Types, flows, the app declarations (`registerApp`, `app`), `fieldsSchema(type)` and its cached validator; `bundle()` / `load()` |
|
|
66
|
+
| `appSchemaHelper` — `merge`, `assertDeclarations`, `bagSchemaOf`, `assertBag`, `fieldsSchemaOf` | The application's declarations: merge order, closed forms, a definition's `app` bag, a type's effective fields schema |
|
|
65
67
|
| `scopedSchemaHelper` — `resolveScopedBundle`, `scopedRegistryOf`, `assertTypeSchema`, `assertFlowSchema`, `assertOverridable`, `flowInUse`, `schemaRecordKey`, `schemaKeyOf` | Data-defined layers: resolution, the read-only view, the closed-form checks |
|
|
66
68
|
| `makePlanningProtocols(opts)` | The protocol tree |
|
|
67
69
|
| `makeWorkcardModel`, `makeProjectModel`, `makeSpecificationModel`, `modelOf`, `executeFor` | Models |
|
|
@@ -71,7 +73,8 @@ forms generated code keeps writing are `server-planning` → Creating and readin
|
|
|
71
73
|
|
|
72
74
|
- **Base fields at the top level, provider fields under `fields`.** `title`, `description`, `code`,
|
|
73
75
|
`status`, `labels`, `order`, `parent` are generic and indexable; everything a type adds lives in
|
|
74
|
-
`fields` and is validated by the type's `fields` JSON schema
|
|
76
|
+
`fields` and is validated by the type's `fields` JSON schema — beside the application's base card
|
|
77
|
+
fields (`schemas.app.card`, the `types` part). Generic code reads only the top.
|
|
75
78
|
A `fields` key never holds `.` or `$` at any depth (`validateHelper.invalidFieldKeys`).
|
|
76
79
|
- **`entityId` is the organization's stable record id** — never the wire `entitySlug`, never a body
|
|
77
80
|
value. Every read is scoped by it; where a request's comes from is `server-planning` → Scope and
|
|
@@ -150,7 +153,7 @@ Load a part on top of this core when its job is in play.
|
|
|
150
153
|
|
|
151
154
|
| Part | Load it when |
|
|
152
155
|
|---|---|
|
|
153
|
-
| [types](parts/types.md) | Declaring a type or a status flow, data-defined types and flows (`scopedSchemaHelper`), or a new record schema |
|
|
156
|
+
| [types](parts/types.md) | Declaring a type or a status flow, the application's own properties and base card fields (`app`, `appSchemaHelper`), data-defined types and flows (`scopedSchemaHelper`), or a new record schema |
|
|
154
157
|
| [fold](parts/fold.md) | Folding transitions (`applyHelper`, `changesHelper`) or translating a `WorkcardQuery` (`queryHelper`, `wireHelper`) |
|
|
155
158
|
| [mounting](parts/mounting.md) | Declaring or mounting the protocol tree (`makePlanningProtocols`), or serving it in a generated target |
|
|
156
159
|
| [errors](parts/errors.md) | Throwing, matching or phrasing a planning refusal (marker, HTTP status, i18n text) |
|
|
@@ -59,3 +59,6 @@ routes; domain rules are `before` plugins. This section is the hub; each package
|
|
|
59
59
|
`overridable: true` with open `fields` (`additionalProperties: true`); the container project type
|
|
60
60
|
(always sealed) carries `scopedCardTypes: true`, so the app's people override and extend them as
|
|
61
61
|
data through `schema.define`.
|
|
62
|
+
- What the app itself keeps about every type, flow or card (a type's `description`, an origin's
|
|
63
|
+
attribute planning has no key for) is `PLANNING.schemas.app` — never an extra key on a type or a
|
|
64
|
+
flow (the `types` part, Application-declared properties).
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: types
|
|
3
|
-
description: Declaring card, project and specification types and status flows as closed data, the data-defined layers (code, entity, project) and retirement, and the rules every record schema keeps.
|
|
3
|
+
description: Declaring card, project and specification types and status flows as closed data, the application's own definition properties and base card fields (`app`), the data-defined layers (code, entity, project) and retirement, and the rules every record schema keeps.
|
|
4
4
|
metadata:
|
|
5
5
|
purposes: data
|
|
6
|
-
mentions: WorkcardTypeSchema, ProjectTypeSchema, StatusFlowSchema, SpecificationSlot, CodePolicy, makeSchemaRegistry, scopedSchemaHelper, resolveScopedBundle, ScopedSchemaRecord, ScopedSchemaBundle, SchemaStore, putType, putFlow, putAssigneeType, scopedCardTypes, overridable
|
|
6
|
+
mentions: WorkcardTypeSchema, ProjectTypeSchema, StatusFlowSchema, SpecificationSlot, CodePolicy, makeSchemaRegistry, scopedSchemaHelper, resolveScopedBundle, ScopedSchemaRecord, ScopedSchemaBundle, SchemaStore, putType, putFlow, putAssigneeType, scopedCardTypes, overridable, appSchemaHelper, PlanningAppDeclarations, PlanningAppSchema, registerApp, fieldsSchema
|
|
7
7
|
---
|
|
8
8
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
9
9
|
|
|
@@ -17,16 +17,18 @@ the keys:
|
|
|
17
17
|
|
|
18
18
|
| Declaration | Required | Optional |
|
|
19
19
|
|---|---|---|
|
|
20
|
-
| card / specification type | `type` (its key), `kind`, `version`, `fields`, `flows` (at least one), `specifications` | `intrinsic`, `relationships`, `labels`, `code`, `label`, `tone`, `icon`, `overridable` |
|
|
20
|
+
| card / specification type | `type` (its key), `kind`, `version`, `fields`, `flows` (at least one), `specifications` | `intrinsic`, `relationships`, `labels`, `code`, `label`, `tone`, `icon`, `overridable`, `app` |
|
|
21
21
|
| project type | the same, plus `cardTypes` | `projectTypes`, `scopedCardTypes` |
|
|
22
|
-
| flow | `id` (its key), `version`, `statuses` (at least one), `transitions` | `label`, `tone`, `icon`, `overridable` |
|
|
22
|
+
| flow | `id` (its key), `version`, `statuses` (at least one), `transitions` | `label`, `tone`, `icon`, `overridable`, `app` |
|
|
23
23
|
| status | `key`, `intrinsic` | `initial`, `terminal`, `label`, `tone` |
|
|
24
24
|
| transition rule | `name`, `from` (status keys or `'*'`), `to` | `label`, `explicit` |
|
|
25
25
|
|
|
26
26
|
The display name is `label` everywhere; a type or a flow has no `name`, `key` or `description`
|
|
27
|
-
(`key` belongs to a status, `name` to a rule).
|
|
28
|
-
`
|
|
29
|
-
|
|
27
|
+
(`key` belongs to a status, `name` to a rule). Anything else the application keeps about a type or
|
|
28
|
+
a flow — a `description`, an origin's attribute — goes in its `app` bag, which the application
|
|
29
|
+
declares (below). As data, `definitions` refuses an extra key with `SchemaInvalid`; in code the
|
|
30
|
+
registry does not validate a declaration, so only TypeScript's excess-property check catches it —
|
|
31
|
+
keep the literal typed.
|
|
30
32
|
|
|
31
33
|
- `fields` — the AJV schema of `fields`; the registry compiles and caches it (`validator(type)`).
|
|
32
34
|
- `specifications` — the slots this type's cards carry as children. A slot may name its
|
|
@@ -49,6 +51,48 @@ excess-property check catches it — keep the literal typed.
|
|
|
49
51
|
`colors`). An unknown value renders the picker's fallback (`slate`, `circle`); server code and
|
|
50
52
|
seeds read the data React-free from `@owlmeans/web-panel/picker/vocabulary`.
|
|
51
53
|
|
|
54
|
+
## Application-declared properties (`app`)
|
|
55
|
+
|
|
56
|
+
Two kinds of field exist: the custom ones a data-defined type gives its cards (its `fields`,
|
|
57
|
+
written by the app's people), and the ones the APPLICATION pregenerates in code for every type,
|
|
58
|
+
flow or card. The latter are `PlanningAppDeclarations { type?, flow?, card? }`, declared in
|
|
59
|
+
`PlanningPlugin.schemas.app` (and `PlanningServiceOptions.schemas.app`) and served in the bundle
|
|
60
|
+
(`bundle.app`, `registry.app()`):
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
schemas: { app: {
|
|
64
|
+
type: { properties: { description: { type: 'string', maxLength: 2000 } } },
|
|
65
|
+
flow: { properties: { description: { type: 'string' } } },
|
|
66
|
+
card: { properties: { priority: { type: 'string', enum: ['low', 'high'] } } },
|
|
67
|
+
} }
|
|
68
|
+
// then a type: { type: 'wm:task', …, app: { description: 'Work items' } }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- **Closed form** (`appSchemaHelper.assertDeclarations` → `SchemaInvalid('app:<kind>:…')`): each
|
|
72
|
+
kind is `{ type?: 'object', properties, required? }` and nothing else; property names hold no
|
|
73
|
+
`.` or `$`; every `required` name is declared in the same declaration; the schema compiles.
|
|
74
|
+
- **Merge** (`appSchemaHelper.merge`, run by the server's plugin registry on every `use` and by
|
|
75
|
+
the client over the served bundle): the service's own `schemas.app` first, then each plugin's in
|
|
76
|
+
plugin order (`order` ascending, registration order among equals). Per kind `properties` are
|
|
77
|
+
united — a later declaration of a name replaces the earlier one whole — and `required` is united.
|
|
78
|
+
A plugin replaced by name takes its declarations with it. The result is normalized
|
|
79
|
+
(`type: 'object'`); nothing declared → `undefined` and no `app` key in any bundle.
|
|
80
|
+
- **`type` / `flow` → the definition's `app` bag**, closed over the declared properties
|
|
81
|
+
(`additionalProperties: false`; an absent bag reads `{}`, so a `required` property makes the bag
|
|
82
|
+
mandatory). Checked on every data-defined write — `define`, `put*`, `seed`, the wire
|
|
83
|
+
`schema.define` — by `assertTypeSchema(type, flows, app)` / `assertFlowSchema(flow, app)`. A kind
|
|
84
|
+
the application does not declare refuses any bag (`<kind>:<key>:app:undeclared`). Code
|
|
85
|
+
declarations are not validated (as every code declaration); a record written under earlier
|
|
86
|
+
declarations still resolves.
|
|
87
|
+
- **`card` → base `fields` of every type of kind `card`**, code or data-defined
|
|
88
|
+
(`registry.fieldsSchema(type)`, compiled by `registry.validator(type)`). The type's schema stays
|
|
89
|
+
the root (its `#/…` references still resolve); each base name absent from its top-level
|
|
90
|
+
`properties` is added as `{}` — so its `additionalProperties: false` never refuses a base field —
|
|
91
|
+
and the base object schema is appended to its `allOf`. A type that declares a base name itself
|
|
92
|
+
narrows it (both apply). Projects and specifications are untouched. A required base field, like a
|
|
93
|
+
newly required type field, refuses every later write of a card that lacks it.
|
|
94
|
+
- Without declarations every behavior is the previous one: `fieldsSchema(type)` IS `type.fields`.
|
|
95
|
+
|
|
52
96
|
## Data-defined types and flows
|
|
53
97
|
|
|
54
98
|
Card types, assignee types and status flows may also be DATA — `ScopedSchemaRecord`s a store keeps
|
|
@@ -64,9 +108,9 @@ assignee types layer **code → entity** and refuse a project-local declaration:
|
|
|
64
108
|
- A record's `version` is its compare-and-set token and is written into the declaration's own
|
|
65
109
|
`version`: a write lands only at its layer's next version, 1 for a new key (`SchemaConflict`).
|
|
66
110
|
- The closed-form checks are shared by every store: `scopedSchemaHelper.assertFlowSchema` (the declaration's schema,
|
|
67
|
-
unique status keys, every `to` declared, `from` `'*'` or declared statuses) and
|
|
68
|
-
`scopedSchemaHelper.assertTypeSchema` (the `card` kind, a
|
|
69
|
-
`SchemaInvalid`.
|
|
111
|
+
unique status keys, every `to` declared, `from` `'*'` or declared statuses, the `app` bag) and
|
|
112
|
+
`scopedSchemaHelper.assertTypeSchema` (the `card` kind, the `app` bag, a `fields` schema that
|
|
113
|
+
compiles with the base card fields, unique flows that resolve) — `SchemaInvalid`.
|
|
70
114
|
- **Retired** means offered for nothing new, still resolved for what uses it: a retired record
|
|
71
115
|
gives way to a live declaration below it, and a key retired in every layer resolves retired —
|
|
72
116
|
present in the bundle's `types`/`flows`, listed in `retired`. A flow cannot be retired while a
|
|
@@ -74,7 +118,7 @@ assignee types layer **code → entity** and refuse a project-local declaration:
|
|
|
74
118
|
- `scopedSchemaHelper.resolveScopedBundle(code, records, scope)` is the ONE resolution (pure);
|
|
75
119
|
`scopedRegistryOf` is its read-only registry (`originOf`, `isRetired`; `register*`/`load` refuse). A
|
|
76
120
|
`ScopedSchemaBundle` extends the plain bundle with `scope`, `revision`, `origins`, `retired`, so a
|
|
77
|
-
reader of the plain bundle is unaffected.
|
|
121
|
+
reader of the plain bundle is unaffected; the code bundle's `app` passes through.
|
|
78
122
|
- `SchemaStore`: `list(where)`, `put(record)` (the CAS), `purge({ entityId, project })`,
|
|
79
123
|
`revision(entityId)` (monotonic per organization), optional `watch(listener)`.
|
|
80
124
|
- `PlanningFacade.definitions` (present only where the store has the port): `bundle(project?)`,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The kinds an application declares properties for, in merge order. */
|
|
2
|
+
export declare const APP_KINDS: readonly ['type', 'flow', 'card'];
|
|
3
|
+
/** The only keywords a kind's declaration may carry — a merge by name honours nothing else. */
|
|
4
|
+
export declare const APP_SCHEMA_KEYS: Set<string>;
|
|
5
|
+
//# sourceMappingURL=consts.local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../../../src/helpers/app/consts.local.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,eAAO,MAAM,SAAS,YAAI,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAA;AAE1D,+FAA+F;AAC/F,eAAO,MAAM,eAAe,aAA8C,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** The kinds an application declares properties for, in merge order. */
|
|
2
|
+
export const APP_KINDS = ['type', 'flow', 'card'];
|
|
3
|
+
/** The only keywords a kind's declaration may carry — a merge by name honours nothing else. */
|
|
4
|
+
export const APP_SCHEMA_KEYS = new Set(['type', 'properties', 'required']);
|
|
5
|
+
//# sourceMappingURL=consts.local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../../../src/helpers/app/consts.local.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAA;AAE1D,+FAA+F;AAC/F,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { AnySchema } from 'ajv';
|
|
2
|
+
import type { PlanningSchemaKind } from '../../consts.js';
|
|
3
|
+
import type { AnyTypeSchema, PlanningAppDeclarations } from '../../types.js';
|
|
4
|
+
/** The declarations whose properties a definition carries in its `app` bag. */
|
|
5
|
+
export type PlanningAppBagKind = PlanningSchemaKind.Type | PlanningSchemaKind.Flow;
|
|
6
|
+
/**
|
|
7
|
+
* The application's pregenerated planning properties: the `app` bag of every type and flow
|
|
8
|
+
* declaration, and the base `fields` of every card — declared in code, beside the custom fields a
|
|
9
|
+
* data-defined type gives its cards.
|
|
10
|
+
*/
|
|
11
|
+
export interface AppSchemaHelper {
|
|
12
|
+
/**
|
|
13
|
+
* Merge declarations in the order given — a planning service passes its own `schemas.app` first,
|
|
14
|
+
* then every plugin's in plugin order (`order` ascending, registration order among equals). Per
|
|
15
|
+
* kind (`type`, `flow`, `card`): `properties` are united, a later declaration of a name replacing
|
|
16
|
+
* the earlier one whole; `required` is the union. `undefined` when no source declares anything.
|
|
17
|
+
*
|
|
18
|
+
* @throws {SchemaInvalid} a malformed source
|
|
19
|
+
*/
|
|
20
|
+
merge: (sources: ReadonlyArray<PlanningAppDeclarations | undefined>) => PlanningAppDeclarations | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* The closed form of declarations: per kind only `type` (`'object'`), `properties` (names without
|
|
23
|
+
* `.` or `$`) and `required` (each name declared), and a schema that compiles.
|
|
24
|
+
*
|
|
25
|
+
* @throws {SchemaInvalid} `app:<kind>:…`
|
|
26
|
+
*/
|
|
27
|
+
assertDeclarations: (app: PlanningAppDeclarations) => void;
|
|
28
|
+
/**
|
|
29
|
+
* The schema a definition's `app` bag must match: the declared kind closed over its properties
|
|
30
|
+
* (`additionalProperties: false`). `undefined` when the kind is not declared.
|
|
31
|
+
*/
|
|
32
|
+
bagSchemaOf: (app: PlanningAppDeclarations | undefined, kind: PlanningAppBagKind) => AnySchema | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Check a declaration's `app` bag: refused when the kind is undeclared and the bag is present;
|
|
35
|
+
* matched against {@link bagSchemaOf} otherwise (an absent bag is `{}`, so a required property
|
|
36
|
+
* makes the bag mandatory).
|
|
37
|
+
*
|
|
38
|
+
* @throws {SchemaInvalid} `<kind>:<key>:app:…`
|
|
39
|
+
*/
|
|
40
|
+
assertBag: (kind: PlanningAppBagKind, key: string, bag: unknown, app?: PlanningAppDeclarations) => void;
|
|
41
|
+
/**
|
|
42
|
+
* The schema a type's `fields` validate against. Without base card fields, or for a project or
|
|
43
|
+
* specification type, it is the type's own `fields` object itself. Otherwise the type's schema
|
|
44
|
+
* stays the root (so its `#/…` references still resolve) and gains: each base name in its
|
|
45
|
+
* top-level `properties` as `{}` when it does not declare it (its `additionalProperties` never
|
|
46
|
+
* refuses a base field; its own declaration of the name still applies and may narrow it), and the
|
|
47
|
+
* base object schema appended to its `allOf`.
|
|
48
|
+
*/
|
|
49
|
+
fieldsSchemaOf: (type: AnyTypeSchema, app?: PlanningAppDeclarations) => AnySchema;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/helpers/app/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AACpC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAA;AAE5E,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAA;AAElF;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,KAAK,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC,uBAAuB,GAAG,SAAS,CAAC,KAAK,uBAAuB,GAAG,SAAS,CAAA;IAC3G;;;;;OAKG;IACH,kBAAkB,EAAE,CAAC,GAAG,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAC1D;;;OAGG;IACH,WAAW,EAAE,CAAC,GAAG,EAAE,uBAAuB,GAAG,SAAS,EAAE,IAAI,EAAE,kBAAkB,KAAK,SAAS,GAAG,SAAS,CAAA;IAC1G;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAA;IACvG;;;;;;;OAOG;IACH,cAAc,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,uBAAuB,KAAK,SAAS,CAAA;CAClF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/helpers/app/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/helpers/app.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,gBAAgB,CAAA;AASzE,eAAO,MAAM,qBAAqB,QAAO,eAwIxC,CAAA;AAED,eAAO,MAAM,eAAe,iBAA0B,CAAA"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { PlanningSchemaKind, WorkcardKind } from '../consts.js';
|
|
2
|
+
import { SchemaInvalid } from '../errors.js';
|
|
3
|
+
import { APP_KINDS, APP_SCHEMA_KEYS } from './app/consts.local.js';
|
|
4
|
+
import { makeAjv, validateHelper } from './validate.js';
|
|
5
|
+
const messageOf = (error) => error instanceof Error ? error.message : `${error}`;
|
|
6
|
+
const isObject = (value) => value != null && typeof value === 'object' && !Array.isArray(value);
|
|
7
|
+
export const createAppSchemaHelper = () => {
|
|
8
|
+
// Keyed by the declared kind object a registry keeps — a fresh ajv per entry, so a replaced
|
|
9
|
+
// declaration leaves nothing compiled behind.
|
|
10
|
+
const bags = new WeakMap();
|
|
11
|
+
const objectSchemaOf = (declared) => ({
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: declared.properties,
|
|
14
|
+
...((declared.required?.length ?? 0) > 0 ? { required: [...declared.required] } : {}),
|
|
15
|
+
});
|
|
16
|
+
const declaredOf = (app, kind) => kind === PlanningSchemaKind.Type ? app?.type : app?.flow;
|
|
17
|
+
const assertDeclarations = app => {
|
|
18
|
+
if (!isObject(app)) {
|
|
19
|
+
throw new SchemaInvalid('app:declarations');
|
|
20
|
+
}
|
|
21
|
+
const kinds = APP_KINDS;
|
|
22
|
+
const stranger = Object.keys(app).find(key => !kinds.includes(key));
|
|
23
|
+
if (stranger != null) {
|
|
24
|
+
throw new SchemaInvalid(`app:kind:${stranger}`);
|
|
25
|
+
}
|
|
26
|
+
for (const kind of APP_KINDS) {
|
|
27
|
+
const declared = app[kind];
|
|
28
|
+
if (declared == null) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (!isObject(declared)) {
|
|
32
|
+
throw new SchemaInvalid(`app:${kind}:schema`);
|
|
33
|
+
}
|
|
34
|
+
const keyword = Object.keys(declared).find(key => !APP_SCHEMA_KEYS.has(key));
|
|
35
|
+
if (keyword != null) {
|
|
36
|
+
throw new SchemaInvalid(`app:${kind}:keyword:${keyword}`);
|
|
37
|
+
}
|
|
38
|
+
if (declared.type != null && declared.type !== 'object') {
|
|
39
|
+
throw new SchemaInvalid(`app:${kind}:type`);
|
|
40
|
+
}
|
|
41
|
+
if (!isObject(declared.properties)) {
|
|
42
|
+
throw new SchemaInvalid(`app:${kind}:properties`);
|
|
43
|
+
}
|
|
44
|
+
const names = Object.keys(declared.properties);
|
|
45
|
+
const badName = names.find(name => name === '' || name.includes('.') || name.includes('$'));
|
|
46
|
+
if (badName != null) {
|
|
47
|
+
throw new SchemaInvalid(`app:${kind}:name:${badName}`);
|
|
48
|
+
}
|
|
49
|
+
const required = declared.required;
|
|
50
|
+
if (required != null && (!Array.isArray(required) || required.some(name => typeof name !== 'string'))) {
|
|
51
|
+
throw new SchemaInvalid(`app:${kind}:required`);
|
|
52
|
+
}
|
|
53
|
+
const missing = required?.find(name => !names.includes(name));
|
|
54
|
+
if (missing != null) {
|
|
55
|
+
throw new SchemaInvalid(`app:${kind}:required:${missing}`);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
makeAjv().compile(objectSchemaOf(declared));
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new SchemaInvalid(`app:${kind}:${messageOf(error)}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const merge = sources => {
|
|
66
|
+
const merged = {};
|
|
67
|
+
for (const source of sources) {
|
|
68
|
+
if (source == null) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
assertDeclarations(source);
|
|
72
|
+
for (const kind of APP_KINDS) {
|
|
73
|
+
const next = source[kind];
|
|
74
|
+
if (next == null) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const current = merged[kind];
|
|
78
|
+
const required = [...new Set([...(current?.required ?? []), ...(next.required ?? [])])];
|
|
79
|
+
merged[kind] = {
|
|
80
|
+
type: 'object',
|
|
81
|
+
properties: { ...current?.properties, ...structuredClone(next.properties) },
|
|
82
|
+
...(required.length > 0 ? { required } : {}),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
87
|
+
};
|
|
88
|
+
const bagSchemaOf = (app, kind) => {
|
|
89
|
+
const declared = declaredOf(app, kind);
|
|
90
|
+
return declared == null ? undefined : { ...objectSchemaOf(declared), additionalProperties: false };
|
|
91
|
+
};
|
|
92
|
+
const assertBag = (kind, key, bag, app) => {
|
|
93
|
+
const declared = declaredOf(app, kind);
|
|
94
|
+
if (declared == null) {
|
|
95
|
+
if (bag != null) {
|
|
96
|
+
throw new SchemaInvalid(`${kind}:${key}:app:undeclared`);
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const keys = validateHelper.invalidFieldKeys(bag);
|
|
101
|
+
if (keys.length > 0) {
|
|
102
|
+
throw new SchemaInvalid(`${kind}:${key}:app:keys:${keys.join(',')}`);
|
|
103
|
+
}
|
|
104
|
+
let validate = bags.get(declared);
|
|
105
|
+
if (validate == null) {
|
|
106
|
+
validate = makeAjv().compile(bagSchemaOf(app, kind));
|
|
107
|
+
bags.set(declared, validate);
|
|
108
|
+
}
|
|
109
|
+
if (!validate(bag ?? {})) {
|
|
110
|
+
throw new SchemaInvalid(`${kind}:${key}:app:${validateHelper.ajvErrorText(validate.errors)}`);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const fieldsSchemaOf = (type, app) => {
|
|
114
|
+
const base = app?.card;
|
|
115
|
+
const own = type.fields;
|
|
116
|
+
if (base == null || type.kind !== WorkcardKind.Card) {
|
|
117
|
+
return own;
|
|
118
|
+
}
|
|
119
|
+
const declared = objectSchemaOf(base);
|
|
120
|
+
if (!isObject(own)) {
|
|
121
|
+
return own === false ? false : declared;
|
|
122
|
+
}
|
|
123
|
+
// The type's schema stays the root, so its own `#/…` references keep resolving.
|
|
124
|
+
const admitted = Object.fromEntries(Object.keys(base.properties).map(name => [name, {}]));
|
|
125
|
+
return {
|
|
126
|
+
...own,
|
|
127
|
+
properties: { ...admitted, ...(isObject(own.properties) ? own.properties : {}) },
|
|
128
|
+
allOf: [...(Array.isArray(own.allOf) ? own.allOf : []), declared],
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
return { merge, assertDeclarations, bagSchemaOf, assertBag, fieldsSchemaOf };
|
|
132
|
+
};
|
|
133
|
+
export const appSchemaHelper = createAppSchemaHelper();
|
|
134
|
+
//# sourceMappingURL=app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/helpers/app.ts"],"names":[],"mappings":"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"}
|
package/build/helpers/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type * from './app/types.js';
|
|
1
2
|
export type * from './apply/types.js';
|
|
2
3
|
export type * from './card/types.js';
|
|
3
4
|
export type * from './changes/types.js';
|
|
@@ -9,6 +10,7 @@ export type * from './specification/types.js';
|
|
|
9
10
|
export type * from './status/types.js';
|
|
10
11
|
export type * from './validate/types.js';
|
|
11
12
|
export type * from './wire/types.js';
|
|
13
|
+
export * from './app.js';
|
|
12
14
|
export * from './apply.js';
|
|
13
15
|
export * from './card.js';
|
|
14
16
|
export * from './changes.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,kBAAkB,CAAA;AACrC,mBAAmB,iBAAiB,CAAA;AACpC,mBAAmB,oBAAoB,CAAA;AACvC,mBAAmB,iBAAiB,CAAA;AACpC,mBAAmB,kBAAkB,CAAA;AACrC,mBAAmB,kBAAkB,CAAA;AACrC,mBAAmB,mBAAmB,CAAA;AACtC,mBAAmB,0BAA0B,CAAA;AAC7C,mBAAmB,mBAAmB,CAAA;AACtC,mBAAmB,qBAAqB,CAAA;AACxC,mBAAmB,iBAAiB,CAAA;AAEpC,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,gBAAgB,CAAA;AACnC,mBAAmB,kBAAkB,CAAA;AACrC,mBAAmB,iBAAiB,CAAA;AACpC,mBAAmB,oBAAoB,CAAA;AACvC,mBAAmB,iBAAiB,CAAA;AACpC,mBAAmB,kBAAkB,CAAA;AACrC,mBAAmB,kBAAkB,CAAA;AACrC,mBAAmB,mBAAmB,CAAA;AACtC,mBAAmB,0BAA0B,CAAA;AAC7C,mBAAmB,mBAAmB,CAAA;AACtC,mBAAmB,qBAAqB,CAAA;AACxC,mBAAmB,iBAAiB,CAAA;AAEpC,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA"}
|
package/build/helpers/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAaA,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,cAAc,CAAA;AAC5B,cAAc,WAAW,CAAA;AACzB,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,oBAAoB,CAAA;AAClC,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,cAAc,WAAW,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AssigneeTypeSchema } from '../../resources/types.js';
|
|
2
2
|
import type { PlanningSchemaKind } from '../../consts.js';
|
|
3
|
-
import type { PlanningSchemaBundle, PlanningSchemaRegistry, SchemaScope, ScopedSchemaBundle, ScopedSchemaRecord, ScopedSchemaRegistry, StatusFlowSchema, WorkcardTypeSchema } from '../../types.js';
|
|
3
|
+
import type { PlanningAppDeclarations, PlanningSchemaBundle, PlanningSchemaRegistry, SchemaScope, ScopedSchemaBundle, ScopedSchemaRecord, ScopedSchemaRegistry, StatusFlowSchema, WorkcardTypeSchema } from '../../types.js';
|
|
4
4
|
/** Data-defined (scoped) types and flows: their keys, the checks a write passes, and the layer they resolve to. */
|
|
5
5
|
export interface ScopedSchemaHelper {
|
|
6
6
|
/** One layer's identity of a record: organization, project (or none), kind, key. */
|
|
@@ -15,21 +15,30 @@ export interface ScopedSchemaHelper {
|
|
|
15
15
|
*/
|
|
16
16
|
assertOverridable: (code: Pick<PlanningSchemaRegistry, 'has' | 'type' | 'flows' | 'assigneeTypes'>, kind: PlanningSchemaKind, key: string) => void;
|
|
17
17
|
/**
|
|
18
|
-
* The closed-form checks of a data-defined
|
|
19
|
-
*
|
|
20
|
-
* statuses.
|
|
18
|
+
* The closed-form checks of a data-defined assignee type: the declaration's own schema and a
|
|
19
|
+
* `fields` schema that compiles.
|
|
21
20
|
*
|
|
22
21
|
* @throws {SchemaInvalid}
|
|
23
22
|
*/
|
|
24
23
|
assertAssigneeTypeSchema: (schema: AssigneeTypeSchema) => void;
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* The closed-form checks of a data-defined flow: the declaration's own schema, at least one status,
|
|
26
|
+
* unique status keys, every rule's `to` declared, a `from` that is `'*'` or a list of declared
|
|
27
|
+
* statuses, and its `app` bag against the application's `flow` declaration
|
|
28
|
+
* (`appSchemaHelper.assertBag` — refused when `app` declares none).
|
|
29
|
+
*
|
|
30
|
+
* @throws {SchemaInvalid}
|
|
31
|
+
*/
|
|
32
|
+
assertFlowSchema: (flow: StatusFlowSchema, app?: PlanningAppDeclarations) => void;
|
|
26
33
|
/**
|
|
27
34
|
* The closed-form checks of a data-defined type: the declaration's own schema, the `card` kind,
|
|
28
|
-
*
|
|
35
|
+
* its `app` bag against the application's `type` declaration (refused when `app` declares none),
|
|
36
|
+
* a `fields` schema that compiles together with the application's base card fields, and unique
|
|
37
|
+
* flow ids every one of which resolves.
|
|
29
38
|
*
|
|
30
39
|
* @throws {SchemaInvalid}
|
|
31
40
|
*/
|
|
32
|
-
assertTypeSchema: (type: WorkcardTypeSchema, flows: Pick<PlanningSchemaRegistry, 'flow'
|
|
41
|
+
assertTypeSchema: (type: WorkcardTypeSchema, flows: Pick<PlanningSchemaRegistry, 'flow'>, app?: PlanningAppDeclarations) => void;
|
|
33
42
|
/**
|
|
34
43
|
* One layer resolved: the code bundle, overlaid by the organization-wide records, then by the
|
|
35
44
|
* project's (when `scope.project` names one). Pure — every store and both sides of the wire resolve
|
|
@@ -42,6 +51,9 @@ export interface ScopedSchemaHelper {
|
|
|
42
51
|
* - A retired record gives way to the nearest live declaration below it; a key retired in every
|
|
43
52
|
* layer resolves retired — present in `types`/`flows`, listed in `retired`.
|
|
44
53
|
* - A data-defined declaration carries its record's `version`.
|
|
54
|
+
* - The code bundle's `app` declarations pass through as they are; a record's `app` bag is not
|
|
55
|
+
* re-checked here (the write path checks it), so a record written under earlier declarations
|
|
56
|
+
* still resolves.
|
|
45
57
|
*/
|
|
46
58
|
resolveScopedBundle: (code: PlanningSchemaBundle, records: readonly ScopedSchemaRecord[], scope: SchemaScope & {
|
|
47
59
|
revision?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/helpers/scoped/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,KAAK,EACV,oBAAoB,EAAE,sBAAsB,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/helpers/scoped/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAA;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,KAAK,EACV,uBAAuB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,WAAW,EAAE,kBAAkB,EAAE,kBAAkB,EAC1H,oBAAoB,EAAE,gBAAgB,EAAE,kBAAkB,EAC3D,MAAM,gBAAgB,CAAA;AAEvB,mHAAmH;AACnH,MAAM,WAAW,kBAAkB;IACjC,oFAAoF;IACpF,eAAe,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,KAAK,MAAM,CAAA;IACtG,6EAA6E;IAC7E,WAAW,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,UAAU,EAAE,kBAAkB,GAAG,gBAAgB,GAAG,kBAAkB,KAAK,MAAM,CAAA;IACzH;;;;;OAKG;IACH,iBAAiB,EAAE,CACjB,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,eAAe,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,KAClH,IAAI,CAAA;IACT;;;;;OAKG;IACH,wBAAwB,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAA;IAC9D;;;;;;;OAOG;IACH,gBAAgB,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAA;IACjF;;;;;;;OAOG;IACH,gBAAgB,EAAE,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAA;IAChI;;;;;;;;;;;;;;;OAeG;IACH,mBAAmB,EAAE,CACnB,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,SAAS,kBAAkB,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,KAC3G,kBAAkB,CAAA;IACvB;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,oBAAoB,CAAA;IACtE;;;OAGG;IACH,SAAS,EAAE,CAAC,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;CAC5E"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AssigneeTypeSchema } from '../resources/types.js';
|
|
2
2
|
import { PlanningSchemaKind } from '../consts.js';
|
|
3
|
-
import type { PlanningSchemaBundle, PlanningSchemaRegistry, SchemaScope, ScopedSchemaBundle, ScopedSchemaRecord, ScopedSchemaRegistry, StatusFlowSchema, WorkcardTypeSchema } from '../types.js';
|
|
3
|
+
import type { PlanningAppDeclarations, PlanningSchemaBundle, PlanningSchemaRegistry, SchemaScope, ScopedSchemaBundle, ScopedSchemaRecord, ScopedSchemaRegistry, StatusFlowSchema, WorkcardTypeSchema } from '../types.js';
|
|
4
4
|
import type { ScopedSchemaHelper } from './scoped/types.js';
|
|
5
5
|
export declare const createScopedSchemaHelper: () => ScopedSchemaHelper;
|
|
6
6
|
export declare const scopedSchemaHelper: ScopedSchemaHelper;
|
|
@@ -11,9 +11,9 @@ export declare const schemaKeyOf: (kind: PlanningSchemaKind, definition: Workcar
|
|
|
11
11
|
/** @deprecated compat:factory-refactor — use `scopedSchemaHelper.assertOverridable(…)` */
|
|
12
12
|
export declare const assertOverridable: (code: Pick<PlanningSchemaRegistry, 'has' | 'type' | 'flows' | 'assigneeTypes'>, kind: PlanningSchemaKind, key: string) => void;
|
|
13
13
|
/** @deprecated compat:factory-refactor — use `scopedSchemaHelper.assertFlowSchema(…)` */
|
|
14
|
-
export declare const assertFlowSchema: (flow: StatusFlowSchema) => void;
|
|
14
|
+
export declare const assertFlowSchema: (flow: StatusFlowSchema, app?: PlanningAppDeclarations) => void;
|
|
15
15
|
/** @deprecated compat:factory-refactor — use `scopedSchemaHelper.assertTypeSchema(…)` */
|
|
16
|
-
export declare const assertTypeSchema: (type: WorkcardTypeSchema, flows: Pick<PlanningSchemaRegistry, 'flow'
|
|
16
|
+
export declare const assertTypeSchema: (type: WorkcardTypeSchema, flows: Pick<PlanningSchemaRegistry, 'flow'>, app?: PlanningAppDeclarations) => void;
|
|
17
17
|
/** @deprecated compat:factory-refactor — use `scopedSchemaHelper.resolveScopedBundle(…)` */
|
|
18
18
|
export declare const resolveScopedBundle: (code: PlanningSchemaBundle, records: readonly ScopedSchemaRecord[], scope: SchemaScope & {
|
|
19
19
|
revision?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scoped.d.ts","sourceRoot":"","sources":["../../src/helpers/scoped.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAG/D,OAAO,EAAE,kBAAkB,EAA8B,MAAM,cAAc,CAAA;AAI7E,OAAO,KAAK,EACK,oBAAoB,EAAE,sBAAsB,EAAE,WAAW,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"scoped.d.ts","sourceRoot":"","sources":["../../src/helpers/scoped.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAG/D,OAAO,EAAE,kBAAkB,EAA8B,MAAM,cAAc,CAAA;AAI7E,OAAO,KAAK,EACK,uBAAuB,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,WAAW,EAAE,kBAAkB,EACrH,kBAAkB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,kBAAkB,EAC/E,MAAM,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAM3D,eAAO,MAAM,wBAAwB,QAAO,kBAqO3C,CAAA;AAED,eAAO,MAAM,kBAAkB,oBAA6B,CAAA;AAE5D,wFAAwF;AACxF,eAAO,MAAM,eAAe,WAAY,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,KAAG,MAChE,CAAA;AAE5C,oFAAoF;AACpF,eAAO,MAAM,WAAW,SAAU,kBAAkB,cAAc,kBAAkB,GAAG,gBAAgB,GAAG,kBAAkB,KAAG,MAC7E,CAAA;AAElD,0FAA0F;AAC1F,eAAO,MAAM,iBAAiB,SACtB,IAAI,CAAC,sBAAsB,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,eAAe,CAAC,QAAQ,kBAAkB,OAAO,MAAM,KACpH,IAA6D,CAAA;AAEhE,yFAAyF;AACzF,eAAO,MAAM,gBAAgB,SAAU,gBAAgB,QAAQ,uBAAuB,KAAG,IAAsD,CAAA;AAE/I,yFAAyF;AACzF,eAAO,MAAM,gBAAgB,SAAU,kBAAkB,SAAS,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,QAAQ,uBAAuB,KAAG,IACjF,CAAA;AAEvD,4FAA4F;AAC5F,eAAO,MAAM,mBAAmB,SACxB,oBAAoB,WAAW,SAAS,kBAAkB,EAAE,SAAS,WAAW,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,KAC7G,kBAAkF,CAAA;AAErF,yFAAyF;AACzF,eAAO,MAAM,gBAAgB,WAAY,kBAAkB,KAAG,oBAAmE,CAAA;AAEjI,kFAAkF;AAClF,eAAO,MAAM,SAAS,WAAY,kBAAkB,QAAQ,MAAM,KAAG,MAAM,GAAG,SAAuD,CAAA"}
|