@adminiumjs/manifest 0.3.26 → 0.3.28
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/app-grants.d.ts +134 -0
- package/dist/app-grants.d.ts.map +1 -0
- package/dist/app-grants.js +263 -0
- package/dist/app-grants.js.map +1 -0
- package/dist/automations.d.ts +2172 -56
- package/dist/automations.d.ts.map +1 -1
- package/dist/automations.js +438 -25
- package/dist/automations.js.map +1 -1
- package/dist/compose.d.ts.map +1 -1
- package/dist/compose.js +3 -0
- package/dist/compose.js.map +1 -1
- package/dist/documents.d.ts +1 -0
- package/dist/documents.d.ts.map +1 -1
- package/dist/documents.js +2 -0
- package/dist/documents.js.map +1 -1
- package/dist/index.d.ts +11 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/ledgers.d.ts.map +1 -1
- package/dist/ledgers.js +2 -0
- package/dist/ledgers.js.map +1 -1
- package/dist/modules.d.ts +93 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +489 -0
- package/dist/modules.js.map +1 -0
- package/dist/occupies.d.ts +50 -0
- package/dist/occupies.d.ts.map +1 -0
- package/dist/occupies.js +123 -0
- package/dist/occupies.js.map +1 -0
- package/dist/outbox.d.ts +223 -17
- package/dist/outbox.d.ts.map +1 -1
- package/dist/outbox.js +125 -13
- package/dist/outbox.js.map +1 -1
- package/dist/page-board.d.ts +144 -0
- package/dist/page-board.d.ts.map +1 -0
- package/dist/page-board.js +280 -0
- package/dist/page-board.js.map +1 -0
- package/dist/public-access.d.ts +6 -0
- package/dist/public-access.d.ts.map +1 -1
- package/dist/public-access.js +74 -0
- package/dist/public-access.js.map +1 -1
- package/dist/rail.d.ts +50 -0
- package/dist/rail.d.ts.map +1 -0
- package/dist/rail.js +122 -0
- package/dist/rail.js.map +1 -0
- package/dist/roles.d.ts +647 -1
- package/dist/roles.d.ts.map +1 -1
- package/dist/roles.js +459 -3
- package/dist/roles.js.map +1 -1
- package/dist/sample.d.ts +62 -0
- package/dist/sample.d.ts.map +1 -1
- package/dist/sample.js +203 -4
- package/dist/sample.js.map +1 -1
- package/dist/schema.d.ts +4277 -169
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +539 -40
- package/dist/schema.js.map +1 -1
- package/dist/shapes.d.ts +3 -2
- package/dist/shapes.d.ts.map +1 -1
- package/dist/shapes.js +76 -7
- package/dist/shapes.js.map +1 -1
- package/dist/state-actions.d.ts +4 -0
- package/dist/state-actions.d.ts.map +1 -1
- package/dist/state-actions.js +7 -0
- package/dist/state-actions.js.map +1 -1
- package/dist/states.d.ts +20 -1
- package/dist/states.d.ts.map +1 -1
- package/dist/states.js +47 -5
- package/dist/states.js.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +41 -0
- package/dist/validate.js.map +1 -1
- package/dist/words.d.ts +1 -1
- package/dist/words.d.ts.map +1 -1
- package/dist/words.js +328 -1
- package/dist/words.js.map +1 -1
- package/package.json +2 -2
package/dist/sample.d.ts
CHANGED
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
* `{"@table": "<table>"}` that table's stored name, for a column that
|
|
22
22
|
* holds one (`rules.tableRef`): the name it has
|
|
23
23
|
* on this install, whichever app made the table
|
|
24
|
+
* `{"@person": "<key>"}` one of the manifest's sample people
|
|
25
|
+
* (`sampleData.people`): the staff member made
|
|
26
|
+
* for that key. In a staff column (`rules.staff`)
|
|
27
|
+
* or another text column that holds a staff id,
|
|
28
|
+
* and anywhere inside a json value (a saved
|
|
29
|
+
* filter that names a rep)
|
|
24
30
|
*
|
|
25
31
|
* A `@day` may add `"@workdays": true`: its days count Monday to Friday, and
|
|
26
32
|
* day 0 on a weekend is the Monday after — so "today's" busy day is never a
|
|
@@ -61,6 +67,10 @@
|
|
|
61
67
|
* `"@onlyIfEmpty": true` is for a table that holds one row, the app's own
|
|
62
68
|
* settings: the row is added only when the table has none, and otherwise its
|
|
63
69
|
* `@label` names the row already there — the operator's own settings stay.
|
|
70
|
+
* With `"@fillEmpty": true` beside it, the row already there takes the
|
|
71
|
+
* sample's values in the columns it holds nothing in (a depot's name on a
|
|
72
|
+
* settings row the install wrote with its defaults): never over a value, and
|
|
73
|
+
* emptied again with the sample where nobody changed them since.
|
|
64
74
|
*
|
|
65
75
|
* AN APP'S ROWS FOR AN ADD-ON. An app that names an add-on may ship a second
|
|
66
76
|
* file of the same format with a top-level `addOn`: rows of that add-on's
|
|
@@ -102,6 +112,8 @@ export declare const sampleValueSchema: z.ZodUnion<readonly [z.ZodUnion<readonly
|
|
|
102
112
|
'@asset': z.ZodString;
|
|
103
113
|
}, z.core.$strict>, z.ZodObject<{
|
|
104
114
|
'@table': z.ZodString;
|
|
115
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
116
|
+
'@person': z.ZodString;
|
|
105
117
|
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>;
|
|
106
118
|
export declare const sampleRowSchema: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
107
119
|
'@ref': z.ZodString;
|
|
@@ -130,6 +142,8 @@ export declare const sampleRowSchema: z.ZodRecord<z.ZodString, z.ZodUnion<readon
|
|
|
130
142
|
'@asset': z.ZodString;
|
|
131
143
|
}, z.core.$strict>, z.ZodObject<{
|
|
132
144
|
'@table': z.ZodString;
|
|
145
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
146
|
+
'@person': z.ZodString;
|
|
133
147
|
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
134
148
|
/** `@byClock`: a row's columns by where its time falls against the adding moment. */
|
|
135
149
|
export declare const byClockSchema: z.ZodObject<{
|
|
@@ -160,6 +174,8 @@ export declare const byClockSchema: z.ZodObject<{
|
|
|
160
174
|
'@asset': z.ZodString;
|
|
161
175
|
}, z.core.$strict>, z.ZodObject<{
|
|
162
176
|
'@table': z.ZodString;
|
|
177
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
178
|
+
'@person': z.ZodString;
|
|
163
179
|
}, z.core.$strict>]>]>;
|
|
164
180
|
before: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
165
181
|
'@ref': z.ZodString;
|
|
@@ -188,6 +204,8 @@ export declare const byClockSchema: z.ZodObject<{
|
|
|
188
204
|
'@asset': z.ZodString;
|
|
189
205
|
}, z.core.$strict>, z.ZodObject<{
|
|
190
206
|
'@table': z.ZodString;
|
|
207
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
208
|
+
'@person': z.ZodString;
|
|
191
209
|
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
|
|
192
210
|
around: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
193
211
|
'@ref': z.ZodString;
|
|
@@ -216,6 +234,8 @@ export declare const byClockSchema: z.ZodObject<{
|
|
|
216
234
|
'@asset': z.ZodString;
|
|
217
235
|
}, z.core.$strict>, z.ZodObject<{
|
|
218
236
|
'@table': z.ZodString;
|
|
237
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
238
|
+
'@person': z.ZodString;
|
|
219
239
|
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
|
|
220
240
|
after: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
221
241
|
'@ref': z.ZodString;
|
|
@@ -244,6 +264,8 @@ export declare const byClockSchema: z.ZodObject<{
|
|
|
244
264
|
'@asset': z.ZodString;
|
|
245
265
|
}, z.core.$strict>, z.ZodObject<{
|
|
246
266
|
'@table': z.ZodString;
|
|
267
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
268
|
+
'@person': z.ZodString;
|
|
247
269
|
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
|
|
248
270
|
}, z.core.$strict>;
|
|
249
271
|
export type ByClock = z.infer<typeof byClockSchema>;
|
|
@@ -276,6 +298,8 @@ export declare const byStaySchema: z.ZodObject<{
|
|
|
276
298
|
'@asset': z.ZodString;
|
|
277
299
|
}, z.core.$strict>, z.ZodObject<{
|
|
278
300
|
'@table': z.ZodString;
|
|
301
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
302
|
+
'@person': z.ZodString;
|
|
279
303
|
}, z.core.$strict>]>]>;
|
|
280
304
|
to: z.ZodUnion<readonly [z.ZodString, z.ZodUnion<readonly [z.ZodObject<{
|
|
281
305
|
'@ref': z.ZodString;
|
|
@@ -304,6 +328,8 @@ export declare const byStaySchema: z.ZodObject<{
|
|
|
304
328
|
'@asset': z.ZodString;
|
|
305
329
|
}, z.core.$strict>, z.ZodObject<{
|
|
306
330
|
'@table': z.ZodString;
|
|
331
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
332
|
+
'@person': z.ZodString;
|
|
307
333
|
}, z.core.$strict>]>]>;
|
|
308
334
|
times: z.ZodOptional<z.ZodObject<{
|
|
309
335
|
from: z.ZodOptional<z.ZodString>;
|
|
@@ -336,6 +362,8 @@ export declare const byStaySchema: z.ZodObject<{
|
|
|
336
362
|
'@asset': z.ZodString;
|
|
337
363
|
}, z.core.$strict>, z.ZodObject<{
|
|
338
364
|
'@table': z.ZodString;
|
|
365
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
366
|
+
'@person': z.ZodString;
|
|
339
367
|
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
|
|
340
368
|
during: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
341
369
|
'@ref': z.ZodString;
|
|
@@ -364,6 +392,8 @@ export declare const byStaySchema: z.ZodObject<{
|
|
|
364
392
|
'@asset': z.ZodString;
|
|
365
393
|
}, z.core.$strict>, z.ZodObject<{
|
|
366
394
|
'@table': z.ZodString;
|
|
395
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
396
|
+
'@person': z.ZodString;
|
|
367
397
|
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
|
|
368
398
|
after: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>, z.ZodUnion<readonly [z.ZodObject<{
|
|
369
399
|
'@ref': z.ZodString;
|
|
@@ -392,11 +422,15 @@ export declare const byStaySchema: z.ZodObject<{
|
|
|
392
422
|
'@asset': z.ZodString;
|
|
393
423
|
}, z.core.$strict>, z.ZodObject<{
|
|
394
424
|
'@table': z.ZodString;
|
|
425
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
426
|
+
'@person': z.ZodString;
|
|
395
427
|
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
|
|
396
428
|
}, z.core.$strict>;
|
|
397
429
|
export type ByStay = z.infer<typeof byStaySchema>;
|
|
398
430
|
/** The keys of a row that are directives about the row, not columns. */
|
|
399
431
|
export declare const ROW_DIRECTIVES: ReadonlySet<string>;
|
|
432
|
+
/** The most moves one file asks for. */
|
|
433
|
+
export declare const SAMPLE_MOVES_MAX = 50;
|
|
400
434
|
/** The weekdays a bundle's week anchor names. */
|
|
401
435
|
export declare const SAMPLE_WEEKDAYS: readonly ["mon", "tue", "wed", "thu", "fri", "sat", "sun"];
|
|
402
436
|
export declare const sampleBundleSchema: z.ZodObject<{
|
|
@@ -447,8 +481,15 @@ export declare const sampleBundleSchema: z.ZodObject<{
|
|
|
447
481
|
'@asset': z.ZodString;
|
|
448
482
|
}, z.core.$strict>, z.ZodObject<{
|
|
449
483
|
'@table': z.ZodString;
|
|
484
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
485
|
+
'@person': z.ZodString;
|
|
450
486
|
}, z.core.$strict>]>, z.ZodArray<z.ZodUnknown>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>>;
|
|
451
487
|
}, z.core.$strict>>;
|
|
488
|
+
moves: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
489
|
+
ref: z.ZodOptional<z.ZodString>;
|
|
490
|
+
table: z.ZodOptional<z.ZodString>;
|
|
491
|
+
to: z.ZodString;
|
|
492
|
+
}, z.core.$strict>>>;
|
|
452
493
|
}, z.core.$strict>;
|
|
453
494
|
export type SampleBundle = z.infer<typeof sampleBundleSchema>;
|
|
454
495
|
export type SampleValue = z.infer<typeof sampleValueSchema>;
|
|
@@ -489,7 +530,15 @@ export declare function sampleDirective(value: unknown): {
|
|
|
489
530
|
} | {
|
|
490
531
|
kind: 'table';
|
|
491
532
|
ref: string;
|
|
533
|
+
} | {
|
|
534
|
+
kind: 'person';
|
|
535
|
+
key: string;
|
|
492
536
|
} | null;
|
|
537
|
+
/**
|
|
538
|
+
* Every sample person a value names: itself, or anywhere inside it when it
|
|
539
|
+
* is a json value (an object or a list that is no directive of its own).
|
|
540
|
+
*/
|
|
541
|
+
export declare function samplePeopleIn(value: unknown): string[];
|
|
493
542
|
/** An ISO-8601 duration in milliseconds. */
|
|
494
543
|
export declare function isoDurationMs(duration: string): number;
|
|
495
544
|
export interface SampleIssue {
|
|
@@ -535,6 +584,19 @@ export declare function seedRowIdentity(manifest: Manifest, table: string, row:
|
|
|
535
584
|
* is written only by actions that count nothing. The receipt table never is.
|
|
536
585
|
*/
|
|
537
586
|
export declare function ledgerCatalogueTables(addOn: AddOnManifest): ReadonlySet<string>;
|
|
587
|
+
/**
|
|
588
|
+
* The tables a ledger writes that an app's file may still bring ROWS WITH NO
|
|
589
|
+
* HISTORY of: an item with no stock, an order still a draft. A table is one
|
|
590
|
+
* when a person may make its rows by hand (a role of the add-on is granted
|
|
591
|
+
* `create` on it), and it is not the receipt table. The row then leaves out
|
|
592
|
+
* every column the ledger keeps (`ledgerKeptColumns`) that it can be made
|
|
593
|
+
* without, and names no receipt.
|
|
594
|
+
* What only the ledger writes (a movement, a level, a reservation) comes only
|
|
595
|
+
* from the ledger: the file asks for it with `moves`, and the add-on writes it.
|
|
596
|
+
*/
|
|
597
|
+
export declare function ledgerBringableTables(addOn: AddOnManifest): ReadonlySet<string>;
|
|
598
|
+
/** The columns of a table that an add-on's ledgers keep: what a plan may change of a row that is there (`update.set`). */
|
|
599
|
+
export declare function ledgerKeptColumns(addOn: AddOnManifest, ref: string): ReadonlySet<string>;
|
|
538
600
|
/**
|
|
539
601
|
* An app's rows for an add-on it names (`sampleData.addOns.<key>.file`):
|
|
540
602
|
* the file is for this app and that add-on, the app names the add-on, a
|
package/dist/sample.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sample.d.ts","sourceRoot":"","sources":["../src/sample.ts"],"names":[],"mappings":"AACA
|
|
1
|
+
{"version":3,"file":"sample.d.ts","sourceRoot":"","sources":["../src/sample.ts"],"names":[],"mappings":"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"}
|
package/dist/sample.js
CHANGED
|
@@ -22,6 +22,12 @@
|
|
|
22
22
|
* `{"@table": "<table>"}` that table's stored name, for a column that
|
|
23
23
|
* holds one (`rules.tableRef`): the name it has
|
|
24
24
|
* on this install, whichever app made the table
|
|
25
|
+
* `{"@person": "<key>"}` one of the manifest's sample people
|
|
26
|
+
* (`sampleData.people`): the staff member made
|
|
27
|
+
* for that key. In a staff column (`rules.staff`)
|
|
28
|
+
* or another text column that holds a staff id,
|
|
29
|
+
* and anywhere inside a json value (a saved
|
|
30
|
+
* filter that names a rep)
|
|
25
31
|
*
|
|
26
32
|
* A `@day` may add `"@workdays": true`: its days count Monday to Friday, and
|
|
27
33
|
* day 0 on a weekend is the Monday after — so "today's" busy day is never a
|
|
@@ -62,6 +68,10 @@
|
|
|
62
68
|
* `"@onlyIfEmpty": true` is for a table that holds one row, the app's own
|
|
63
69
|
* settings: the row is added only when the table has none, and otherwise its
|
|
64
70
|
* `@label` names the row already there — the operator's own settings stay.
|
|
71
|
+
* With `"@fillEmpty": true` beside it, the row already there takes the
|
|
72
|
+
* sample's values in the columns it holds nothing in (a depot's name on a
|
|
73
|
+
* settings row the install wrote with its defaults): never over a value, and
|
|
74
|
+
* emptied again with the sample where nobody changed them since.
|
|
65
75
|
*
|
|
66
76
|
* AN APP'S ROWS FOR AN ADD-ON. An app that names an add-on may ship a second
|
|
67
77
|
* file of the same format with a top-level `addOn`: rows of that add-on's
|
|
@@ -112,6 +122,7 @@ const directive = z.union([
|
|
|
112
122
|
z.object({ '@t': z.record(z.string().regex(/^[a-z]{2}(-[A-Z]{2})?$/), z.string()).refine((m) => Object.keys(m).length > 0) }).strict(),
|
|
113
123
|
z.object({ '@asset': label }).strict(),
|
|
114
124
|
z.object({ '@table': z.string().regex(/^[a-z][a-z0-9_]*$/, 'a table') }).strict(),
|
|
125
|
+
z.object({ '@person': z.string().regex(/^[a-z][a-z0-9_-]{0,39}$/, 'a sample person\'s key') }).strict(),
|
|
115
126
|
]);
|
|
116
127
|
const plain = z.union([z.string(), z.number(), z.boolean(), z.null()]);
|
|
117
128
|
/** A column's value: a plain value, a directive, or (for a json column) any object or array. */
|
|
@@ -144,7 +155,9 @@ export const byStaySchema = z
|
|
|
144
155
|
})
|
|
145
156
|
.strict();
|
|
146
157
|
/** The keys of a row that are directives about the row, not columns. */
|
|
147
|
-
export const ROW_DIRECTIVES = new Set(['@label', '@byClock', '@byStay', '@onlyIfEmpty']);
|
|
158
|
+
export const ROW_DIRECTIVES = new Set(['@label', '@byClock', '@byStay', '@onlyIfEmpty', '@fillEmpty']);
|
|
159
|
+
/** The most moves one file asks for. */
|
|
160
|
+
export const SAMPLE_MOVES_MAX = 50;
|
|
148
161
|
/** The weekdays a bundle's week anchor names. */
|
|
149
162
|
export const SAMPLE_WEEKDAYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];
|
|
150
163
|
export const sampleBundleSchema = z
|
|
@@ -170,6 +183,19 @@ export const sampleBundleSchema = z
|
|
|
170
183
|
})
|
|
171
184
|
.strict())
|
|
172
185
|
.min(1),
|
|
186
|
+
/**
|
|
187
|
+
* In an app's rows for an add-on: changes of state made once the rows are in, each as a save of its own, in
|
|
188
|
+
* this order. Such a save is a real one, so what the add-on's ledger hands to a move (a receipt posted: stock
|
|
189
|
+
* in) is written by the add-on itself. One row by its label (`ref`), or every row this file wrote of a table.
|
|
190
|
+
*/
|
|
191
|
+
moves: z
|
|
192
|
+
.array(z
|
|
193
|
+
.object({ ref: label.optional(), table: z.string().min(1).optional(), to: z.string().min(1).max(80) })
|
|
194
|
+
.strict()
|
|
195
|
+
.refine((move) => (move.ref === undefined) !== (move.table === undefined), { message: 'a move names one row (`ref`) or one table (`table`), not both' }))
|
|
196
|
+
.min(1)
|
|
197
|
+
.max(SAMPLE_MOVES_MAX)
|
|
198
|
+
.optional(),
|
|
173
199
|
})
|
|
174
200
|
.strict();
|
|
175
201
|
/** A value's directive, when it is one. */
|
|
@@ -204,8 +230,24 @@ export function sampleDirective(value) {
|
|
|
204
230
|
return { kind: 'asset', label: record['@asset'] };
|
|
205
231
|
if (typeof record['@table'] === 'string')
|
|
206
232
|
return { kind: 'table', ref: record['@table'] };
|
|
233
|
+
if (typeof record['@person'] === 'string')
|
|
234
|
+
return { kind: 'person', key: record['@person'] };
|
|
207
235
|
return null;
|
|
208
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* Every sample person a value names: itself, or anywhere inside it when it
|
|
239
|
+
* is a json value (an object or a list that is no directive of its own).
|
|
240
|
+
*/
|
|
241
|
+
export function samplePeopleIn(value) {
|
|
242
|
+
const found = sampleDirective(value);
|
|
243
|
+
if (found !== null)
|
|
244
|
+
return found.kind === 'person' ? [found.key] : [];
|
|
245
|
+
if (Array.isArray(value))
|
|
246
|
+
return value.flatMap(samplePeopleIn);
|
|
247
|
+
if (typeof value === 'object' && value !== null)
|
|
248
|
+
return Object.values(value).flatMap(samplePeopleIn);
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
209
251
|
/** An ISO-8601 duration in milliseconds. */
|
|
210
252
|
export function isoDurationMs(duration) {
|
|
211
253
|
const match = ISO_DURATION.exec(duration);
|
|
@@ -257,8 +299,11 @@ export function sampleBundleIssues(bundle, manifest) {
|
|
|
257
299
|
if (table.own === true)
|
|
258
300
|
issues.push({ path: `tables.${String(t)}.own`, message: '"own" marks a table of the app in its rows for an add-on; a manifest\'s own sample file takes none.' });
|
|
259
301
|
});
|
|
302
|
+
if (bundle.moves !== undefined)
|
|
303
|
+
issues.push({ path: 'moves', message: '"moves" are for an app\'s rows for an add-on (sampleData.addOns); a manifest\'s own sample file writes its rows as they should stand.' });
|
|
260
304
|
const declared = new Map((manifest.requiredSchema?.tables ?? []).map((table) => [table.ref, table]));
|
|
261
|
-
|
|
305
|
+
const people = new Set(((manifest.kind === 'app' ? manifest.sampleData?.people : undefined) ?? []).map((person) => person.key));
|
|
306
|
+
issues.push(...rowIssues(bundle, declared, { names: new Set(declared.keys()), what: manifest.kind === 'add-on' ? 'add-on' : 'app', otherLabels: false, known: seedLabelsOf(manifest), people }));
|
|
262
307
|
issues.push(...ledgerOrderIssues(bundle, manifest, declared));
|
|
263
308
|
return issues;
|
|
264
309
|
}
|
|
@@ -403,6 +448,42 @@ export function ledgerCatalogueTables(addOn) {
|
|
|
403
448
|
verdicts.set(ledger.receipts, false);
|
|
404
449
|
return new Set([...verdicts].filter(([, catalogue]) => catalogue).map(([ref]) => ref));
|
|
405
450
|
}
|
|
451
|
+
/**
|
|
452
|
+
* The tables a ledger writes that an app's file may still bring ROWS WITH NO
|
|
453
|
+
* HISTORY of: an item with no stock, an order still a draft. A table is one
|
|
454
|
+
* when a person may make its rows by hand (a role of the add-on is granted
|
|
455
|
+
* `create` on it), and it is not the receipt table. The row then leaves out
|
|
456
|
+
* every column the ledger keeps (`ledgerKeptColumns`) that it can be made
|
|
457
|
+
* without, and names no receipt.
|
|
458
|
+
* What only the ledger writes (a movement, a level, a reservation) comes only
|
|
459
|
+
* from the ledger: the file asks for it with `moves`, and the add-on writes it.
|
|
460
|
+
*/
|
|
461
|
+
export function ledgerBringableTables(addOn) {
|
|
462
|
+
const byHand = new Set();
|
|
463
|
+
for (const role of addOn.roles ?? []) {
|
|
464
|
+
for (const permission of role.permissions ?? []) {
|
|
465
|
+
const [kind, table, action] = permission.split(':');
|
|
466
|
+
if (kind === 'table' && action === 'create' && table !== undefined)
|
|
467
|
+
byHand.add(table.replace(/^@/, ''));
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const out = new Set();
|
|
471
|
+
for (const ledger of ledgersOf(addOn))
|
|
472
|
+
for (const ref of Object.keys(ledger.writes))
|
|
473
|
+
if (byHand.has(ref))
|
|
474
|
+
out.add(ref);
|
|
475
|
+
for (const ledger of ledgersOf(addOn))
|
|
476
|
+
out.delete(ledger.receipts);
|
|
477
|
+
return out;
|
|
478
|
+
}
|
|
479
|
+
/** The columns of a table that an add-on's ledgers keep: what a plan may change of a row that is there (`update.set`). */
|
|
480
|
+
export function ledgerKeptColumns(addOn, ref) {
|
|
481
|
+
const out = new Set();
|
|
482
|
+
for (const ledger of ledgersOf(addOn))
|
|
483
|
+
for (const column of ledger.writes[ref]?.update?.set ?? [])
|
|
484
|
+
out.add(column);
|
|
485
|
+
return out;
|
|
486
|
+
}
|
|
406
487
|
/**
|
|
407
488
|
* An app's rows for an add-on it names (`sampleData.addOns.<key>.file`):
|
|
408
489
|
* the file is for this app and that add-on, the app names the add-on, a
|
|
@@ -429,6 +510,7 @@ export function sampleSectionIssues(bundle, app, addOn) {
|
|
|
429
510
|
const theirs = addOn === undefined ? null : new Map((addOn.requiredSchema?.tables ?? []).map((table) => [table.ref, table]));
|
|
430
511
|
const declared = new Map();
|
|
431
512
|
const catalogue = addOn === undefined ? new Set() : ledgerCatalogueTables(addOn);
|
|
513
|
+
const bringable = addOn === undefined ? new Set() : ledgerBringableTables(addOn);
|
|
432
514
|
const receipts = new Set(addOn === undefined ? [] : ledgersOf(addOn).map((ledger) => ledger.receipts));
|
|
433
515
|
bundle.tables.forEach((table, t) => {
|
|
434
516
|
const at = `tables.${String(t)}`;
|
|
@@ -450,7 +532,7 @@ export function sampleSectionIssues(bundle, app, addOn) {
|
|
|
450
532
|
const shape = theirs.get(table.ref);
|
|
451
533
|
// An add-on's history is its own to write: an app brings what a ledger counts, never what it counted.
|
|
452
534
|
// What a ledger writes beside its books (which item a dish uses) is no history, and an app may bring it.
|
|
453
|
-
const ledger = addOn === undefined || catalogue.has(table.ref) ? undefined : ledgersOf(addOn).find((candidate) => candidate.receipts === table.ref || candidate.writes[table.ref] !== undefined);
|
|
535
|
+
const ledger = addOn === undefined || catalogue.has(table.ref) || bringable.has(table.ref) ? undefined : ledgersOf(addOn).find((candidate) => candidate.receipts === table.ref || candidate.writes[table.ref] !== undefined);
|
|
454
536
|
if (shape === undefined)
|
|
455
537
|
issues.push({ path: `${at}.ref`, message: `"${table.ref}" is not a table of "${key}". A table of the app itself is marked "own": true.` });
|
|
456
538
|
else if (ledger !== undefined)
|
|
@@ -466,8 +548,21 @@ export function sampleSectionIssues(bundle, app, addOn) {
|
|
|
466
548
|
issues.push({ path: `${at}.rows.${String(r)}.${column.ref}`, message: `"${table.ref}.${column.ref}" names the receipt of a posting: an app's rows for an add-on are made by no posting, so leave it out.` });
|
|
467
549
|
});
|
|
468
550
|
}
|
|
551
|
+
// A row with no history: what the ledger keeps of it (an average cost, a status it moves) is the ledger's to write.
|
|
552
|
+
// But for a column a row cannot be made without (an order line's quantity, which a receipt later adjusts): that one a person types.
|
|
553
|
+
const needed = new Set(shape.columns.filter((column) => column.nullable !== true && column.default === undefined).map((column) => column.ref));
|
|
554
|
+
const kept = addOn === undefined || catalogue.has(table.ref) ? new Set() : new Set([...ledgerKeptColumns(addOn, table.ref)].filter((column) => !needed.has(column)));
|
|
555
|
+
if (kept.size > 0) {
|
|
556
|
+
table.rows.forEach((row, r) => {
|
|
557
|
+
for (const column of kept) {
|
|
558
|
+
if (row[column] !== undefined)
|
|
559
|
+
issues.push({ path: `${at}.rows.${String(r)}.${column}`, message: `"${table.ref}.${column}" is kept by "${key}"'s ledger: an app's row brings no history, so leave it out (a move asks the add-on to write it).` });
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
}
|
|
469
563
|
}
|
|
470
564
|
});
|
|
565
|
+
issues.push(...sampleMoveIssues(bundle, theirs));
|
|
471
566
|
const twice = bundle.tables.map((table) => table.ref).filter((ref, i, all) => all.indexOf(ref) !== i);
|
|
472
567
|
for (const ref of new Set(twice))
|
|
473
568
|
issues.push({ path: 'tables', message: `"${ref}" is listed twice.` });
|
|
@@ -475,6 +570,51 @@ export function sampleSectionIssues(bundle, app, addOn) {
|
|
|
475
570
|
issues.push(...rowIssues(bundle, declared, { names: new Set(own.keys()), what: 'app', otherLabels: true }));
|
|
476
571
|
return issues;
|
|
477
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* A section's `moves`: each names a labelled row, or a table, of the add-on's
|
|
575
|
+
* that this file itself writes, and a state that table has. Whether the move
|
|
576
|
+
* is one the table allows from where the row stands is judged when it is
|
|
577
|
+
* made, as for anybody's save.
|
|
578
|
+
*/
|
|
579
|
+
function sampleMoveIssues(bundle, theirs) {
|
|
580
|
+
const issues = [];
|
|
581
|
+
const tableOfLabel = new Map();
|
|
582
|
+
const written = new Map();
|
|
583
|
+
for (const table of bundle.tables) {
|
|
584
|
+
written.set(table.ref, table.own === true);
|
|
585
|
+
for (const row of table.rows)
|
|
586
|
+
if (typeof row['@label'] === 'string')
|
|
587
|
+
tableOfLabel.set(row['@label'], table.ref);
|
|
588
|
+
}
|
|
589
|
+
(bundle.moves ?? []).forEach((move, m) => {
|
|
590
|
+
const at = `moves.${String(m)}`;
|
|
591
|
+
const ref = move.table ?? (move.ref === undefined ? undefined : tableOfLabel.get(move.ref));
|
|
592
|
+
if (ref === undefined) {
|
|
593
|
+
issues.push({ path: `${at}.ref`, message: `No row of this file carries the label "${String(move.ref)}".` });
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
if (!written.has(ref)) {
|
|
597
|
+
issues.push({ path: `${at}.table`, message: `This file writes no row of "${ref}": a move is of a row the file itself brings.` });
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
if (written.get(ref) === true) {
|
|
601
|
+
issues.push({ path: at, message: `"${ref}" is the app's own table: a move is of a row of the add-on's, whose ledger then writes what follows.` });
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
const shape = theirs?.get(ref);
|
|
605
|
+
if (shape === undefined)
|
|
606
|
+
return; // checked when the add-on's manifest is at hand
|
|
607
|
+
const states = shape.states;
|
|
608
|
+
if (states === undefined) {
|
|
609
|
+
issues.push({ path: at, message: `"${ref}" has no states, so its rows make no move.` });
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
const values = shape.columns.find((column) => column.ref === states.column)?.enum ?? [];
|
|
613
|
+
if (!values.includes(move.to))
|
|
614
|
+
issues.push({ path: `${at}.to`, message: `"${ref}" has no state "${move.to}".` });
|
|
615
|
+
});
|
|
616
|
+
return issues;
|
|
617
|
+
}
|
|
478
618
|
/**
|
|
479
619
|
* The checks every row of a file gets, over the tables `declared` knows. A
|
|
480
620
|
* table it does not know is skipped: the caller has said why, or cannot see it.
|
|
@@ -511,9 +651,44 @@ function rowIssues(bundle, declared, opts) {
|
|
|
511
651
|
}
|
|
512
652
|
}
|
|
513
653
|
// A number Adminium gives without gaps: a sample row names it, empty, or the load numbers it into the real series.
|
|
514
|
-
|
|
654
|
+
// One the app opened to its sample (`sequence.sample`) may instead be given its number: checked below, with the text written from it.
|
|
655
|
+
const gapless = shape.columns.filter((column) => column.rules?.sequence?.gapless === true && column.rules.sequence.sample !== true).map((column) => column.ref);
|
|
656
|
+
const numberedBySample = shape.columns.filter((column) => column.rules?.sequence?.gapless === true && column.rules.sequence.sample === true);
|
|
657
|
+
const taken = new Map();
|
|
515
658
|
for (const [r, row] of table.rows.entries()) {
|
|
516
659
|
const at = `tables.${String(t)}.rows.${String(r)}`;
|
|
660
|
+
for (const numbered of numberedBySample) {
|
|
661
|
+
const column = numbered.ref;
|
|
662
|
+
const given = row[column];
|
|
663
|
+
if (given === null)
|
|
664
|
+
continue;
|
|
665
|
+
if (typeof given !== 'number' || !Number.isInteger(given) || given < 1) {
|
|
666
|
+
const now = given === undefined ? 'this row leaves it out' : 'this row gives it something else';
|
|
667
|
+
issues.push({ path: `${at}.${column}`, message: `"${column}" is a running number, and ${now}. Write the row's number (1, 2, 3 …), or "${column}": null to give it none.` });
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
// One series per parent row when the number is scoped: the same number under two parents is two numbers.
|
|
671
|
+
const scope = numbered.rules?.sequence?.scope;
|
|
672
|
+
const key = `${column}\u0000${scope === undefined ? '' : JSON.stringify(row[scope] ?? null)}\u0000${String(given)}`;
|
|
673
|
+
const before = taken.get(key);
|
|
674
|
+
if (before !== undefined)
|
|
675
|
+
issues.push({ path: `${at}.${column}`, message: `"${column}" ${String(given)} is row ${String(before)}'s number already.` });
|
|
676
|
+
else
|
|
677
|
+
taken.set(key, r);
|
|
678
|
+
// The text people read is written with it: nothing writes it for a sample row.
|
|
679
|
+
const text = shape.columns.find((other) => other.rules?.format?.from === column);
|
|
680
|
+
const format = text?.rules?.format;
|
|
681
|
+
if (text === undefined || format === undefined)
|
|
682
|
+
continue;
|
|
683
|
+
const written = row[text.ref];
|
|
684
|
+
const want = format.prefixSetting === undefined ? `${format.prefix ?? ''}${String(given).padStart(format.pad ?? 0, '0')}` : null;
|
|
685
|
+
if (typeof written !== 'string' || written === '') {
|
|
686
|
+
issues.push({ path: `${at}.${text.ref}`, message: `"${text.ref}" is the number as people read it${want === null ? '' : ` ("${want}")`}: a sample row that gives "${column}" writes it too.` });
|
|
687
|
+
}
|
|
688
|
+
else if (want !== null && written !== want) {
|
|
689
|
+
issues.push({ path: `${at}.${text.ref}`, message: `"${text.ref}" is written from "${column}": for ${String(given)} it reads "${want}", not "${written}".` });
|
|
690
|
+
}
|
|
691
|
+
}
|
|
517
692
|
for (const column of gapless) {
|
|
518
693
|
if (row[column] !== null) {
|
|
519
694
|
// Said as what to write: a model given only the reason left the key out, eight times running.
|
|
@@ -541,6 +716,13 @@ function rowIssues(bundle, declared, opts) {
|
|
|
541
716
|
issues.push({ path: `${at}.@onlyIfEmpty`, message: `"${table.ref}" is only for an empty table as a whole; a row of it says nothing more.` });
|
|
542
717
|
continue;
|
|
543
718
|
}
|
|
719
|
+
if (column === '@fillEmpty') {
|
|
720
|
+
if (value !== true)
|
|
721
|
+
issues.push({ path: `${at}.@fillEmpty`, message: '"@fillEmpty" is true, or absent.' });
|
|
722
|
+
else if (row['@onlyIfEmpty'] !== true)
|
|
723
|
+
issues.push({ path: `${at}.@fillEmpty`, message: '"@fillEmpty" goes with "@onlyIfEmpty": it says what to do with the row the table already holds.' });
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
544
726
|
if (column === '@byStay') {
|
|
545
727
|
if (row['@byClock'] !== undefined)
|
|
546
728
|
issues.push({ path: `${at}.@byStay`, message: 'A row takes @byClock or @byStay, not both.' });
|
|
@@ -609,6 +791,11 @@ function rowIssues(bundle, declared, opts) {
|
|
|
609
791
|
issues.push({ path: `${at}.${column}`, message: `"${table.ref}" has no column "${column}".` });
|
|
610
792
|
continue;
|
|
611
793
|
}
|
|
794
|
+
// A file is uploaded by a signed-in person: no sample row brings one.
|
|
795
|
+
if (value !== null && !(Array.isArray(value) && value.length === 0) && shape.columns.find((c) => c.ref === column)?.rules?.file !== undefined) {
|
|
796
|
+
issues.push({ path: `${at}.${column}`, message: `"${table.ref}.${column}" holds files a signed-in person uploads, so a sample row leaves it empty.` });
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
612
799
|
// An object that looks like a directive must BE one: a malformed
|
|
613
800
|
// `@ago` would otherwise be written into the column as JSON.
|
|
614
801
|
if (typeof value === 'object' &&
|
|
@@ -620,6 +807,18 @@ function rowIssues(bundle, declared, opts) {
|
|
|
620
807
|
continue;
|
|
621
808
|
}
|
|
622
809
|
const found = sampleDirective(value);
|
|
810
|
+
// A sample person: one the manifest lists, in a column that can hold a staff member's id.
|
|
811
|
+
for (const key of samplePeopleIn(value)) {
|
|
812
|
+
if (opts.people === undefined)
|
|
813
|
+
issues.push({ path: `${at}.${column}`, message: 'A sample person is named in the app\'s own sample file, not in its rows for an add-on.' });
|
|
814
|
+
else if (!opts.people.has(key))
|
|
815
|
+
issues.push({ path: `${at}.${column}`, message: `"${key}" is not one of the manifest's sample people (sampleData.people).` });
|
|
816
|
+
}
|
|
817
|
+
if (found?.kind === 'person') {
|
|
818
|
+
const holds = shape.columns.find((c) => c.ref === column);
|
|
819
|
+
if (holds?.type !== 'text')
|
|
820
|
+
issues.push({ path: `${at}.${column}`, message: `"${table.ref}.${column}" is not a text column, so it cannot hold a staff member.` });
|
|
821
|
+
}
|
|
623
822
|
if (found?.kind === 'table') {
|
|
624
823
|
const holds = shape.columns.find((c) => c.ref === column);
|
|
625
824
|
if (!opts.names.has(found.ref))
|