« get me outta code hell

withResolvedReferenceList.js « wiki-data « composite « data « src - hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/data/composite/wiki-data/withResolvedReferenceList.js
blob: 42f0e1758208011d4731ada1bca94fba015899d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Resolves a list of references, with each reference matched with provided
// data in the same way as withResolvedReference. This will early exit if the
// data dependency is null (even if the reference list is empty). By default
// it will filter out references which don't match, but this can be changed
// to early exit ({notFoundMode: 'exit'}) or leave null in place ('null').

import {input, templateCompositeFrom} from '#composite';
import {is, isString, validateArrayItems} from '#validators';

import {
  exitWithoutDependency,
  raiseOutputWithoutDependency,
} from '#composite/control-flow';

import inputWikiData from './inputWikiData.js';

export default templateCompositeFrom({
  annotation: `withResolvedReferenceList`,

  inputs: {
    list: input({
      validate: validateArrayItems(isString),
      acceptsNull: true,
    }),

    data: inputWikiData({allowMixedTypes: true}),
    find: input({type: 'function'}),

    notFoundMode: input({
      validate: is('exit', 'filter', 'null'),
      defaultValue: 'filter',
    }),
  },

  outputs: ['#resolvedReferenceList'],

  steps: () => [
    exitWithoutDependency({
      dependency: input('data'),
      value: input.value([]),
    }),

    raiseOutputWithoutDependency({
      dependency: input('list'),
      mode: input.value('empty'),
      output: input.value({
        ['#resolvedReferenceList']: [],
      }),
    }),

    {
      dependencies: [input('list'), input('data'), input('find')],
      compute: (continuation, {
        [input('list')]: list,
        [input('data')]: data,
        [input('find')]: findFunction,
      }) =>
        continuation({
          '#matches': list.map(ref => findFunction(ref, data, {mode: 'quiet'})),
        }),
    },

    {
      dependencies: ['#matches'],
      compute: (continuation, {'#matches': matches}) =>
        (matches.every(match => match)
          ? continuation.raiseOutput({
              ['#resolvedReferenceList']: matches,
            })
          : continuation()),
    },

    {
      dependencies: ['#matches', input('notFoundMode')],
      compute(continuation, {
        ['#matches']: matches,
        [input('notFoundMode')]: notFoundMode,
      }) {
        switch (notFoundMode) {
          case 'exit':
            return continuation.exit([]);

          case 'filter':
            return continuation.raiseOutput({
              ['#resolvedReferenceList']:
                matches.filter(match => match),
            });

          case 'null':
            return continuation.raiseOutput({
              ['#resolvedReferenceList']:
                matches.map(match => match ?? null),
            });

          default:
            throw new TypeError(`Expected notFoundMode to be exit, filter, or null`);
        }
      },
    },
  ],
});