Skip to content

Commit d96aa47

Browse files
dignifiedquiretmcw
authored andcommitted
feat(config): add file property for notes (#614)
* feat(config): add file property for notes Fixes #609 * feat(config): resolve files against the config file location
1 parent 43e01ce commit d96aa47

File tree

7 files changed

+172
-6
lines changed

7 files changed

+172
-6
lines changed

docs/CONFIG.md

+21
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,24 @@ This puts the top level API documentation for the `Map`, `LngLat`, and `LngLatBo
2727
items in the given order, and inserts a narrative item titled `Geography`
2828
after the section on maps. The `description` property of that narrative item
2929
is interpreted as Markdown.
30+
If you would like reuse your existing markdown files or just keep the content separate from the configuration you can use the `file` property. It is a filename it will be resolved against the directory that the `documentation.yml` file resides in.
31+
32+
So with a `documentation.yml` file like this
33+
34+
```yml
35+
toc:
36+
- Map
37+
- name: Geography
38+
file: geo.md
39+
- LngLat
40+
- LngLatBounds
41+
```
42+
43+
and a file `geo.md`
44+
45+
```markdown
46+
These are Mapbox GL JS's ways of representing locations
47+
and areas on the sphere.
48+
```
49+
50+
it would produce the same output as the previous example.

lib/load_config.js

+23-5
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,41 @@ var yaml = require('js-yaml'),
1616
*/
1717
function loadConfig(filePath) {
1818
var ext = path.extname(filePath);
19-
var rawFile = fs.readFileSync(
20-
path.resolve(process.cwd(), filePath), 'utf8'
21-
);
19+
var absFilePath = path.resolve(process.cwd(), filePath);
20+
var rawFile = fs.readFileSync(absFilePath, 'utf8');
2221

2322
try {
2423
if (ext === '.json') {
25-
return JSON.parse(stripComments(rawFile));
24+
return processToc(JSON.parse(stripComments(rawFile)));
2625
}
2726

28-
return yaml.safeLoad(rawFile);
27+
return processToc(yaml.safeLoad(rawFile));
2928
} catch (e) {
3029
e.message = 'Cannot read config file: ' +
3130
filePath +
3231
'\nError: ' +
3332
e.message;
3433
throw e;
3534
}
35+
36+
function processToc(config) {
37+
if (!config || !config.toc) {
38+
return config;
39+
}
40+
41+
config.toc = config.toc.map(function (entry) {
42+
if (entry && entry.file) {
43+
entry.file = path.join(
44+
path.dirname(absFilePath),
45+
entry.file
46+
);
47+
}
48+
49+
return entry;
50+
});
51+
52+
return config;
53+
}
3654
}
3755

3856
module.exports = loadConfig;

lib/sort.js

+15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
var parseMarkdown = require('./parse_markdown');
44
var chalk = require('chalk');
5+
var path = require('path');
6+
var fs = require('fs');
57

68
/**
79
* Sort two documentation objects, given an optional order object. Returns
@@ -36,6 +38,19 @@ module.exports = function sortDocs(comments, options) {
3638
var fixed = options.toc.filter(function (val) {
3739
return typeof val === 'object' && val.name;
3840
}).map(function (val) {
41+
if (typeof val.file === 'string') {
42+
var filename = val.file;
43+
if (!path.isAbsolute(val.file)) {
44+
filename = path.join(process.cwd(), val.file);
45+
}
46+
47+
try {
48+
val.description = fs.readFileSync(filename).toString();
49+
delete val.file;
50+
} catch (err) {
51+
process.stderr.write(chalk.red('Failed to read file ' + filename));
52+
}
53+
}
3954
if (typeof val.description === 'string') {
4055
val.description = parseMarkdown(val.description);
4156
}

test/config_fixture/config_file.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
toc:
2+
- name: snowflake
3+
file: ../fixture/snowflake.md

test/fixture/snowflake.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# The Snowflake

test/lib/load_config.js

+7
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,12 @@ test('loadConfig', function (t) {
2828
t.deepEqual(loadConfig(path.join(__dirname, '../config_fixture/config_links.yml')),
2929
{ foo: 'hello [link](https://github.com/my/link) world' }, 'config with markdown link');
3030

31+
t.deepEqual(loadConfig(path.join(__dirname, '../config_fixture/config_file.yml')),{
32+
toc: [{
33+
name: 'snowflake',
34+
file: path.join(__dirname, '../fixture/snowflake.md')
35+
}]
36+
}, 'config with file reference');
37+
3138
t.end();
3239
});

test/lib/sort.js

+102-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use strict';
22

33
var test = require('tap').test,
4-
sort = require('../../lib/sort');
4+
sort = require('../../lib/sort'),
5+
path = require('path');
56

67
test('sort stream alphanumeric', function (t) {
78
var apples = { context: { sortKey: 'a' }, name: 'apples' };
@@ -177,3 +178,103 @@ test('sort an already-sorted stream containing a section/description', function
177178
t.deepEqual(sortTwice, [carrot, sectionMarkdown, bananas, apples]);
178179
t.end();
179180
});
181+
182+
test('sort toc with files', function (t) {
183+
var apples = { context: { sortKey: 'a' }, name: 'apples' };
184+
var carrot = { context: { sortKey: 'b' }, name: 'carrot' };
185+
var bananas = { context: { sortKey: 'c' }, name: 'bananas' };
186+
187+
var snowflake = {
188+
name: 'snowflake',
189+
file: 'test/fixture/snowflake.md'
190+
};
191+
192+
var processedSnowflake = {
193+
name: 'snowflake',
194+
kind: 'note',
195+
description: {
196+
children: [{
197+
children: [{
198+
position: {
199+
end: {column: 16, line: 1, offset: 15},
200+
indent: [],
201+
start: {column: 3, line: 1, offset: 2}
202+
},
203+
type: 'text',
204+
value: 'The Snowflake'
205+
}],
206+
depth: 1,
207+
position: {
208+
end: {column: 16, line: 1, offset: 15},
209+
indent: [],
210+
start: {column: 1, line: 1, offset: 0}
211+
},
212+
type: 'heading'
213+
}],
214+
position: {
215+
end: {column: 1, line: 2, offset: 16},
216+
start: {column: 1, line: 1, offset: 0}
217+
},
218+
type: 'root'
219+
}
220+
};
221+
t.deepEqual(sort([
222+
apples, carrot, bananas
223+
], {
224+
toc: [snowflake]
225+
}), [
226+
processedSnowflake, apples, carrot, bananas
227+
], 'with configuration');
228+
229+
t.end();
230+
});
231+
232+
test('sort toc with files absolute path', function (t) {
233+
var apples = { context: { sortKey: 'a' }, name: 'apples' };
234+
var carrot = { context: { sortKey: 'b' }, name: 'carrot' };
235+
var bananas = { context: { sortKey: 'c' }, name: 'bananas' };
236+
237+
var snowflake = {
238+
name: 'snowflake',
239+
file: path.join(__dirname, '../fixture/snowflake.md')
240+
};
241+
242+
var processedSnowflake = {
243+
name: 'snowflake',
244+
kind: 'note',
245+
description: {
246+
children: [{
247+
children: [{
248+
position: {
249+
end: {column: 16, line: 1, offset: 15},
250+
indent: [],
251+
start: {column: 3, line: 1, offset: 2}
252+
},
253+
type: 'text',
254+
value: 'The Snowflake'
255+
}],
256+
depth: 1,
257+
position: {
258+
end: {column: 16, line: 1, offset: 15},
259+
indent: [],
260+
start: {column: 1, line: 1, offset: 0}
261+
},
262+
type: 'heading'
263+
}],
264+
position: {
265+
end: {column: 1, line: 2, offset: 16},
266+
start: {column: 1, line: 1, offset: 0}
267+
},
268+
type: 'root'
269+
}
270+
};
271+
t.deepEqual(sort([
272+
apples, carrot, bananas
273+
], {
274+
toc: [snowflake]
275+
}), [
276+
processedSnowflake, apples, carrot, bananas
277+
], 'with configuration');
278+
279+
t.end();
280+
});

0 commit comments

Comments
 (0)