« get me outta code hell

withThingsSortedAlphabetically.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/withThingsSortedAlphabetically.js
blob: 5e85fa6a27e88066896915f52c959088b69256c2 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Sorts a list of live, generic wiki data objects alphabetically.
// Note that this uses localeCompare but isn't specialized to a particular
// language; where localization is concerned (in content), a follow-up, locale-
// specific sort should be performed. But this function does serve to organize
// a list so same-name entries are beside each other.

import {input, templateCompositeFrom} from '#composite';
import {compareCaseLessSensitive, normalizeName} from '#sort';
import {validateWikiData} from '#validators';

import {raiseOutputWithoutDependency} from '#composite/control-flow';
import {withMappedList, withSortedList, withPropertiesFromList}
  from '#composite/data';

export default templateCompositeFrom({
  annotation: `withThingsSortedAlphabetically`,

  inputs: {
    things: input({validate: validateWikiData}),
  },

  outputs: ['#sortedThings'],

  steps: () => [
    raiseOutputWithoutDependency({
      dependency: input('things'),
      mode: input.value('empty'),
      output: input.value({'#sortedThings': []}),
    }),

    withPropertiesFromList({
      list: input('things'),
      properties: input.value(['name', 'directory']),
    }).outputs({
      '#list.name': '#names',
      '#list.directory': '#directories',
    }),

    withMappedList({
      list: '#names',
      map: input.value(normalizeName),
    }).outputs({
      '#mappedList': '#normalizedNames',
    }),

    withSortedList({
      list: '#normalizedNames',
      sort: input.value(compareCaseLessSensitive),
    }).outputs({
      '#unstableSortIndices': '#normalizedNameSortIndices',
    }),

    withSortedList({
      list: '#names',
      sort: input.value(compareCaseLessSensitive),
    }).outputs({
      '#unstableSortIndices': '#nonNormalizedNameSortIndices',
    }),

    withSortedList({
      list: '#directories',
      sort: input.value(compareCaseLessSensitive),
    }).outputs({
      '#unstableSortIndices': '#directorySortIndices',
    }),

    // TODO: No primitive for the next two-three steps, yet...

    {
      dependencies: [input('things')],
      compute: (continuation, {
        [input('things')]: things,
      }) => continuation({
        ['#combinedSortIndices']:
          Array.from(
            {length: things.length},
            (_item, index) => index),
      }),
    },

    {
      dependencies: [
        '#combinedSortIndices',
        '#normalizedNameSortIndices',
        '#nonNormalizedNameSortIndices',
        '#directorySortIndices',
      ],

      compute: (continuation, {
        ['#combinedSortIndices']: combined,
        ['#normalizedNameSortIndices']: normalized,
        ['#nonNormalizedNameSortIndices']: nonNormalized,
        ['#directorySortIndices']: directory,
      }) => continuation({
        ['#combinedSortIndices']:
          combined.sort((index1, index2) => {
            if (normalized[index1] !== normalized[index2])
              return normalized[index1] - normalized[index2];

            if (nonNormalized[index1] !== nonNormalized[index2])
              return nonNormalized[index1] - nonNormalized[index2];

            if (directory[index1] !== directory[index2])
              return directory[index1] - directory[index2];

            return 0;
          }),
      }),
    },

    {
      dependencies: [input('things'), '#combinedSortIndices'],
      compute: (continuation, {
        [input('things')]: things,
        ['#combinedSortIndices']: combined,
      }) => continuation({
        ['#sortedThings']:
          combined.map(index => things[index]),
      }),
    },
  ],
});