Skip to content

Commit e61cd10

Browse files
committed
Removed peer dependency on unexpected
1 parent ad970fb commit e61cd10

File tree

3 files changed

+172
-136
lines changed

3 files changed

+172
-136
lines changed

README.md

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# The Unexpected documentation site generator
2+
3+
This is a documentation site generator extracted from
4+
[unexpected](http://unexpectedjs.github.io/). This module in only
5+
useful for building documentation sites for unexpected plugins and
6+
unexpected itself.
7+
8+
You add a `generate-site.js` file to your project containing the
9+
following code:
10+
11+
```js
12+
var argv = require('minimist')(process.argv.slice(2));
13+
14+
var unexpected = require('unexpected');
15+
var generator = require('unexpected-documentation-site-generator');
16+
argv.unexpected = unexpected;
17+
generator(argv);
18+
```
19+
20+
Then you add the following scripts to `package.json`:
21+
22+
```json
23+
"scripts": {
24+
"generate-site": "node generate-site.js",
25+
"update-examples": "node generate-site.js --update-examples"
26+
},
27+
```
28+
29+
I know this is anoying but we need to control which version of
30+
unexpected is used, and a peer dependency wont cut it.
31+
32+
Then you add markdown files in a documentation directory. The
33+
subfolders `assertions` and `api` are special. In the `assertions`
34+
folder you add documentation for assertions grouped by type. In the
35+
`api` folder you add documentation for api methods. See
36+
[unexpected](https://github.com/unexpectedjs/unexpected/tree/master/documentation)
37+
as an example on how to structure the documentation.

index.js

+134-131
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
#!/usr/bin/env node
21
/*global __dirname*/
32
var metalSmith = require('metalsmith');
43
var path = require('path');
5-
var argv = require('minimist')(process.argv.slice(2));
6-
var expect = require('unexpected');
74

85
function idToName(id) {
96
return id.replace(/-/g, ' ');
@@ -58,147 +55,153 @@ function addTypeToIndex(typeIndex, type) {
5855
}
5956
}
6057

61-
function sortTypesByHierarchy(assertionsByType) {
62-
var typeIndex = {};
63-
var unknownTypes = [];
64-
Object.keys(assertionsByType).forEach(function (typeName) {
65-
var type = expect.getType(typeName);
66-
if (type) {
67-
addTypeToIndex(typeIndex, type);
68-
} else {
69-
unknownTypes.push(typeName);
70-
}
71-
});
72-
73-
var typeHierarchy = { 'any': getTypeHierarchy(typeIndex, 'any') };
74-
75-
var result = {};
7658

77-
flattenTypeHierarchy(typeHierarchy, assertionsByType).concat(unknownTypes).forEach(function (typeName) {
78-
if (assertionsByType[typeName]) {
79-
result[typeName] = assertionsByType[typeName];
80-
}
81-
});
82-
83-
return result;
84-
}
59+
module.exports = function generate(options) {
60+
var expect = options.unexpected;
8561

86-
metalSmith('.')
87-
.destination('site-build')
88-
.source('documentation')
89-
.use(require('metalsmith-collections')({
90-
assertions: {
91-
pattern: 'assertions/*/*.md'
92-
},
93-
apiPages: {
94-
pattern: 'api/*.md'
95-
},
96-
pages: {
97-
pattern: '*.md'
98-
}
99-
}))
100-
.use(require('./lib/include-static-assets')({ path: path.resolve(__dirname, 'static') }))
101-
// Dynamicly generate metadata for assertion files
102-
.use(function (files, metalsmith, next) {
103-
Object.keys(files).filter(function (file) {
104-
return /\.md$/.test(file);
105-
}).forEach(function (file) {
106-
var id = file.match(/([^\/]+)\.md$/)[1];
107-
var name = idToName(id);
108-
109-
if (!files[file].title) {
110-
files[file].title = name;
62+
function sortTypesByHierarchy(assertionsByType) {
63+
var typeIndex = {};
64+
var unknownTypes = [];
65+
Object.keys(assertionsByType).forEach(function (typeName) {
66+
var type = expect.getType(typeName);
67+
if (type) {
68+
addTypeToIndex(typeIndex, type);
69+
} else {
70+
unknownTypes.push(typeName);
11171
}
72+
});
11273

113-
if (files[file].collection.indexOf('apiPages') !== -1) {
114-
files[file].template = 'api.ejs';
115-
} else if (files[file].collection.indexOf('assertions') !== -1) {
116-
var type = file.match(/^assertions\/([^\/]+)/)[1];
74+
var typeHierarchy = { 'any': getTypeHierarchy(typeIndex, 'any') };
11775

118-
files[file].template = 'assertion.ejs';
119-
files[file].windowTitle = type + ' - ' + name;
120-
files[file].type = type;
121-
}
76+
var result = {};
12277

123-
if (!files[file].windowTitle) {
124-
files[file].windowTitle = files[file].title;
78+
flattenTypeHierarchy(typeHierarchy, assertionsByType).concat(unknownTypes).forEach(function (typeName) {
79+
if (assertionsByType[typeName]) {
80+
result[typeName] = assertionsByType[typeName];
12581
}
126-
127-
files[file].url = '/' + file.replace(/(\/?)index.md$/, '$1').replace(/\.md$/, '/');
128-
});
129-
next();
130-
})
131-
.use(function (files, metalsmith, next) {
132-
var metadata = metalsmith.metadata();
133-
134-
metadata.collections.apiPages.sort(function (a, b) {
135-
var aTitle = a.title.toLowerCase();
136-
var bTitle = b.title.toLowerCase();
137-
if (aTitle < bTitle) return -1;
138-
if (aTitle > bTitle) return 1;
139-
return 0;
14082
});
14183

142-
// Make sure that the most important types are listed first and in this order:
143-
var assertionsByType = {};
144-
metadata.collections.assertions.forEach(function (assertion) {
145-
assertionsByType[assertion.type] = assertionsByType[assertion.type] || [];
146-
assertionsByType[assertion.type].push(assertion);
147-
});
84+
return result;
85+
}
14886

149-
assertionsByType = sortTypesByHierarchy(assertionsByType);
150-
Object.keys(assertionsByType).forEach(function (type) {
151-
assertionsByType[type].sort(function (a, b) {
152-
var aName = a.title.toLowerCase();
153-
var bName = b.title.toLowerCase();
154-
if (aName < bName) return -1;
155-
if (aName > bName) return 1;
87+
metalSmith('.')
88+
.destination('site-build')
89+
.source('documentation')
90+
.use(require('metalsmith-collections')({
91+
assertions: {
92+
pattern: 'assertions/*/*.md'
93+
},
94+
apiPages: {
95+
pattern: 'api/*.md'
96+
},
97+
pages: {
98+
pattern: '*.md'
99+
}
100+
}))
101+
.use(require('./lib/include-static-assets')({ path: path.resolve(__dirname, 'static') }))
102+
// Dynamicly generate metadata for assertion files
103+
.use(function (files, metalsmith, next) {
104+
Object.keys(files).filter(function (file) {
105+
return /\.md$/.test(file);
106+
}).forEach(function (file) {
107+
var id = file.match(/([^\/]+)\.md$/)[1];
108+
var name = idToName(id);
109+
110+
if (!files[file].title) {
111+
files[file].title = name;
112+
}
113+
114+
if (files[file].collection.indexOf('apiPages') !== -1) {
115+
files[file].template = 'api.ejs';
116+
} else if (files[file].collection.indexOf('assertions') !== -1) {
117+
var type = file.match(/^assertions\/([^\/]+)/)[1];
118+
119+
files[file].template = 'assertion.ejs';
120+
files[file].windowTitle = type + ' - ' + name;
121+
files[file].type = type;
122+
}
123+
124+
if (!files[file].windowTitle) {
125+
files[file].windowTitle = files[file].title;
126+
}
127+
128+
files[file].url = '/' + file.replace(/(\/?)index.md$/, '$1').replace(/\.md$/, '/');
129+
});
130+
next();
131+
})
132+
.use(function (files, metalsmith, next) {
133+
var metadata = metalsmith.metadata();
134+
135+
metadata.collections.apiPages.sort(function (a, b) {
136+
var aTitle = a.title.toLowerCase();
137+
var bTitle = b.title.toLowerCase();
138+
if (aTitle < bTitle) return -1;
139+
if (aTitle > bTitle) return 1;
156140
return 0;
157141
});
158-
});
159-
metadata.assertionsByType = assertionsByType;
160-
next();
161-
})
162-
.use(function (files, metalsmith, next) {
163-
var metadata = metalsmith.metadata();
164-
var indexData = [];
165-
166-
metadata.collections.apiPages.forEach(function (assertion) {
167-
indexData.push({
168-
label: assertion.title + ' (api)',
169-
url: assertion.url
142+
143+
// Make sure that the most important types are listed first and in this order:
144+
var assertionsByType = {};
145+
metadata.collections.assertions.forEach(function (assertion) {
146+
assertionsByType[assertion.type] = assertionsByType[assertion.type] || [];
147+
assertionsByType[assertion.type].push(assertion);
170148
});
171-
});
172149

173-
metadata.collections.assertions.forEach(function (assertion) {
174-
indexData.push({
175-
label: assertion.title + ' (' + assertion.type + ')',
176-
url: assertion.url
150+
assertionsByType = sortTypesByHierarchy(assertionsByType);
151+
Object.keys(assertionsByType).forEach(function (type) {
152+
assertionsByType[type].sort(function (a, b) {
153+
var aName = a.title.toLowerCase();
154+
var bName = b.title.toLowerCase();
155+
if (aName < bName) return -1;
156+
if (aName > bName) return 1;
157+
return 0;
158+
});
177159
});
178-
});
179-
files['searchIndex.json'] = { contents: JSON.stringify(indexData, null, 2) };
180-
next();
181-
})
182-
.use(require('metalsmith-unexpected-markdown')({
183-
unexpected: expect,
184-
testFile: path.resolve('.', 'test', 'documentation.spec.js'),
185-
updateExamples: 'update-examples' in argv
186-
}))
160+
metadata.assertionsByType = assertionsByType;
161+
next();
162+
})
163+
.use(function (files, metalsmith, next) {
164+
var metadata = metalsmith.metadata();
165+
var indexData = [];
166+
167+
metadata.collections.apiPages.forEach(function (assertion) {
168+
indexData.push({
169+
label: assertion.title + ' (api)',
170+
url: assertion.url
171+
});
172+
});
173+
174+
metadata.collections.assertions.forEach(function (assertion) {
175+
indexData.push({
176+
label: assertion.title + ' (' + assertion.type + ')',
177+
url: assertion.url
178+
});
179+
});
180+
files['searchIndex.json'] = { contents: JSON.stringify(indexData, null, 2) };
181+
next();
182+
})
183+
.use(require('metalsmith-unexpected-markdown')({
184+
unexpected: expect,
185+
testFile: path.resolve('.', 'test', 'documentation.spec.js'),
186+
updateExamples: !!options['updateExamples']
187+
}))
187188
// permalinks with no options will just make pretty urls...
188-
.use(require('metalsmith-permalinks')({ relative: false }))
189-
.use(function (files, metalsmith, next) {
190-
// Useful for debugging ;-)
191-
// require('uninspected').log(files);
192-
next();
193-
})
194-
.use(require('metalsmith-less')())
195-
.use(require('metalsmith-templates')({
196-
engine: 'ejs',
197-
directory: path.resolve(__dirname, 'templates')
198-
}))
199-
.use(require('metalsmith-autoprefixer')({ browsers: 'last 2 versions', cascade: false }))
200-
.use(require('./lib/delete-less-files')())
201-
.build(function (err) {
202-
if (err) { throw err; }
203-
console.log('wrote site to site-build');
204-
});
189+
.use(require('metalsmith-permalinks')({ relative: false }))
190+
.use(function (files, metalsmith, next) {
191+
// Useful for debugging ;-)
192+
// require('uninspected').log(files);
193+
next();
194+
})
195+
.use(require('metalsmith-less')())
196+
.use(require('metalsmith-templates')({
197+
engine: 'ejs',
198+
directory: path.resolve(__dirname, 'templates')
199+
}))
200+
.use(require('metalsmith-autoprefixer')({ browsers: 'last 2 versions', cascade: false }))
201+
.use(require('./lib/delete-less-files')())
202+
.build(function (err) {
203+
if (err) { throw err; }
204+
console.log('wrote site to site-build');
205+
});
206+
207+
}

package.json

+1-5
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,10 @@
3333
"metalsmith-templates": "0.6.0",
3434
"metalsmith-unexpected-markdown": "1.1.1",
3535
"minimatch": "2.0.7",
36-
"minimist": "1.1.1",
3736
"passerror": "1.1.0",
3837
"stat-mode": "0.2.0"
3938
},
4039
"peerDependencies": {
41-
"unexpected": "*"
42-
},
43-
"bin" : {
44-
"generate-site" : "./index.js"
40+
"minimist": "*"
4541
}
4642
}

0 commit comments

Comments
 (0)