diff --git a/buildcfg/jsdoc/symbols/conf.json b/buildcfg/jsdoc/info/conf.json similarity index 58% rename from buildcfg/jsdoc/symbols/conf.json rename to buildcfg/jsdoc/info/conf.json index 29f6b31ecd..90eab39059 100644 --- a/buildcfg/jsdoc/symbols/conf.json +++ b/buildcfg/jsdoc/info/conf.json @@ -1,7 +1,7 @@ { "opts": { "recurse": true, - "template": "buildcfg/jsdoc/symbols" + "template": "buildcfg/jsdoc/info" }, "tags": { "allowUnknownTags": true @@ -10,6 +10,7 @@ "includePattern": "\\.js$" }, "plugins": [ - "buildcfg/jsdoc/symbols/todo-plugin" + "buildcfg/jsdoc/info/define-plugin", + "buildcfg/jsdoc/info/todo-plugin" ] } diff --git a/buildcfg/jsdoc/info/define-plugin.js b/buildcfg/jsdoc/info/define-plugin.js new file mode 100644 index 0000000000..57c4e355f2 --- /dev/null +++ b/buildcfg/jsdoc/info/define-plugin.js @@ -0,0 +1,35 @@ +/** + * @fileoverview This plugin extracts info from boolean defines. This only + * handles boolean defines with the default value in the description. Default + * is assumed to be provided with something like "default is `true`" (case + * insensitive, with or without ticks). + */ + + +var DEFAULT_VALUE = /default\s+is\s+`?(true|false)`?/i; + + +/** + * Hook to define new tags. + * @param {Object} dictionary The tag dictionary. + */ +exports.defineTags = function(dictionary) { + + dictionary.defineTag('define', { + canHaveType: true, + mustHaveValue: true, + onTagged: function(doclet, tag) { + var types = tag.value.type.names; + if (types.length === 1 && types[0] === 'boolean') { + var match = tag.value.description.match(DEFAULT_VALUE); + if (match) { + doclet.define = { + default: match[1] === 'true' + }; + doclet.description = tag.value.description; + } + } + } + }); + +}; diff --git a/buildcfg/jsdoc/info/publish.js b/buildcfg/jsdoc/info/publish.js new file mode 100644 index 0000000000..6972c39b49 --- /dev/null +++ b/buildcfg/jsdoc/info/publish.js @@ -0,0 +1,59 @@ +/** + * @fileoverview Generates JSON output based on exportable symbols (those with + * an api tag) and boolean defines (with a define tag and a default value). + */ +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); + + +/** + * Publish hook for the JSDoc template. Writes to JSON stdout. + * @param {function} data The root of the Taffy DB containing doclet records. + * @param {Object} opts Options. + */ +exports.publish = function(data, opts) { + var cwd = process.cwd(); + + // get all doclets with the "api" property or define (excluding enums, + // typedefs and events) + var docs = data( + [{define: {isObject: true}}, {api: {isString: true}}], + {isEnum: {'!is': true}}, + {kind: {'!is': 'typedef'}}, + {kind: {'!is': 'event'}}).get(); + + // get symbols data, filter out those that are members of private classes + var symbols = []; + var defines = []; + docs.filter(function(doc) { + var include = true; + var constructor = doc.memberof; + if (constructor && constructor.substr(-1) === '_') { + assert.strictEqual(doc.inherited, true, + 'Unexpected export on private class: ' + doc.longname); + include = false; + } + return include; + }).forEach(function(doc) { + if (doc.define) { + defines.push({ + name: doc.longname, + description: doc.description, + path: path.join(doc.meta.path, doc.meta.filename), + default: doc.define.default + }); + } else { + symbols.push({ + name: doc.longname, + description: doc.description, + extends: doc.augments, + path: path.join(doc.meta.path, doc.meta.filename) + }); + } + }); + + process.stdout.write( + JSON.stringify({symbols: symbols, defines: defines}, null, 2)); + +}; diff --git a/buildcfg/jsdoc/symbols/todo-plugin.js b/buildcfg/jsdoc/info/todo-plugin.js similarity index 100% rename from buildcfg/jsdoc/symbols/todo-plugin.js rename to buildcfg/jsdoc/info/todo-plugin.js diff --git a/buildcfg/jsdoc/symbols/publish.js b/buildcfg/jsdoc/symbols/publish.js deleted file mode 100644 index 7363f93c91..0000000000 --- a/buildcfg/jsdoc/symbols/publish.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @fileoverview Generates JSON output based on doclets with the "api" tag. - */ -var assert = require('assert'); -var fs = require('fs'); -var path = require('path'); - - -/** - * Publish hook for the JSDoc template. Writes to JSON stdout. - * @param {function} data The root of the Taffy DB containing doclet records. - * @param {Object} opts Options. - */ -exports.publish = function(data, opts) { - var cwd = process.cwd(); - - // get all doclets with the "api" property, but no enums, typedefs and events. - var docs = data( - {api: {isString: true}}, - {isEnum: {'!is': true}}, - {kind: {'!is': 'typedef'}}, - {kind: {'!is': 'event'}} - ).get(); - - // get symbols data, filter out those that are members of private classes - var symbols = docs.filter(function(doc) { - var include = true; - var constructor = doc.memberof; - if (constructor && constructor.substr(-1) === '_') { - assert.strictEqual(doc.inherited, true, - 'Unexpected export on private class: ' + doc.longname); - include = false; - } - return include; - }).map(function(doc) { - return { - name: doc.longname, - extends: doc.augments, - path: path.join(doc.meta.path, doc.meta.filename) - }; - }); - - process.stdout.write(JSON.stringify({symbols: symbols}, null, 2)); - -}; diff --git a/src/ol/ol.js b/src/ol/ol.js index e2048e2c82..97f362903c 100644 --- a/src/ol/ol.js +++ b/src/ol/ol.js @@ -4,7 +4,7 @@ goog.provide('ol'); /** - * @define {boolean} Assume touch. + * @define {boolean} Assume touch. Default is `false`. */ ol.ASSUME_TOUCH = false; @@ -64,57 +64,62 @@ ol.DRAG_BOX_HYSTERESIS_PIXELS = 8; /** - * @define {boolean} Whether to enable canvas. + * @define {boolean} Enable the Canvas renderer. Default is `true`. */ ol.ENABLE_CANVAS = true; /** - * @define {boolean} Whether to enable DOM. + * @define {boolean} Enable the DOM renderer (used as a fallback where Canvas is + * not available). Default is `true`. */ ol.ENABLE_DOM = true; /** - * @define {boolean} Whether to enable rendering of image layers. + * @define {boolean} Enable rendering of ol.layer.Image based layers. Default + * is `true`. */ ol.ENABLE_IMAGE = true; /** - * @define {boolean} Enable named colors. - * Enabling named colors adds about 3KB uncompressed / 1.5KB compressed to the - * final build size. + * @define {boolean} Enable named colors. Enabling named colors adds about 3KB + * uncompressed / 1.5KB compressed to the final build size. Default is + * `true`. */ ol.ENABLE_NAMED_COLORS = true; /** - * @define {boolean} Enable Proj4js. + * @define {boolean} Enable integration with the Proj4js library. Default is + * `true`. */ ol.ENABLE_PROJ4JS = true; /** - * @define {boolean} Whether to enable rendering of tile layers. + * @define {boolean} Enable rendering of ol.layer.Tile based layers. Default is + * `true`. */ ol.ENABLE_TILE = true; /** - * @define {boolean} Whether to enable rendering of vector layers. + * @define {boolean} Enable rendering of ol.layer.Vector based layers. Default + * is `true`. */ ol.ENABLE_VECTOR = true; /** - * @define {boolean} Whether to enable WebGL. + * @define {boolean} Enable the WebGL renderer. Default is `true`. */ ol.ENABLE_WEBGL = true; /** - * @define {boolean} Whether to support legacy IE (7-8). + * @define {boolean} Support legacy IE (7-8). Default is `false`. */ ol.LEGACY_IE_SUPPORT = false; diff --git a/tasks/generate-exports.js b/tasks/generate-exports.js index ab5c4d4b21..70d5dd2b40 100644 --- a/tasks/generate-exports.js +++ b/tasks/generate-exports.js @@ -5,7 +5,7 @@ var async = require('async'); var fse = require('fs-extra'); var nomnom = require('nomnom'); -var generateSymbols = require('./generate-symbols'); +var generateInfo = require('./generate-info'); var build = path.join(__dirname, '..', 'build'); @@ -49,18 +49,18 @@ function getPatterns(configPath, callback) { /** - * Read the symbols file. + * Read the symbols from info file. * @param {Array.} patterns List of patterns to pass along. * @param {funciton(Error, Array., Array.)} callback Called * with the patterns and symbols (or any error). */ function getSymbols(patterns, callback) { - generateSymbols(function(err) { + generateInfo(function(err) { if (err) { - callback(new Error('Trouble generating symbols: ' + err.message)); + callback(new Error('Trouble generating info: ' + err.message)); return; } - var symbols = require('../build/symbols.json').symbols; + var symbols = require('../build/info.json').symbols; callback(null, patterns, symbols); }); } diff --git a/tasks/generate-symbols.js b/tasks/generate-info.js similarity index 55% rename from tasks/generate-symbols.js rename to tasks/generate-info.js index d2882490b4..b89002aa3e 100644 --- a/tasks/generate-symbols.js +++ b/tasks/generate-info.js @@ -7,31 +7,40 @@ var fse = require('fs-extra'); var walk = require('walk').walk; var sourceDir = path.join(__dirname, '..', 'src', 'ol'); -var destPath = path.join(__dirname, '..', 'build', 'symbols.json'); +var infoPath = path.join(__dirname, '..', 'build', 'info.json'); var jsdoc = path.join(__dirname, '..', 'node_modules', '.bin', 'jsdoc'); var jsdocConfig = path.join( - __dirname, '..', 'buildcfg', 'jsdoc', 'symbols', 'conf.json'); + __dirname, '..', 'buildcfg', 'jsdoc', 'info', 'conf.json'); /** - * Read symbols from dest file. - * @param {function(Error, Array, Date)} callback Callback called with any - * error, the symbols array, and the mtime of the symbols file. + * Create a new metadata object. + * @return {Object} New metadata. */ -function readSymbols(callback) { - fs.stat(destPath, function(err, stats) { +function createInfo() { + return {symbols: [], defines: []}; +} + + +/** + * Read symbols & defines metadata from info file. + * @param {function(Error, Object, Date)} callback Callback called with any + * error, the metadata, and the mtime of the info file. + */ +function readInfo(callback) { + fs.stat(infoPath, function(err, stats) { if (err) { if (err.code === 'ENOENT') { - callback(null, [], new Date(0)); + callback(null, createInfo(), new Date(0)); } else { callback(err); } } else { - fs.readFile(destPath, function(err, data) { + fs.readFile(infoPath, function(err, data) { if (err) { callback(err); } else { - callback(null, JSON.parse(String(data)).symbols, stats.mtime); + callback(null, JSON.parse(String(data)), stats.mtime); } }); } @@ -50,13 +59,13 @@ function makeUnique(array) { /** * Generate a list of .js paths in the source directory that are newer than - * the symbols file. - * @param {Array} symbols Array of symbol metadata. - * @param {Date} date Modification time of symbols file. - * @param {function(Error, Array, Array.)} callback Callback called with - * any error, the symbols array, and the array of newer source paths. + * the info file. + * @param {Object} info Symbol and defines metadata. + * @param {Date} date Modification time of info file. + * @param {function(Error, Object, Array.)} callback Called with any + * error, the info object, and the array of newer source paths. */ -function getNewer(symbols, date, callback) { +function getNewer(info, date, callback) { var allPaths = []; var newerPaths = []; @@ -77,7 +86,7 @@ function getNewer(symbols, date, callback) { walker.on('end', function() { // prune symbols if file no longer exists or has been modified var lookup = {}; - symbols.forEach(function(symbol) { + info.symbols.forEach(function(symbol) { lookup[symbol.name] = symbol; }); @@ -100,7 +109,7 @@ function getNewer(symbols, date, callback) { var dirtyPaths = []; - symbols = symbols.filter(function(symbol) { + info.symbols = info.symbols.filter(function(symbol) { var dirty = allPaths.indexOf(symbol.path) < 0; if (!dirty) { // confirm that symbol and all parent paths are not newer @@ -116,21 +125,30 @@ function getNewer(symbols, date, callback) { return !dirty; }); - callback(null, symbols, makeUnique(newerPaths.concat(dirtyPaths))); + info.defines = info.defines.filter(function(define) { + var dirty = allPaths.indexOf(define.path) < 0 || + newerPaths.indexOf(define.path) >= 0; + if (dirty) { + dirtyPaths.push(define.path); + } + return !dirty; + }); + + callback(null, info, makeUnique(newerPaths.concat(dirtyPaths))); }); } /** * Spawn JSDoc. - * @param {Array} symbols Array of symbol metadata. + * @param {Object} info Symbol and defines metadata. * @param {Array.} newerSources Paths to newer source files. * @param {function(Error, Array, string)} callback Callback called with any - * error, existing symbols, and the JSDoc output. + * error, existing metadata, and the JSDoc output (new metadata). */ -function spawnJSDoc(symbols, newerSources, callback) { +function spawnJSDoc(info, newerSources, callback) { if (newerSources.length === 0) { - callback(null, symbols, JSON.stringify({symbols: []})); + callback(null, info, JSON.stringify(createInfo())); return; } @@ -150,12 +168,49 @@ function spawnJSDoc(symbols, newerSources, callback) { if (code) { callback(new Error(errors || 'JSDoc failed with no output')); } else { - callback(null, symbols, output); + callback(null, info, output); } }); } +/** + * Parse the JSDoc output. + * @param {Object} info Existing metadata. + * @param {string} output JSDoc output + * @param {function(Error, Object, Object)} callback Called with any error, + * existing metadata, and new metadata. + */ +function parseOutput(info, output, callback) { + if (!output) { + callback(new Error('Expected JSON output')); + return; + } + + var newInfo; + try { + newInfo = JSON.parse(String(output)); + } catch (err) { + callback(new Error('Failed to parse output as JSON: ' + output)); + return; + } + + if (!Array.isArray(newInfo.symbols)) { + callback(new Error('Expected symbols array: ' + output)); + return; + } + + if (!Array.isArray(newInfo.defines)) { + callback(new Error('Expected defines array: ' + output)); + return; + } + + process.nextTick(function() { + callback(null, info, newInfo); + }); +} + + /** * Given the path to a source file, get the list of provides. * @param {string} srcPath Path to source file. @@ -182,85 +237,67 @@ var getProvides = async.memoize(function(srcPath, callback) { /** - * Add provides to a symbol. - * @param {Object} symbol Symbol object. - * @param {function(Error, Object)} callback Called with the augmented symbol or - * any error. + * Add provides data to new symbols. + * @param {Object} info Existing symbols and defines metadata. + * @param {Object} newInfo New metadata. + * @param {function(Error, Object)} callback Updated metadata. */ -function addProvides(symbol, callback) { - getProvides(symbol.path, function(err, provides) { - if (err) { - callback(err); - return; - } - symbol.provides = provides; - callback(null, symbol); +function addSymbolProvides(info, newInfo, callback) { + + function addProvides(symbol, callback) { + getProvides(symbol.path, function(err, provides) { + if (err) { + callback(err); + return; + } + symbol.provides = provides; + callback(null, symbol); + }); + } + + async.map(newInfo.symbols, addProvides, function(err, newSymbols) { + newInfo.symbols = newSymbols; + callback(err, info, newInfo); }); } /** - * Parse JSDoc output and add provides data to each symbol. - * @param {Array} symbols Existing symbols. - * @param {string} output Output from JSDoc. - * @param {function(Error, Array)} callback Concatenated symbols. - */ -function addAllProvides(symbols, output, callback) { - if (!output) { - callback(new Error('Expected JSON output')); - return; - } - - var data; - try { - data = JSON.parse(String(output)); - } catch (err) { - callback(new Error('Failed to parse output as JSON: ' + output)); - return; - } - - if (!data || !Array.isArray(data.symbols)) { - callback(new Error('Expected symbols array: ' + output)); - return; - } - - async.map(data.symbols, addProvides, function(err, newSymbols) { - callback(err, symbols, newSymbols); - }); -} - - -/** - * Write symbol metadata to the symbols file. - * @param {Array} symbols Existing symbols. - * @param {Array} newSymbols New symbols. + * Write symbol and define metadata to the info file. + * @param {Object} info Existing metadata. + * @param {Object} newInfo New meatadat. * @param {function(Error)} callback Callback. */ -function writeSymbols(symbols, newSymbols, callback) { +function writeInfo(info, newInfo, callback) { - symbols = symbols.concat(newSymbols).sort(function(a, b) { + info.symbols = info.symbols.concat(newInfo.symbols).sort(function(a, b) { return a.name < b.name ? -1 : 1; }); - var str = JSON.stringify({symbols: symbols}, null, ' '); - fse.outputFile(destPath, str, callback); + info.defines = info.defines.concat(newInfo.defines).sort(function(a, b) { + return a.name < b.name ? -1 : 1; + }); + + var str = JSON.stringify(info, null, ' '); + fse.outputFile(infoPath, str, callback); } /** - * Determine which source files have been changed, run JSDoc against those, - * write out exported symbols, and clean up the build dir. + * Determine which source files have been changed, run JSDoc against those, and + * write out updated info. * - * @param {function(Error)} callback Called when the symbols file has been - * written (or if an error occurs). + * @param {function(Error)} callback Called when the info file has been written + * (or an error occurs). */ function main(callback) { async.waterfall([ - readSymbols, + readInfo, getNewer, spawnJSDoc, - addAllProvides, - writeSymbols + parseOutput, + addSymbolProvides, + writeInfo ], callback); } diff --git a/tasks/readme.md b/tasks/readme.md index 5710e143c9..ca57c7b137 100644 --- a/tasks/readme.md +++ b/tasks/readme.md @@ -66,9 +66,9 @@ To generate a build named `ol.min.js` with the `build.json`, you would run this: Called internally to generate a `build/exports.js` file optionally with a limited set of exports. -## `generate-symbols.js` +## `generate-info.js` -Called internally to parse the library for API annotations and write out a `build/symbols.json` file. +Called internally to parse the library for annotations and write out a `build/info.json` file. ## `parse-examples.js`