@reventlessdev/trait-attachments 1.0.0-alpha.5 → 1.0.0-alpha.50
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 +5 -3
- package/package.json +7 -7
- package/src/Attachments.res +40 -15
- package/src/Attachments_Conformance.res +57 -21
- package/src/Attachments_Conformance.res.mjs +51 -22
- package/src/Attachments_Rules.res +63 -20
- package/src/Attachments_Rules.res.mjs +22 -1
- package/src/Attachments_Scaffold.res +331 -261
- package/src/Attachments_Scaffold.res.mjs +67 -30
|
@@ -8,11 +8,12 @@ import * as Attachments_Rules$TraitAttachments from "./Attachments_Rules.res.mjs
|
|
|
8
8
|
let configSchema = Sury.$schema(s => ({
|
|
9
9
|
entity: s.m(Sury.string),
|
|
10
10
|
entityId: s.m(Sury.string),
|
|
11
|
+
entityIdType: s.m(Sury.$option(Sury.string)),
|
|
11
12
|
noun: s.m(Sury.string),
|
|
12
13
|
file: s.m(Sury.string),
|
|
13
14
|
cardinality: s.m(Sury.$option(Attachments_Rules$TraitAttachments.cardinalitySchema)),
|
|
14
15
|
created: s.m(Sury.string),
|
|
15
|
-
createdCarriesEntityId: s.m(Sury.$option(Sury.
|
|
16
|
+
createdCarriesEntityId: s.m(Sury.$option(Sury.boolean)),
|
|
16
17
|
view: s.m(Sury.string),
|
|
17
18
|
lifecycleType: s.m(Sury.$option(Sury.string)),
|
|
18
19
|
refType: s.m(Sury.$option(Sury.string)),
|
|
@@ -43,6 +44,7 @@ function namesOf(c) {
|
|
|
43
44
|
attached: subject + "Attached",
|
|
44
45
|
removed: subject + "Removed",
|
|
45
46
|
primarySet: c.entity + "Primary" + c.noun + "Set",
|
|
47
|
+
effectiveChanged: c.entity + "Effective" + c.noun + "Changed",
|
|
46
48
|
altTextSet: subject + "AltTextSet",
|
|
47
49
|
notFound: c.entity + "NotFound",
|
|
48
50
|
notAttached: subject + "NotAttached"
|
|
@@ -53,6 +55,19 @@ function refTypeOf(c) {
|
|
|
53
55
|
return Stdlib_Option.getOr(c.refType, "Reventless.UploadableImage.t");
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
function idTypeOf(c) {
|
|
59
|
+
return Stdlib_Option.mapOr(c.entityIdType, "string", t => t + ".t");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function idValueOf(c, literal) {
|
|
63
|
+
let t = c.entityIdType;
|
|
64
|
+
if (t !== undefined) {
|
|
65
|
+
return t + `.make("` + literal + `")`;
|
|
66
|
+
} else {
|
|
67
|
+
return `"` + literal + `"`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
56
71
|
function viewTypeOf(c) {
|
|
57
72
|
if (Stdlib_Option.getOr(c.refType, "Reventless.UploadableImage.t").includes("Image")) {
|
|
58
73
|
return "Reventless.CaptionedImage.t";
|
|
@@ -155,7 +170,7 @@ function sliceSpec(c) {
|
|
|
155
170
|
let sel = selectionTypeOf(c);
|
|
156
171
|
let single = Stdlib_Option.getOr(c.cardinality, "Many") === "Single";
|
|
157
172
|
let attrs = commandAttributes(c);
|
|
158
|
-
let createdArm = Stdlib_Option.getOr(c.createdCarriesEntityId, true) ? ` | ` + c.created + `({ ` + c.entityId + `:
|
|
173
|
+
let createdArm = Stdlib_Option.getOr(c.createdCarriesEntityId, true) ? ` | ` + c.created + `({ ` + c.entityId + `: ` + idTypeOf(c) + `})` : ` | ` + c.created;
|
|
159
174
|
let primaryArm = prefix => {
|
|
160
175
|
if (single) {
|
|
161
176
|
return [];
|
|
@@ -189,6 +204,7 @@ function sliceSpec(c) {
|
|
|
189
204
|
primaryArm(""),
|
|
190
205
|
[
|
|
191
206
|
` | ` + n.altTextSet + `({ ` + c.file + `: ` + ref + `, altText: string})`,
|
|
207
|
+
` | ` + n.effectiveChanged + `({ ` + c.file + `?: ` + ref + `})`,
|
|
192
208
|
` // TODO(graft): add the events this host's own refusal turns on — whatever`,
|
|
193
209
|
` // moves it into a state where attachments may not be changed.`,
|
|
194
210
|
``
|
|
@@ -214,12 +230,12 @@ function sliceSpec(c) {
|
|
|
214
230
|
[
|
|
215
231
|
`@schema`,
|
|
216
232
|
`type command =`,
|
|
217
|
-
attrs + n.attachCmd + `({ ` + c.entityId + `:
|
|
218
|
-
single ? attrs + n.removeCmd + `({ ` + c.entityId + `:
|
|
233
|
+
attrs + n.attachCmd + `({ ` + c.entityId + `: ` + idTypeOf(c) + `, ` + c.file + `: ` + ref + `, altText?: string})`,
|
|
234
|
+
single ? attrs + n.removeCmd + `({ ` + c.entityId + `: ` + idTypeOf(c) + `})` : attrs + n.removeCmd + `({ ` + c.entityId + `: ` + idTypeOf(c) + `, ` + c.file + `: ` + sel + `})`
|
|
219
235
|
],
|
|
220
|
-
single ? [] : [attrs + n.setPrimaryCmd + `({ ` + c.entityId + `:
|
|
236
|
+
single ? [] : [attrs + n.setPrimaryCmd + `({ ` + c.entityId + `: ` + idTypeOf(c) + `, ` + c.file + `: ` + sel + `})`],
|
|
221
237
|
[
|
|
222
|
-
single ? attrs + n.setAltTextCmd + `({ ` + c.entityId + `:
|
|
238
|
+
single ? attrs + n.setAltTextCmd + `({ ` + c.entityId + `: ` + idTypeOf(c) + `, altText: string})` : attrs + n.setAltTextCmd + `({ ` + c.entityId + `: ` + idTypeOf(c) + `, ` + c.file + `: ` + sel + `, altText: string})`,
|
|
223
239
|
``,
|
|
224
240
|
`@schema`,
|
|
225
241
|
`type error =`,
|
|
@@ -229,12 +245,16 @@ function sliceSpec(c) {
|
|
|
229
245
|
``,
|
|
230
246
|
`@schema`,
|
|
231
247
|
`type event =`,
|
|
232
|
-
` | ` + n.attached + `({ ` + c.entityId + `:
|
|
233
|
-
` | ` + n.removed + `({ ` + c.entityId + `:
|
|
248
|
+
` | ` + n.attached + `({ ` + c.entityId + `: ` + idTypeOf(c) + `, ` + c.file + `: ` + ref + `, altText?: string})`,
|
|
249
|
+
` | ` + n.removed + `({ ` + c.entityId + `: ` + idTypeOf(c) + `, ` + c.file + `: ` + ref + `})`
|
|
234
250
|
],
|
|
235
|
-
primaryArm(c.entityId + `:
|
|
251
|
+
primaryArm(c.entityId + `: ` + idTypeOf(c) + `, `),
|
|
236
252
|
[
|
|
237
|
-
` | ` + n.altTextSet + `({ ` + c.entityId + `:
|
|
253
|
+
` | ` + n.altTextSet + `({ ` + c.entityId + `: ` + idTypeOf(c) + `, ` + c.file + `: ` + ref + `, altText: string})`,
|
|
254
|
+
` // The member a reader should now show, or none. A conclusion rather than a`,
|
|
255
|
+
` // decision: most of the moves that change it — a first attachment, a removal`,
|
|
256
|
+
` // promoting the next — are nobody's choice, so nothing else announces them.`,
|
|
257
|
+
` | ` + n.effectiveChanged + `({ ` + c.entityId + `: ` + idTypeOf(c) + `, ` + c.file + `?: ` + ref + `})`,
|
|
238
258
|
``
|
|
239
259
|
],
|
|
240
260
|
commandTransitionBinding(c),
|
|
@@ -273,6 +293,7 @@ function sliceBehavior(c) {
|
|
|
273
293
|
single ? [] : [` | ` + n.primarySet + `({` + c.file + `}) => fold(PrimarySet({ref: ` + c.file + `}))`],
|
|
274
294
|
[
|
|
275
295
|
` | ` + n.altTextSet + `({` + c.file + `, altText}) => fold(AltTextSet({ref: ` + c.file + `, altText}))`,
|
|
296
|
+
` | ` + n.effectiveChanged + `({` + c.file + `: ?ref}) => fold(EffectiveChanged({ref: ref}))`,
|
|
276
297
|
` // TODO(graft): fold this host's own events into its own state.`,
|
|
277
298
|
` }`,
|
|
278
299
|
`}`,
|
|
@@ -332,6 +353,12 @@ function sliceBehavior(c) {
|
|
|
332
353
|
) + n.altTextSet + `({` + c.entityId + `, ` + c.file + `: ref, altText})` + (
|
|
333
354
|
single ? ")" : ""
|
|
334
355
|
),
|
|
356
|
+
` | Attachments.EffectiveChanged({ref}) =>`,
|
|
357
|
+
` ` + (
|
|
358
|
+
single ? "Some(" : ""
|
|
359
|
+
) + n.effectiveChanged + `({` + c.entityId + `, ` + c.file + `: ?ref})` + (
|
|
360
|
+
single ? ")" : ""
|
|
361
|
+
),
|
|
335
362
|
` }`,
|
|
336
363
|
``,
|
|
337
364
|
`let decide = (state, command) =>`,
|
|
@@ -358,7 +385,7 @@ function conformanceBinding(c) {
|
|
|
358
385
|
let id = "e1";
|
|
359
386
|
let refA = Stdlib_Option.getOr(c.refA, `/uploads/00000000-0000-4000-8000-000000000001/a`);
|
|
360
387
|
let refB = Stdlib_Option.getOr(c.refB, `/uploads/00000000-0000-4000-8000-000000000002/b`);
|
|
361
|
-
let createdValue = Stdlib_Option.getOr(c.createdCarriesEntityId, true) ? c.created + `({ ` + c.entityId + `:
|
|
388
|
+
let createdValue = Stdlib_Option.getOr(c.createdCarriesEntityId, true) ? c.created + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `})` : c.created;
|
|
362
389
|
return Belt_Array.concatMany([
|
|
363
390
|
[
|
|
364
391
|
`// The Attachments trait's conformance suite, bound to \`` + n.slice + `\`.`,
|
|
@@ -373,35 +400,43 @@ function conformanceBinding(c) {
|
|
|
373
400
|
` module Behavior = ` + n.slice + `_Behavior`,
|
|
374
401
|
``,
|
|
375
402
|
` // Annotated: the slice consumes and emits same-named constructors.`,
|
|
376
|
-
`
|
|
377
|
-
`
|
|
378
|
-
`
|
|
403
|
+
` // The same facts as the slice consumes them: no ` + c.entityId + `, because the`,
|
|
404
|
+
` // partition already says which entity they belong to.`,
|
|
405
|
+
` module Consumed = {`,
|
|
406
|
+
` let created: array<` + n.slice + `.consumedEvent> = [` + createdValue + `]`,
|
|
407
|
+
` let attached = (ref): ` + n.slice + `.consumedEvent => ` + n.attached + `({ ` + c.file + `: ref})`,
|
|
408
|
+
` let removed = (ref): ` + n.slice + `.consumedEvent => ` + n.removed + `({ ` + c.file + `: ref})`
|
|
379
409
|
],
|
|
380
|
-
single ? [] : [`
|
|
410
|
+
single ? [] : [` let primarySet = (ref): ` + n.slice + `.consumedEvent => ` + n.primarySet + `({ ` + c.file + `: ref})`],
|
|
381
411
|
[
|
|
382
|
-
`
|
|
383
|
-
`
|
|
412
|
+
` let altTextSet = (ref, altText): ` + n.slice + `.consumedEvent =>`,
|
|
413
|
+
` ` + n.altTextSet + `({ ` + c.file + `: ref, altText})`,
|
|
414
|
+
` let effectiveChanged = (ref): ` + n.slice + `.consumedEvent =>`,
|
|
415
|
+
` ` + n.effectiveChanged + `({ ` + c.file + `: ?ref})`,
|
|
416
|
+
` }`,
|
|
384
417
|
``,
|
|
385
|
-
` let attach = ref => ` + n.slice + `.` + n.attachCmd + `({ ` + c.entityId + `:
|
|
418
|
+
` let attach = ref => ` + n.slice + `.` + n.attachCmd + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, ` + c.file + `: ref})`
|
|
386
419
|
],
|
|
387
|
-
single ? [` let clear = ` + n.slice + `.` + n.removeCmd + `({ ` + c.entityId + `:
|
|
388
|
-
` let remove = ref => ` + n.slice + `.` + n.removeCmd + `({ ` + c.entityId + `:
|
|
420
|
+
single ? [` let clear = ` + n.slice + `.` + n.removeCmd + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `})`] : [
|
|
421
|
+
` let remove = ref => ` + n.slice + `.` + n.removeCmd + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, ` + c.file + `: ref})`,
|
|
389
422
|
` let setPrimary = ref =>`,
|
|
390
|
-
` ` + n.slice + `.` + n.setPrimaryCmd + `({ ` + c.entityId + `:
|
|
423
|
+
` ` + n.slice + `.` + n.setPrimaryCmd + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, ` + c.file + `: ref})`
|
|
391
424
|
],
|
|
392
425
|
[
|
|
393
|
-
single ? ` let setAltText = altText => ` + n.slice + `.` + n.setAltTextCmd + `({ ` + c.entityId + `:
|
|
426
|
+
single ? ` let setAltText = altText => ` + n.slice + `.` + n.setAltTextCmd + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, altText})` : ` let setAltText = (ref, altText) =>\n ` + n.slice + `.` + n.setAltTextCmd + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, ` + c.file + `: ref, altText})`,
|
|
394
427
|
``,
|
|
395
|
-
` let attached = ref => ` + n.slice + `.` + n.attached + `({ ` + c.entityId + `:
|
|
396
|
-
` let removed = ref => ` + n.slice + `.` + n.removed + `({ ` + c.entityId + `:
|
|
428
|
+
` let attached = ref => ` + n.slice + `.` + n.attached + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, ` + c.file + `: ref})`,
|
|
429
|
+
` let removed = ref => ` + n.slice + `.` + n.removed + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, ` + c.file + `: ref})`
|
|
397
430
|
],
|
|
398
431
|
single ? [] : [
|
|
399
432
|
` let primarySet = ref =>`,
|
|
400
|
-
` ` + n.slice + `.` + n.primarySet + `({ ` + c.entityId + `:
|
|
433
|
+
` ` + n.slice + `.` + n.primarySet + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, ` + c.file + `: ref})`
|
|
401
434
|
],
|
|
402
435
|
[
|
|
403
436
|
` let altTextSet = (ref, altText) =>`,
|
|
404
|
-
` ` + n.slice + `.` + n.altTextSet + `({ ` + c.entityId + `:
|
|
437
|
+
` ` + n.slice + `.` + n.altTextSet + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, ` + c.file + `: ref, altText})`,
|
|
438
|
+
` let effectiveChanged = ref =>`,
|
|
439
|
+
` ` + n.slice + `.` + n.effectiveChanged + `({ ` + c.entityId + `: ` + idValueOf(c, id) + `, ` + c.file + `: ?ref})`,
|
|
405
440
|
` let notAttached = ` + n.slice + `.` + n.notAttached,
|
|
406
441
|
`}`,
|
|
407
442
|
``,
|
|
@@ -416,7 +451,7 @@ function conformanceBinding(c) {
|
|
|
416
451
|
function singleProjectionPatch(c) {
|
|
417
452
|
let n = namesOf(c);
|
|
418
453
|
return {
|
|
419
|
-
into: `
|
|
454
|
+
into: `StateViewStream/` + c.view + `_Projection.res`,
|
|
420
455
|
at: `the projection's \`switch\`, and one field on \`` + c.view + `\`'s state`,
|
|
421
456
|
contents: [
|
|
422
457
|
`// On the view's state, one field — the reference and its text, in one value.`,
|
|
@@ -456,7 +491,7 @@ function manyProjectionPatch(c) {
|
|
|
456
491
|
let n = namesOf(c);
|
|
457
492
|
let set = c.file + "s";
|
|
458
493
|
return {
|
|
459
|
-
into: `
|
|
494
|
+
into: `StateViewStream/` + c.view + `_Projection.res`,
|
|
460
495
|
at: `the projection's \`switch\`, and one field on \`` + c.view + `\`'s state`,
|
|
461
496
|
contents: [
|
|
462
497
|
`// On the view's state, one field — the set, primary first.`,
|
|
@@ -525,11 +560,11 @@ function emit(config, into, tests) {
|
|
|
525
560
|
return {
|
|
526
561
|
files: [
|
|
527
562
|
{
|
|
528
|
-
path: into + `/
|
|
563
|
+
path: into + `/StateChange/` + n.slice + `.res`,
|
|
529
564
|
contents: sliceSpec(config)
|
|
530
565
|
},
|
|
531
566
|
{
|
|
532
|
-
path: into + `/
|
|
567
|
+
path: into + `/StateChange/` + n.slice + `_Behavior.res`,
|
|
533
568
|
contents: sliceBehavior(config)
|
|
534
569
|
},
|
|
535
570
|
{
|
|
@@ -547,6 +582,8 @@ export {
|
|
|
547
582
|
isSingle,
|
|
548
583
|
namesOf,
|
|
549
584
|
refTypeOf,
|
|
585
|
+
idTypeOf,
|
|
586
|
+
idValueOf,
|
|
550
587
|
viewTypeOf,
|
|
551
588
|
setFieldOf,
|
|
552
589
|
selectionBinding,
|