Remove unused code, get tests passing on Travis

This commit is contained in:
Tim Schaub
2017-12-11 16:19:03 -07:00
parent b0c0166e9b
commit 50737f7f73
34 changed files with 66 additions and 1913 deletions

View File

@@ -1,272 +0,0 @@
var path = require('path');
var Metalsmith = require('metalsmith');
var handlebars = require('handlebars');
var templates = require('metalsmith-layouts');
var marked = require('marked');
var pkg = require('../package.json');
var markupRegEx = /([^\/^\.]*)\.html$/;
var cleanupJSRegEx = /.*(\/\/ NOCOMPILE|goog\.require\(.*\);)[\r\n]*/g;
var requiresRegEx = /.*goog\.require\('(ol\.\S*)'\);/g;
var isCssRegEx = /\.css$/;
var isJsRegEx = /\.js(\?.*)?$/;
var srcDir = path.join(__dirname, '..', 'examples');
var destDir = path.join(__dirname, '..', 'build', 'examples');
var templatesDir = path.join(__dirname, '..', 'config', 'examples');
/**
* Returns an array of names that are explicitly required inside the source
* by calling `goog.require('ol.…')`. Only returns `ol.` prefixed names.
*
* @param {string} src The JavaScript sourcecode to search for goog.require.
* @returns {Array.<string>} An array of `ol.*` names.
*/
function getRequires(src) {
var requires = [];
var match = requiresRegEx.exec(src);
while (match) {
requires.push(match[1]);
match = requiresRegEx.exec(src);
}
return requires;
}
/**
* Takes an array of the names of required OpenLayers symbols and returns an
* HTML-snippet with an unordered list to the API-docs for the particular
* classes.
*
* @param {Array.<string>} requires An array of `ol.` names that the source
* requires.
* @returns {string} The HTML-snippet with the list of links to API-docs.
*/
function getLinkToApiHtml(requires) {
var lis = requires.map(function(symb) {
var href = '../apidoc/' + symb + '.html';
return '<li><a href="' + href + '" title="API documentation for ' +
symb + '">' + symb + '</a></li>';
});
return '<ul class="inline">' + lis.join() + '</ul>';
}
/**
* A Metalsmith plugin that adds metadata to the example HTML files. For each
* example HTML file, this adds metadata for related js and css resources. When
* these files are run through the example template, the extra metadata is used
* to show the complete example source in the textarea and submit the parts to
* CodePen.
*
* @param {Object} files The file lookup provided by Metalsmith. Property names
* are file paths relative to the source directory. The file objects
* include any existing metadata (e.g. from YAML front-matter), the file
* contents, and stats.
* @param {Object} metalsmith The metalsmith instance the plugin is being used
* with.
* @param {function(Error)} done Called when done (with any error).
*/
function augmentExamples(files, metalsmith, done) {
setImmediate(done); // all remaining code is synchronous
for (var filename in files) {
var file = files[filename];
var match = filename.match(markupRegEx);
if (match && filename !== 'index.html') {
if (!file.layout) {
throw new Error(filename + ': Missing "layout" in YAML front-matter');
}
var id = match[1];
// add js tag and source
var jsFilename = id + '.js';
if (!(jsFilename in files)) {
throw new Error('No .js file found for ' + filename);
}
var jsSource = files[jsFilename].contents.toString()
// Change data paths to absolute urls
.replace(/'data\//g, '\'https://openlayers.org/en/v' + pkg.version + '/examples/data/');
if (file.cloak) {
for (var key in file.cloak) {
jsSource = jsSource.replace(new RegExp(key, 'g'), file.cloak[key]);
}
}
var requires = getRequires(jsSource);
file.requires = requires;
file.js = {
tag: '<script src="loader.js?id=' + id + '"></script>',
source: jsSource.replace(cleanupJSRegEx, ''),
apiHtml: getLinkToApiHtml(requires)
};
// add css tag and source
var cssFilename = id + '.css';
if (cssFilename in files) {
file.css = {
tag: '<link rel="stylesheet" href="' + cssFilename + '">',
source: files[cssFilename].contents.toString()
};
}
// add additional resources
if (file.resources) {
var resources = [];
var remoteResources = [];
var codePenResources = [];
for (var i = 0, ii = file.resources.length; i < ii; ++i) {
var resource = file.resources[i];
var remoteResource = resource.indexOf('//') === -1 ?
'https://openlayers.org/en/v' + pkg.version + '/examples/' +
resource : resource;
codePenResources[i] = remoteResource;
if (isJsRegEx.test(resource)) {
resources[i] = '<script src="' + resource + '"></script>';
remoteResources[i] = '<script src="' + remoteResource +
'"></script>';
} else if (isCssRegEx.test(resource)) {
if (resource.indexOf('bootstrap.min.css') === -1) {
resources[i] = '<link rel="stylesheet" href="' + resource + '">';
}
remoteResources[i] = '<link rel="stylesheet" href="' +
remoteResource + '">';
} else {
throw new Error('Invalid value for resource: ' +
resource + ' is not .js or .css: ' + filename);
}
}
file.extraHead = {
local: resources.join('\n'),
remote: remoteResources.join('\n')
};
file.extraResources = file.resources.length ?
',' + codePenResources.join(',') : '';
}
}
}
}
/**
* Create an inverted index of keywords from examples. Property names are
* lowercased words. Property values are objects mapping example index to word
* count.
* @param {Array.<Object>} exampleInfos Array of example info objects.
* @return {Object} Word index.
*/
function createWordIndex(exampleInfos) {
var index = {};
var keys = ['shortdesc', 'title', 'tags', 'requires'];
exampleInfos.forEach(function(info, i) {
keys.forEach(function(key) {
var text = info[key];
if (Array.isArray(text)) {
text = text.join(' ');
}
var words = text ? text.split(/\W+/) : [];
words.forEach(function(word) {
if (word) {
word = word.toLowerCase();
var counts = index[word];
if (counts) {
if (index in counts) {
counts[i] += 1;
} else {
counts[i] = 1;
}
} else {
counts = {};
counts[i] = 1;
index[word] = counts;
}
}
});
});
});
return index;
}
/**
* A plugin that generates the example index.js file. This file includes a
* list of example metadata objects and a word index used when searching for
* examples.
* @param {Object} files The file lookup provided by Metalsmith. Property names
* are file paths relative to the source directory. The file objects
* include any existing metadata (e.g. from YAML front-matter), the file
* contents, and stats.
* @param {Object} metalsmith The metalsmith instance the plugin is being used
* with.
* @param {function(Error)} done Called when done (with any error).
*/
function createIndex(files, metalsmith, done) {
setImmediate(done); // all remaining code is synchronous
var exampleInfos = [];
for (var filename in files) {
var example = files[filename];
if (markupRegEx.test(filename) && filename !== 'index.html') {
exampleInfos.push({
link: filename,
example: filename,
title: example.title,
shortdesc: example.shortdesc,
tags: example.tags,
requires: example.requires
});
}
}
var info = {
examples: exampleInfos,
index: createWordIndex(exampleInfos)
};
files['index.js'] = {
contents: new Buffer('var info = ' + JSON.stringify(info)),
mode: '0644'
};
}
function main(callback) {
var smith = new Metalsmith('.')
.source(srcDir)
.destination(destDir)
.concurrency(25)
.metadata({
olVersion: pkg.version
})
.use(augmentExamples)
.use(createIndex)
.use(templates({
engine: 'handlebars',
directory: templatesDir,
helpers: {
md: function(str) {
return new handlebars.SafeString(marked(str));
},
indent: function(text, options) {
if (!text) {
return text;
}
var count = options.hash.spaces || 2;
var spaces = new Array(count + 1).join(' ');
return text.split('\n').map(function(line) {
return line ? spaces + line : '';
}).join('\n');
}
}
}))
.build(function(err) {
callback(err);
});
return smith;
}
if (require.main === module) {
main(function(err) {
if (err) {
process.stderr.write(
'Building examples failed. See the full trace below.\n\n' +
err.stack + '\n');
process.exit(1);
} else {
process.exit(0);
}
});
}
module.exports = main;

View File

@@ -1,75 +0,0 @@
'use strict';
const cleanup = require('rollup-plugin-cleanup');
const common = require('rollup-plugin-commonjs');
const node = require('rollup-plugin-node-resolve');
const path = require('path');
const pkg = require('../package.json');
const rollup = require('rollup').rollup;
/**
* Wrap a bundled dependency for consumption by the Compiler.
* @param {Object} ext Details from the `ext` object in package.json.
* @return {Object} A rollup plugin.
*/
function wrap(ext) {
return {
name: 'googup',
transformBundle: function(source) {
let name = `ol.ext.${ext.name || ext.module}`;
let postamble = '';
if (ext.import) {
name += '.' + ext.import;
} else {
postamble = `${name} = ${name}.default;\n`;
}
return `
/**
* @fileoverview
* @suppress {accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkRegExp, checkTypes, checkVars, const, constantProperty, deprecated, duplicate, es5Strict, fileoverviewTags, missingProperties, nonStandardJsDocs, strictModuleDepCheck, suspiciousCode, undefinedNames, undefinedVars, unknownDefines, unusedLocalVariables, uselessCode, visibility}
*/
goog.provide('${name}');
/** @typedef {function(*)} */
${name} = function() {};
(function() {${source}}).call(ol.ext);
${postamble}`;
}
};
}
/**
* Build all external modules.
* @return {Promise} Resolves on successful completion.
*/
function main() {
return Promise.all(pkg.ext.map(ext => {
const moduleName = ext.name || ext.module;
const options = {
extend: true,
input: require.resolve(ext.module),
format: 'iife',
exports: 'named',
plugins: [
node(),
common(),
cleanup(),
wrap(ext)
]
};
return rollup(options).then(bundle => {
options.name = moduleName;
options.file = `${path.join(__dirname, '..', 'build', 'ol.ext', moduleName.toLowerCase())}.js`;
bundle.write(options);
});
}));
}
if (require.main === module) {
main().catch(err => {
process.stderr.write(`${err.message}\n`, () => process.exit(1));
});
}
module.exports = main;

View File

@@ -1,324 +0,0 @@
/**
* This task builds OpenLayers with the Closure Compiler.
*/
var path = require('path');
var async = require('async');
var closure = require('closure-util');
var fs = require('fs-extra');
var nomnom = require('nomnom');
var temp = require('temp').track();
var exec = require('child_process').exec;
var generateExports = require('./generate-exports');
var log = closure.log;
var root = path.join(__dirname, '..');
var umdWrapper = ';(function (root, factory) {\n' +
' if (typeof exports === "object") {\n' +
' module.exports = factory();\n' +
' } else if (typeof define === "function" && define.amd) {\n' +
' define([], factory);\n' +
' } else {\n' +
' root.ol = factory();\n' +
' }\n' +
'}(this, function () {\n' +
' var OPENLAYERS = {};\n' +
' %output%\n' +
' return OPENLAYERS.ol;\n' +
'}));\n';
var version;
/**
* Apply defaults and assert that a provided config object is valid.
* @param {Object} config Build configuration object.
* @param {function(Error)} callback Called with an error if config is invalid.
*/
function assertValidConfig(config, callback) {
process.nextTick(function() {
if (!Array.isArray(config.exports)) {
callback(new Error('Config missing "exports" array'));
return;
}
if (config.namespace && typeof config.namespace !== 'string') {
callback(new Error('Config "namespace" must be a string'));
return;
}
if (config.compile && typeof config.compile !== 'object') {
callback(new Error('Config "compile" must be an object'));
return;
}
if (config.jvm && !Array.isArray(config.jvm)) {
callback(new Error('Config "jvm" must be an array'));
return;
}
if (config.src && !Array.isArray(config.src)) {
callback(new Error('Config "src" must be an array'));
return;
}
if (config.umd) {
config.namespace = 'OPENLAYERS';
if (config.compile) {
config.compile.output_wrapper = umdWrapper;
if (version) {
if (!config.compile.define) {
config.compile.define = [];
}
config.compile.define.push('ol.VERSION=\'' + version + '\'');
}
}
}
callback(null);
});
}
/**
* Read the build configuration file.
* @param {string} configPath Path to config file.
* @param {function(Error, Object)} callback Callback.
*/
function readConfig(configPath, callback) {
fs.readFile(configPath, function(err, data) {
if (err) {
if (err.code === 'ENOENT') {
err = new Error('Unable to find config file: ' + configPath);
}
callback(err);
return;
}
var config;
try {
config = JSON.parse(String(data));
} catch (err2) {
callback(new Error('Trouble parsing config as JSON: ' + err2.message));
return;
}
callback(null, config);
});
}
/**
* Write the exports code to a temporary file.
* @param {string} exports Exports code.
* @param {function(Error, string)} callback Called with the path to the temp
* file (or any error).
*/
function writeExports(exports, callback) {
temp.open({prefix: 'exports', suffix: '.js'}, function(err, info) {
if (err) {
callback(err);
return;
}
log.verbose('build', 'Writing exports: ' + info.path);
fs.writeFile(info.path, exports, function(err) {
if (err) {
callback(err);
return;
}
fs.close(info.fd, function(err) {
if (err) {
callback(err);
return;
}
callback(null, info.path);
});
});
});
}
/**
* Get the list of sources sorted in dependency order.
* @param {Object} config Build configuration object.
* @param {string} exports Exports code (with goog.exportSymbol calls).
* @param {function(Error, Array.<string>)} callback Called with a list of paths
* or any error.
*/
function getDependencies(config, exports, callback) {
writeExports(exports, function(err, exportsPath) {
if (err) {
callback(err);
return;
}
log.info('ol', 'Parsing dependencies');
var options;
if (config.src) {
options = {
lib: config.src,
cwd: config.cwd
};
} else {
options = {
lib: ['src/**/*.js', 'build/ol.ext/*.js'],
cwd: root
};
}
closure.getDependencies(options, function(err, paths) {
if (err) {
callback(err);
return;
}
paths.push(exportsPath);
callback(null, paths);
});
});
}
/**
* Concatenate all sources.
* @param {Array.<string>} paths List of paths to source files.
* @param {function(Error, string)} callback Called with the concatenated
* output or any error.
*/
function concatenate(paths, callback) {
async.map(paths, fs.readFile, function(err, results) {
if (err) {
var msg = 'Trouble concatenating sources. ' + err.message;
callback(new Error(msg));
} else {
var parts = umdWrapper.split('%output%');
var src = parts[0] +
'var goog = this.goog = {};\n' +
'this.CLOSURE_NO_DEPS = true;\n' +
results.join('\n') +
'ol.VERSION = \'' + version + '\';\n' +
'OPENLAYERS.ol = ol;\n' +
parts[1];
callback(null, src);
}
});
}
/**
* Run the compiler.
* @param {Object} config Build configuration object.
* @param {Array.<string>} paths List of paths to source files.
* @param {function(Error, string)} callback Called with the compiled output or
* any error.
*/
function build(config, paths, callback) {
var options = {
compile: config.compile,
cwd: config.cwd || root,
jvm: config.jvm
};
if (!options.compile) {
log.info('ol', 'No compile options found. Concatenating ' +
paths.length + ' sources');
concatenate(paths, callback);
} else {
log.info('ol', 'Compiling ' + paths.length + ' sources');
paths = paths.concat('src/ol/typedefs.js');
options.compile.js = paths.concat(options.compile.js || []);
closure.compile(options, callback);
}
}
/**
* Gets the version from the Git tag.
* @param {function(Error, string)} callback Called with the output
* ready to be written into a file, or any error.
*/
function getVersion(callback) {
exec('git describe --tags', function(error, stdout, stderr) {
version = stdout.trim();
callback(null);
});
}
/**
* Adds a file header with the most recent Git tag.
* @param {string} compiledSource The compiled library.
* @param {function(Error, string)} callback Called with the output
* ready to be written into a file, or any error.
*/
function addHeader(compiledSource, callback) {
var header = '// OpenLayers. See https://openlayers.org/\n';
header += '// License: https://raw.githubusercontent.com/openlayers/' +
'openlayers/master/LICENSE.md\n';
if (version !== '') {
header += '// Version: ' + version + '\n';
}
callback(null, header + compiledSource);
}
/**
* Generate a build of the library.
* @param {Object} config Build configuration object. Must have an "exports"
* array and a "compile" object with options for the compiler.
* @param {function(Error, string)} callback Called with the compiled source
* or any error.
*/
function main(config, callback) {
async.waterfall([
getVersion,
assertValidConfig.bind(null, config),
generateExports.bind(null, config),
getDependencies.bind(null, config),
build.bind(null, config),
addHeader
], callback);
}
/**
* If running this module directly, read the config file and call the main
* function.
*/
if (require.main === module) {
var options = nomnom.options({
config: {
position: 0,
required: true,
help: 'Path to JSON config file'
},
output: {
position: 1,
required: true,
help: 'Output file path'
},
loglevel: {
abbr: 'l',
choices: ['silly', 'verbose', 'info', 'warn', 'error'],
default: 'info',
help: 'Log level',
metavar: 'LEVEL'
}
}).parse();
/**
* Set the log level.
* @type {string}
*/
log.level = options.loglevel;
// read the config, run the main function, and write the output file
async.waterfall([
readConfig.bind(null, options.config),
main,
fs.outputFile.bind(fs, options.output)
], function(err) {
if (err) {
log.error(err.message);
process.exit(1);
} else {
process.exit(0);
}
});
}
/**
* Export main function.
*/
module.exports = main;

View File

@@ -1,64 +0,0 @@
/*eslint-env es6*/
const http = require('http');
const path = require('path');
const serveFiles = require('serve-files');
const spawn = require('child_process').spawn;
if (!process.argv[2]) {
process.stdout.write(`USAGE: node ${path.basename(module.filename)} [example_path]\n`);
process.exit(0);
}
const root = process.cwd();
const port = 8000;
const host = null;
const examplePath = process.argv[2];
const phantomPath = require('phantomjs-prebuilt').path;
const server = http.createServer(serveFiles.createFileResponseHandler({
documentRoot: root,
followSymbolicLinks: false,
cacheTimeInSeconds: 3600
}));
server.listen(port, host, null, function() {
const childProcess = spawn(phantomPath, ['--ssl-protocol=any', '--ignore-ssl-errors=true', path.join(__dirname, '..', 'bin', 'check-example.js'), 'http://localhost:8000/' + examplePath]);
childProcess.stdout.pipe(process.stdout);
childProcess.stderr.pipe(process.stderr);
process.stdin.pipe(childProcess.stdin);
childProcess.on('error', function(err) {
process.stderr.write(`Error executing phantom on ${phantomPath}\n`);
process.stderr.write(err.stack + '\n');
process.exit(1);
});
childProcess.on('exit', function(code) {
process.exit(code);
});
});
// Keep track of connections, to enforce killing them when server must be stopped.
var connections = {};
server.on('connection', function(socket) {
socket._cid = process.hrtime();
connections[socket._cid] = socket;
socket.on('end', function() {
delete connections[this._cid];
});
});
['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT', 'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGTERM'].forEach(signal => {
process.once(signal, () => {
process.stdout.write(`Got ${signal}, stopping...\n`),
server.close(() => {
process.stdout.write('Stopped.\n');
process.exit(0);
});
Object.keys(connections).forEach(cid => connections[cid].destroy());
});
});

View File

@@ -1,29 +0,0 @@
const glob = require('glob');
const fs = require('fs');
const path = require('path');
glob('src/**/*.js', {}, function(err, files) {
if (!err) {
process.stdout.write(`Checking ${files.length} files...\n`);
let renamed = 0;
files.forEach(function(filename) {
const contents = fs.readFileSync(filename, 'utf-8');
const lines = contents.split('\n');
for (let i = lines.length - 1; i >= 0; --i) {
const line = lines[i];
const match = line.match(/goog\.provide\('.*\.([^']*)'\);$/);
if (match && match.length) {
const newName = match[1] + '.js';
if (newName != newName.toLowerCase()) {
fs.renameSync(filename, path.resolve(path.dirname(filename), newName));
++renamed;
}
}
}
});
process.stdout.write(`Renamed ${renamed} files.\n`);
} else {
process.stdout.write(err.message);
process.exit(1);
}
});

View File

@@ -1,10 +0,0 @@
var buildExt = require('./build-ext');
buildExt(function(err) {
if (err) {
process.stderr.write(err + '\n');
process.exit(1);
} else {
process.exit(0);
}
});

View File

@@ -106,22 +106,6 @@ Called internally to parse the library for annotations and write out a `build/in
Builds examples and the example index.
## `check-example.js`
Runs an example in PhantomJS and returns an exit code != 0 after printing a stack trace when something is wrong with the example.
To check the `simple.html` example when on master, first run the `build-examples.js` task, then invoke
node tasks/check-example.js build/hosted/master/simple.html
## `serve.js`
Run a debug server that provides all library sources unminified. Provides a static server for examples and tests. See the `--help` option for more detail.
node tasks/serve.js --help
## `test.js`
Run the tests once in a headless browser. Note that you can also run the tests by running the `serve.js` task and then visiting the root of the test directory in your browser.

View File

@@ -1,113 +0,0 @@
/**
* This task starts a dev server that provides a script loader for the
* OpenLayers library.
*/
var path = require('path');
var closure = require('closure-util');
var nomnom = require('nomnom');
var log = closure.log;
var name = path.basename(__filename, '.js');
/**
* Create a debug server for the OpenLayers and Closure Library sources.
* @param {function(Error, closure.Server)} callback Callback.
*/
var createServer = exports.createServer = function(callback) {
var server;
var manager = new closure.Manager({
lib: [
'src/**/*.js',
'build/ol.ext/*.js'
],
cwd: path.join(__dirname, '..')
});
manager.on('error', function(err) {
if (server) {
log.error('serve', err.message);
} else {
callback(err);
}
});
manager.on('ready', function() {
server = new closure.Server({
manager: manager,
loader: '/loader.js'
});
callback(null, server);
});
};
/**
* Try listening for incoming connections on a range of ports.
* @param {number} min Minimum port to try.
* @param {number} max Maximum port to try.
* @param {http.Server} server The server.
* @param {function(Error)} callback Callback called with any error.
*/
function listen(min, max, server, callback) {
function _listen(port) {
server.once('error', function(err) {
if (err.code === 'EADDRINUSE') {
log.warn(name, 'Port %d in use, trying next one', port);
++port;
if (port < max) {
_listen(port);
} else {
callback(new Error('Could not find an open port'));
}
} else {
callback(err);
}
});
server.listen(port);
}
server.once('listening', function() {
callback(null);
});
_listen(min);
}
/**
* If running this module directly start the server.
*/
if (require.main === module) {
var options = nomnom.options({
port: {
abbr: 'p',
default: 3000,
help: 'Port for incoming connections (will try additional ports if used)',
metavar: 'PORT'
},
loglevel: {
abbr: 'l',
choices: ['silly', 'verbose', 'info', 'warn', 'error'],
default: 'info',
help: 'Log level',
metavar: 'LEVEL'
}
}).parse();
/** @type {string} */
log.level = options.loglevel;
log.info(name, 'Parsing dependencies.');
createServer(function(err, server) {
if (err) {
log.error(name, 'Parsing failed');
log.error(name, err.message);
process.exit(1);
}
listen(options.port, options.port + 4, server, function(err) {
if (err) {
log.error(name, 'Server failed to start: ' + err.message);
process.exit(1);
}
log.info(name, 'Debug server running http://localhost:' +
server.address().port + '/loader.js (Ctrl+C to stop)');
});
});
}

View File

@@ -1,158 +0,0 @@
/**
* This task starts a dev server that provides a script loader for OpenLayers
* and Closure Library. In addition, a static server hosts all files in the
* repository.
*/
var path = require('path');
var url = require('url');
var Gaze = require('gaze').Gaze;
var closure = require('closure-util');
var debounce = require('debounce');
var fs = require('fs-extra');
var nomnom = require('nomnom');
var buildExamples = require('./build-examples');
var log = closure.log;
/**
* Create a debug server for ol and Closure Library sources.
* @param {function(Error, closure.Server)} callback Callback.
*/
var createServer = exports.createServer = function(callback) {
var server;
var manager = new closure.Manager({
lib: [
'src/**/*.js',
'build/ol.ext/*.js',
'test/spec/**/*.test.js',
'test_rendering/spec/**/*.test.js',
'build/test_requires.js',
'build/test_rendering_requires.js'
],
main: 'build/examples/*.js'
});
manager.on('error', function(err) {
if (server) {
log.error('serve', err.message);
} else {
callback(err);
}
});
manager.on('ready', function() {
server = new closure.Server({
manager: manager,
loader: /^\/(?:(?:build\/examples)|(?:test(?:_rendering)?))\/loader\.js/,
getMain: function(req) {
var main;
var query = url.parse(req.url, true).query;
var referer = req.headers.referer;
var pathName = url.parse(referer).pathname;
if (pathName.indexOf('/test/') === 0) {
main = path.resolve(
path.join(process.cwd(), 'build'), 'test_requires.js');
} else if (pathName.indexOf('/test_rendering/') === 0) {
main = path.resolve(
path.join(process.cwd(), 'build'), 'test_rendering_requires.js');
} else {
if (query.id) {
if (referer) {
var from = path.join(process.cwd(),
path.dirname(url.parse(referer).pathname));
main = path.resolve(from, query.id + '.js');
}
}
}
return main;
}
});
callback(null, server);
});
};
/**
* Build the examples and exit on any error.
* @param {Function=} opt_callback Called when done building examples.
*/
function buildExamplesOrFatal(opt_callback) {
log.info('serve', 'Building examples.');
buildExamples(function(err) {
if (err) {
log.error('serve', 'Building examples failed.');
log.error('serve', err.message);
log.error('serve', 'Use "verbose" logging to see the full stack trace.');
log.verbose('serve', err.stack);
process.exit(1);
}
// This is awkward, but then so is CSS itself
var src = path.join(__dirname, '..', 'css', 'ol.css');
var dest = path.join(__dirname, '..', 'build', 'css', 'ol.css');
fs.copy(src, dest, function(err2) {
if (err2) {
log.error('serve', 'Failed to copy CSS.');
log.error('serve', err.message);
log.error('serve',
'Use "verbose" logging to see the full stack trace.');
log.verbose('serve', err.stack);
process.exit(1);
}
log.verbose('serve', 'Done building examples.');
if (opt_callback) {
opt_callback();
}
});
});
}
/**
* If running this module directly start the server.
*/
if (require.main === module) {
var options = nomnom.options({
port: {
abbr: 'p',
default: 3000,
help: 'Port for incoming connections',
metavar: 'PORT'
},
loglevel: {
abbr: 'l',
choices: ['silly', 'verbose', 'info', 'warn', 'error'],
default: 'info',
help: 'Log level',
metavar: 'LEVEL'
}
}).parse();
/** @type {string} */
log.level = options.loglevel;
buildExamplesOrFatal(function() {
log.info('serve', 'Parsing dependencies.');
createServer(function(err, server) {
if (err) {
log.error('serve', 'Parsing failed');
log.error('serve', err.message);
process.exit(1);
}
server.listen(options.port, function() {
log.info('serve', 'Listening on http://localhost:' +
options.port + '/ (Ctrl+C to stop)');
});
server.on('error', function(err) {
log.error('serve', 'Server failed to start: ' + err.message);
process.exit(1);
});
});
var gaze = new Gaze('examples/**/*');
var debouncedBuild = debounce(buildExamplesOrFatal, 250);
gaze.on('all', function(event, filepath) {
log.verbose('serve', 'Watch event: ' + event + ' ' + filepath);
debouncedBuild();
});
});
}

View File

@@ -1,102 +0,0 @@
const Server = require('karma').Server;
const closure = require('closure-util');
const path = require('path');
const processCliArgs = require('karma/lib/cli').process;
function insertDependencies(manager, files, previousLookup) {
previousLookup = previousLookup || {};
let firstIndex = NaN;
const original = files.filter((obj, index) => {
if (previousLookup[obj.pattern]) {
if (isNaN(firstIndex)) {
firstIndex = index;
}
return false;
} else {
return true;
}
});
if (isNaN(firstIndex)) {
firstIndex = 0;
}
const lookup = {};
const dependencies = manager.getDependencies().map(script => {
lookup[script.path] = true;
return {
pattern: script.path,
included: true,
served: true,
watched: false
};
});
original.splice.apply(original, [firstIndex, 0].concat(dependencies));
files.length = 0;
files.push.apply(files, original);
return lookup;
}
/**
* Start Karma. This prepends the Karma `files` config with all library files
* sorted in dependency order.
* @param {Object} config Karma options.
* @param {Manager} manager The dependency file manager.
* @param {function(Error)} callback Called with any error.
*/
function serve(config, manager, callback) {
function exit(code) {
let error = null;
if (code) {
error = new Error(`Karma exited with ${code}`);
error.code = code;
}
callback(error);
}
const server = new Server(config, exit);
const files = server.get('config.files');
let lookup = insertDependencies(manager, files);
// stop goog base.js from trying to load deps.js
files.unshift({
pattern: path.resolve(__dirname, '../test/no-deps.js'),
included: true,
served: true,
watched: false
});
manager.on('update', () => {
lookup = insertDependencies(manager, files, lookup);
server.refreshFiles();
});
server.start();
}
function main(config, callback) {
const manager = new closure.Manager({
lib: [
'src/**/*.js',
'build/ol.ext/*.js'
]
});
manager.on('error', callback);
manager.on('ready', () => {
serve(config, manager, callback);
});
}
if (require.main === module) {
const config = processCliArgs();
main(config, (err, manager) => {
if (err) {
process.stderr.write(err.message, () => process.exit(1));
return;
} else {
process.exit(0);
}
});
}