Skip to content
This repository has been archived by the owner on Nov 9, 2017. It is now read-only.

Commit

Permalink
Lots of parsing changes to support shared examples.
Browse files Browse the repository at this point in the history
- All metadata is now parsed before assets are copied and pages are
  generated.
- Shared examples are now displayed in the example list for all
  components listed in the example's "modules" array.
- Combined metadata output now includes fully-merged component metadata
  instead of the partially-merged metadata that was included before.
  • Loading branch information
rgrove committed Jul 29, 2011
1 parent e4a6cea commit ca0e5c2
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 64 deletions.
5 changes: 5 additions & 0 deletions HISTORY.md
Expand Up @@ -4,6 +4,11 @@ Selleck History
0.1.5 (git)
-----------

* All metadata is now parsed before assets are copied and pages are generated.
* Shared examples are now displayed in the example list for all components
listed in the example's "modules" array.
* Combined metadata output now includes fully-merged component metadata instead
of the partially-merged metadata that was included before.
* Views for non-component and non-example pages now have a boolean `page`
property that's set to `true` (examples similarly have an `example` property).

Expand Down
166 changes: 105 additions & 61 deletions bin/selleck
Expand Up @@ -29,14 +29,24 @@ var fs = require('fs'),
'theme' : selleck.defaultTheme
},

projectLayouts = {},
projectMeta = {},
projectPages = {},
projectPartials = {},
components = {},

project = {
layouts : {},
meta : {},
pages : {},
partials : {},
project : true,
validator : projectValidator
},

stack = new util.Stack(),

themeLayouts = {},
themeMeta = {},
themePartials = {},
theme = {
layouts : {},
meta : {},
partials: {}
},

help = [
"Selleck generates YUI user documentation, Mustache-style.",
Expand Down Expand Up @@ -80,7 +90,7 @@ while ((arg = argv.shift())) {
case '-h':
// WTF. This is seriously the only way I've been able to figure out to
// make Node reliably flush to stdout before exiting. It's ridiculous.
// This is stupid.
// This is stupid.
process.stdout.write(help);
while (!process.stdout.flush()) {};
process.exit();
Expand Down Expand Up @@ -180,64 +190,105 @@ if (options.server) {
// If running as a server, start the server instead of continuing.
require('selleck/lib/server')(options);
} else {
selleck.createOutputDir(options.out);
selleck.createOutputDir(options['out-assets']);

// Load theme layouts and partials, and copy theme assets to the output dir,
// if there are any.
themeLayouts = selleck.getLayouts(options.theme);
themeMeta = selleck.getMetadata(options.theme, 'theme');
themePartials = selleck.getPartials(options.theme);

selleck.copyAssets(fsPath.join(options.theme, 'assets'),
options['out-assets'], true, function (err) {
if (err) { throw err; }
});
theme.layouts = selleck.getLayouts(options.theme);
theme.meta = selleck.getMetadata(options.theme, 'theme');
theme.partials = selleck.getPartials(options.theme);

// Traverse the root path and look for documentation directories.
docs = selleck.findDocs(options.rootPath, docs);

if (docs.project) {
projectLayouts = util.merge(themeLayouts, selleck.getLayouts(docs.project.path));
projectMeta = util.merge(themeMeta, selleck.getMetadata(docs.project.path, 'project'));
projectPartials = util.merge(themePartials, selleck.getPartials(docs.project.path));
projectPages = selleck.getPages(docs.project.path);

log('Generating project docs for ' + docs.project.path, 'info');

selleck.generate(docs.project.path, util.merge(options, {
layouts : projectLayouts,
meta : projectMeta,
partials : projectPartials,
pages : projectPages,
project : true,
skipLoad : true, // Don't reload stuff from the input dir.
validator: projectValidator
}), generateComponents);
} else {
generateComponents();
log('Parsing project: ' + docs.project.path, 'info');

project.layouts = util.merge(theme.layouts, selleck.getLayouts(docs.project.path));
project.meta = util.merge(theme.meta, selleck.getMetadata(docs.project.path, 'project'));
project.partials = util.merge(theme.partials, selleck.getPartials(docs.project.path));
project.pages = selleck.getPages(docs.project.path);
}

log('Parsing components', 'info');

// Initial pass to load all component info.
docs.components.forEach(function(component, index) {
var path = component.path;

selleck.prepare(path, util.merge(options, project, {
component: true,
index : index,
path : path,
validator: componentValidator
}), stack.add(function (err, result) {
if (err) { throw err; }
components[result.meta.name] = result;
}));
});

// Second pass to cross-link examples.
stack.done(function () {
util.each(components, function (component) {
if (!component.meta.examples) { return; }

component.meta.examples.forEach(function (example) {
example.componentName || (example.componentName = component.meta.name);

if (!example.modules) { return; }

example.modules.forEach(function (moduleName) {
var module = components[moduleName];

if (module && moduleName !== example.componentName
&& !example.inherited) {

module.meta.examples || (module.meta.examples = []);
module.meta.examples.push(util.merge(example, {
inherited: true
}));
}
});
});
});

project.components = components;

generateProject();
});

function generateProject() {
selleck.createOutputDir(options.out);
selleck.createOutputDir(options['out-assets']);

selleck.copyAssets(fsPath.join(options.theme, 'assets'),
options['out-assets'], true, function (err) {
if (err) { throw err; }
});

if (docs.project) {
log('Generating project docs for ' + docs.project.path, 'info');

selleck.generate(docs.project.path, util.merge(options, project,
{skipLoad: true}), generateComponents);
} else {
generateComponents();
}
}

function generateComponents(err) {
if (err) { return finish(err); }

var toGenerate = docs.components.length;
var toGenerate = util.size(project.components);

if (!toGenerate) { return finish(); }

// Generate component docs.
docs.components.forEach(function(component) {
util.each(project.components, function(component) {
var path = component.path;

log('Generating component docs for ' + path, 'info');

selleck.generate(path, util.merge(options, {
component: true,
layouts : projectLayouts,
meta : projectMeta,
partials : projectPartials,
pages : projectPages,
validator: componentValidator
}), finishComponent);
selleck.generate(path, util.merge(options, component,
{skipLoad: true}), finishComponent);
});

function finishComponent(err) {
Expand All @@ -260,25 +311,18 @@ if (options.server) {
log('Writing combined metadata to ' + options['out-meta'], 'info');

meta = {
project: util.merge(projectMeta, options.overrideMeta),
components: {}
components: {},
project : util.merge(project.meta, options.overrideMeta)
};

docs.components.forEach(function (component) {
var data = selleck.getMetadata(component.path, 'component');
util.each(project.components, function (component) {
var data = util.merge(component.meta);

if (data && data.name) {
meta.components[data.name] = util.merge(
meta.project.componentDefaults || {},
data,
options.overrideMeta
);

delete meta.components[data.name].componentDefaults;
}
delete data.componentDefaults;
meta.components[component.meta.name] = data;
});

fs.writeFile(options['out-meta'], JSON.stringify(meta), 'utf8', function (err) {
fs.writeFile(options['out-meta'], JSON.stringify(meta, null, 2), 'utf8', function (err) {
if (err) {
throw err;
} else {
Expand Down
57 changes: 57 additions & 0 deletions lib/util.js
Expand Up @@ -118,3 +118,60 @@ function size(obj) {
return Array.isArray(obj) ? obj.length : Object.keys(obj).length;
}
exports.size = size;

/**
Creates a stack for multiple callback management:
var s = new util.Stack();
asyncMethod(s.add(fn));
asyncMethod(s.add(fn));
asyncMethod(s.add(fn));
asyncMethod(s.add(fn));
s.done(function() {
// Called when all async methods are done.
});
@class Stack
@return {Stack} Stack instance
@constructor
**/
var Stack = function () {
this.errors = [];
this.finished = 0;
this.results = [];
this.total = 0;
};

Stack.prototype = {
add: function (fn) {
var self = this,
index = self.total;

self.total += 1;

return function (err) {
if (err) { self.errors[index] = err; }

self.finished += 1;
self.results[index] = fn.apply(null, arguments);
self.test();
};
},

test: function () {
if (this.finished >= this.total && this.callback) {
this.callback.call(null, this.errors.length ? this.errors : null,
this.results, this.data);
}
},

done: function (callback, data) {
this.callback = callback;
this.data = data;
this.test();
}
};

exports.Stack = Stack;
4 changes: 3 additions & 1 deletion themes/default/layouts/main.mustache
Expand Up @@ -44,7 +44,9 @@
<div class="bd">
<ul class="examples">
{{#examples}}
<li data-description="{{description}}"><a href="{{name}}.html">{{displayName}}</a></li>
<li data-description="{{description}}">
<a href="../{{componentName}}/{{name}}.html">{{displayName}}</a>
</li>
{{/examples}}
</ul>
</div>
Expand Down
4 changes: 2 additions & 2 deletions themes/default/theme.json
@@ -1,4 +1,4 @@
{
"yuiGridsUrl": "http://yui.yahooapis.com/3.3.0/build/cssgrids/grids-min.css",
"yuiSeedUrl": "http://yui.yahooapis.com/combo?3.3.0/build/yui/yui-min.js&amp;3.3.0/build/loader/loader-min.js"
"yuiGridsUrl": "http://yui.yahooapis.com/3.4.0pr3/build/cssgrids/grids-min.css",
"yuiSeedUrl": "http://yui.yahooapis.com/3.4.0pr3/build/yui/yui-min.js"
}

0 comments on commit ca0e5c2

Please sign in to comment.