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
|
// Code that deals with URLs (really the pathnames that get referenced all
// throughout the gener8ted HTML). Most nota8ly here is generateURLs, which
// is in charge of pre-gener8ting a complete network of template strings
// which can really quickly take su8stitute parameters to link from any one
// place to another; 8ut there are also a few other utilities, too.
//
// Nota8ly, everything here is string-8ased, for gener8ting and transforming
// actual path strings. More a8stract operations using wiki data o8jects is
// the domain of link.js.
import * as path from 'path';
import { withEntries } from './sugar.js';
export function generateURLs(urlSpec) {
const getValueForFullKey = (obj, fullKey, prop = null) => {
const [ groupKey, subKey ] = fullKey.split('.');
if (!groupKey || !subKey) {
throw new Error(`Expected group key and subkey (got ${fullKey})`);
}
if (!obj.hasOwnProperty(groupKey)) {
throw new Error(`Expected valid group key (got ${groupKey})`);
}
const group = obj[groupKey];
if (!group.hasOwnProperty(subKey)) {
throw new Error(`Expected valid subkey (got ${subKey} for group ${groupKey})`);
}
return {
value: group[subKey],
group
};
};
const generateTo = (fromPath, fromGroup) => {
const rebasePrefix = '../'.repeat((fromGroup.prefix || '').split('/').filter(Boolean).length);
const pathHelper = (toPath, toGroup) => {
let target = (toPath === '/' ? '' : toPath);
let argIndex = 0;
target = target.replaceAll('<>', () => `<${argIndex++}>`);
if (toGroup.prefix !== fromGroup.prefix) {
// TODO: Handle differing domains in prefixes.
target = rebasePrefix + (toGroup.prefix || '') + target;
}
const suffix = (toPath.endsWith('/') ? '/' : '');
return {
posix: path.posix.relative(fromPath, target) + suffix,
device: path.relative(fromPath, target) + suffix
};
};
const groupSymbol = Symbol();
const groupHelper = urlGroup => ({
[groupSymbol]: urlGroup,
...withEntries(urlGroup.paths, entries => entries
.map(([key, path]) => [key, pathHelper(path, urlGroup)]))
});
const relative = withEntries(urlSpec, entries => entries
.map(([key, urlGroup]) => [key, groupHelper(urlGroup)]));
const toHelper = (delimiterMode) => (key, ...args) => {
const {
value: {[delimiterMode]: template}
} = getValueForFullKey(relative, key);
let missing = 0;
let result = template.replaceAll(/<([0-9]+)>/g, (match, n) => {
if (n < args.length) {
return args[n];
} else {
missing++;
}
});
if (missing) {
throw new Error(`Expected ${missing + args.length} arguments, got ${args.length} (key ${key}, args [${args}])`);
}
return result;
};
return {
to: toHelper('posix'),
toDevice: toHelper('device')
};
};
const generateFrom = () => {
const map = withEntries(urlSpec, entries => entries
.map(([key, group]) => [key, withEntries(group.paths, entries => entries
.map(([key, path]) => [key, generateTo(path, group)])
)]));
const from = key => getValueForFullKey(map, key).value;
return {from, map};
};
return generateFrom();
}
const thumbnailHelper = name => file =>
file.replace(/\.(jpg|png)$/, name + '.jpg');
export const thumb = {
medium: thumbnailHelper('.medium'),
small: thumbnailHelper('.small')
};
|