-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathindex.js
165 lines (145 loc) · 4.17 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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
'use strict';
var through = require('through');
var PluginError = require('plugin-error');
var File = require('vinyl');
/**
* Add url, root, parent, siblings and children properties to files, reflecting the structure of
* the directories. Each property points to other file objects.
*
* Values are assigned to the `data` property of each file. Follows `gulp-data` convention so
* won't override any other data already added to the file.
*
* @param array options.baseUrl The base url of the final website
* @param array options.sort The property to sort by
* @return stream
*/
module.exports = function(options) {
var buffer = {};
options = Object.assign({
baseUrl: '',
sort: 'url'
}, options || {});
// Normalize trailing slash on base URL
options.baseUrl = options.baseUrl.replace(/\/$/, '') + '/';
return through(bufferContents, endStream);
/**
* Add URL and buffer all files up into an object
*
* @param {object} file
*/
function bufferContents(file) {
if (file.isNull()) {
return;
}
if (file.isStream()) {
return this.emit('error', new PluginError('gulp-ssg', 'Streaming not supported'));
}
file.data = Object.assign({ url: cleanUrl(file), dirtyUrl: url(file) }, file.data || {});
buffer[cleanUrl(file)] = file;
}
/**
* Emit file data at end of stream
*/
function endStream() {
if (buffer.length === 0) {
return this.emit('end');
}
Object.keys(buffer).forEach(function(url) {
var file = buffer[url];
file.data = Object.assign({
root: buffer[options.baseUrl] || null,
parent: parent(url),
children: children(url),
siblings: siblings(url)
}, file.data || {});
}.bind(this));
Object.keys(buffer).forEach(function(url) {
this.emit('data', buffer[url]);
}.bind(this));
this.emit('end');
}
/**
* Get the parent file for a given URL from the buffer
*
* @param {string} url
*/
function parent(url) {
if (url === options.baseUrl) {
return null;
}
return buffer[parentUrl(url)] || null;
}
function parentUrl(url) {
return url
.replace(/\..+$/, '')
.replace(/\/$/, '')
.split('/')
.slice(0, -1)
.join('/') + '/';
}
/**
* Get the child files for a given URL from the buffer
*
* @param {string} url
*/
function children(url) {
// Filter to find files with this url as parent
var ch = filter(new RegExp('^' + url + '[^/]+/?$'));
sort(ch);
return ch;
}
/**
* Get the sibling files for a given URL from the buffer
*
* @param {string} url
*/
function siblings(url) {
if (url === options.baseUrl) {
return [];
}
// Filter to find files with same parent URL
var sb = filter(new RegExp('^' + parentUrl(url) + '[^/]+/?$'));
sort(sb);
return sb;
}
/**
* Generate the URL for the file
*
* @param {object} file
*/
function url(file) {
return options.baseUrl + file.relative;
}
/**
* Generate a clean URL for the file, without any trailing index.*
*
* @param {object} file
*/
function cleanUrl(file) {
return url(file).replace(/index\..+$/, '');
}
/**
* Sort an array of files on `options.sort` property of `data`
*
* @param {array} files
*/
function sort(files) {
if (!options.sort) {
return;
}
files.sort(function(a, b) {
return a.data[options.sort] >= b.data[options.sort] ? 1 : -1;
});
}
/**
* Filter buffer to return array of files with URLs matching given regex
*/
function filter(rx) {
return Object.keys(buffer).reduce(function(files, val) {
if (rx.test(val)) {
files.push(buffer[val]);
}
return files;
}, []);
}
};