-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
120 lines (113 loc) · 2.66 KB
/
index.js
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
const deepEqual = require('deep-equal')
const has = require('has')
const number = require('commonform-number')
const predicate = require('commonform-predicate')
module.exports = (form, values) => {
const numberings = number(form)
return resolveForm(
form,
[],
values,
numberings.form,
numberings.headings
)
}
function resolveForm (form, path, values, numberings, headings) {
form.content = form.content
// resolve content
.map(function (element, index) {
const numbering = (
(
numberings &&
has(numberings, 'content') &&
has(numberings.content, index)
)
? numberings.content[index]
: null
)
const childPath = path.concat('content', index)
return resolveElement(
element,
childPath,
values,
numbering,
headings
)
})
// Concatenate contiguous strings.
.reduce(function (content, element, index) {
const count = content.length
const last = content[count - 1]
if (
index > 0 &&
typeof element === 'string' &&
typeof last === 'string'
) {
content[count - 1] = last + element
} else {
content.push(element)
}
return content
}, [])
return form
}
function resolveElement (element, path, values, numbering, headings) {
if (predicate.child(element)) {
element.numbering = numbering.numbering
element.form = resolveForm(
element.form,
path.concat('form'),
values,
numbering.form || null,
headings
)
return element
} else if (predicate.component(element)) {
element.numbering = numbering.numbering
return element
} else if (predicate.reference(element)) {
const heading = element.reference
// Resolvable
if (has(headings, heading)) {
const matches = headings[heading]
// Unambiguous
if (matches.length === 1) {
return {
heading,
numbering: matches[0]
}
// Ambiguous
} else {
return {
ambiguous: true,
heading,
numberings: matches
}
}
// Broken
} else {
delete element.reference
element.heading = heading
element.broken = true
return element
}
} else if (predicate.blank(element)) {
const text = value(path, values)
// Filled
if (text) {
return { blank: text }
// Empty
} else {
return { blank: undefined }
}
} else {
return element
}
}
function value (path, values) {
for (const element of values) {
if (deepEqual(element.blank, path)) {
return element.value
}
}
}