Merge pull request #7927 from tschaub/unused

Remove unused deps, unused tasks, and outdated info
This commit is contained in:
Tim Schaub
2018-03-04 17:00:59 -07:00
committed by GitHub
17 changed files with 8 additions and 1258 deletions

View File

@@ -1 +0,0 @@
/build/

View File

@@ -55,66 +55,6 @@ Your pull request must:
* Be possible to merge automatically.
### The `check` build target
It is strongly recommended that you run
$ make check
before every commit. This will catch many problems quickly, and it is much
faster than waiting for the Travis CI integration tests to run.
The `check` build target runs a number of quick tests on your code. These
include:
* Lint
* Compile
* Tests
### Follow OpenLayers's coding style
OpenLayers follows [Google's JavaScript Style
Guide](https://google.github.io/styleguide/javascriptguide.xml).
This is checked using [ESLint](http://eslint.org/), you
can run the linter locally on your machine before committing using the `lint`
target:
$ make lint
In addition to fixing problems identified by the linter, please also follow the
style of the existing OpenLayers code, which includes:
* Always wrap the body of `for`, `if`, and `while` statements in braces.
* Class methods should be in alphabetical order.
* `var` declarations should not span multiple lines. If you cannot fit all
the declarations in a single line, then start a new `var` declaration on a
new line. Within a single line, variables should be declared in
alphabetical order.
* Do not use assignments inside expressions.
* Use uppercase for `@const` variables.
### Configure your editor
If possible, configure your editor to follow the coding conventions of the
library. A `.editorconfig` file is included at the root of the repository that
can be used to configure whitespace and charset handling in your editor. See
that file for a description of the conventions. The [EditorConfig](
http://editorconfig.org/#download) site links to plugins for various editors.
### Pass the integration tests run automatically by the Travis CI system
The integration tests contain a number of automated checks to ensure that the
code follows the OpenLayers style and does not break tests or examples. You
can run the integration tests locally using the `ci` target:
$ make ci
### Address a single issue or add a single item of functionality
Please submit separate pull requests for separate issues. This allows each to
@@ -168,33 +108,3 @@ Occasionally other changes to `master` might mean that your pull request cannot
be merged automatically. In this case you may need to rebase your branch on a
more recent `master`, resolve any conflicts, and `git push --force` to update
your branch so that it can be merged automatically.
## Building on Windows
Most developers build on Linux. Building on Windows is possible under Cygwin.
When installing Cygwin from https://www.cygwin.com/, include the developer
tools to get GNU make.
First (before npm install), to avoid file permission problems between Windows
and Cygwin, edit Cygwin's /etc/fstab file to disable ACLs like this
`none /cygdrive cygdrive binary,noacl,posix=0,user 0 0`
Python is normally installed with Cygwin so need not be installed separately.
By default Cygwin will use its own version of Python rather than Window's,
so the Python modules should be installed for Cygwin's Python.
The build targets `check-deps`, `serve`, `lint`, `build`, `test`, `check` and
`host-examples` described above should all work. `host-examples` takes quite a
while to run. If a target does not run properly first time, try it again.
Currently, Firefox fails to run http://localhost:3000/build/examples
from make serve, but Chrome and Internet Explorer will.
Microsoft Visual Studio's javascript debugger may be used to debug the
build/hosted/your-branch/examples. It will be convenient to set
build/hosted/your-branch/examples/index.html as the startup page.
Your OpenLayers source tree need not be under the Cygwin root.
if you checkout to c:/openlayers then you can build under Cygwin at /cygdrive/c/openlayers .
However, keep the path to the OpenLayers files short otherwise you may see
`ENAMETOOLONG` errors.

View File

@@ -15,103 +15,32 @@ pull requests will not be merged.
The minimum requirements are:
* GNU Make
* Git
* [Node.js](http://nodejs.org/) (version 8 and above)
* Python 2.6 or 2.7
* Java 7 (JRE and JDK)
The executables `git`, `node`, and `java` should be in your `PATH`.
You can check your configuration by running:
$ make check-deps
The executables `git` and `node` should be in your `PATH`.
To install the Node.js dependencies run
$ npm install
## Working with the build tool
As an OpenLayers developer you will use `make` to run build targets defined in the
`Makefile` located at the root of the repository. The `Makefile` includes
targets for running the linter, the compiler, the tests, etc.
The usage of `make` is as follows:
$ make <target>
where `<target>` is the name of the build target you want to execute. For
example:
$ make test
The main build targets are `serve`, `lint`, `build`, `test`, and `check`. The
latter is a meta-target that basically runs `lint`, `build`, and `test`.
The `serve` target starts a node-based web server, which we will refer to as the *dev server*. You'll need to start that server for running the examples and the tests in a browser. More information on that further down.
Other targets include `apidoc` and `ci`. The latter is the target used on Travis CI. See OpenLayers's [Travis configuration file](https://github.com/openlayers/openlayers/blob/master/.travis.yml).
## Running the `check` target
The `check` target is to be run before pushing code to GitHub and opening pull
requests. Branches that don't pass `check` won't pass the integration tests,
and have therefore no chance of being merged into `master`.
To run the `check` target:
$ make check
If you want to run the full suite of integration tests, see "Running the integration
tests" below.
## Running examples
To run the examples you first need to start the dev server:
$ make serve
$ npm run serve-examples
Then, just point your browser <http://localhost:3000/build/examples> in your browser. For example <http://localhost:3000/build/examples/side-by-side.html>.
Run examples against the `ol.js` standalone build:
The examples can also be run against the `ol.js` standalone build, just like
the examples [hosted](https://openlayers.org/en/master/examples/) on GitHub.
Start by executing the `host-examples` build target:
$ make host-examples
After running `host-examples` you can now open the examples index page in the browser: <http://localhost:3000/build/hosted/master/examples/>. (This assumes that you still have the dev server running.)
Append `?mode=raw` to make the example work in full debug mode. In raw mode the OpenLayers and Closure Library scripts are loaded individually by the Closure Library's `base.js` script (which the example page loads and executes before any other script).
Then, load <http://localhost:5000/> in your browser.
## Running tests
To run the tests in a browser start the dev server (`make serve`) and open <http://localhost:3000/test/index.html> in the browser.
To run the tests once:
To run the tests on the console (headless testing with PhantomJS) use the `test` target:
$ npm test
$ make test
To run the tests continuously during development:
See also the test-specific [README](../master/test/README.md).
## Running the integration tests
When you submit a pull request the [Travis continuous integration
server](https://travis-ci.org/) will run a full suite of tests, including
building all versions of the library and checking that all of the examples
work. You will receive an email with the results, and the status will be
displayed in the pull request.
To run the full suite of integration tests use the `ci` target:
$ make ci
Running the full suite of integration tests currently takes 5-10 minutes.
This makes sure that your commit won't break the build. It also runs JSDoc3 to
make sure that there are no invalid API doc directives.
$ npm run karma
## Adding examples
@@ -123,14 +52,3 @@ implies creating two or three files in this directory, an `.html` file, a `.js`
file, and, optionally, a `.css` file.
You can use `simple.js` and `simple.html` as templates for new examples.
### Use of the `goog` namespace in examples
Short story: the OpenLayers examples should not use the `goog` namespace, except
for `goog.require`.
Longer story: we want that the OpenLayers examples work in multiple modes, with the
standalone lib (which has implications of the symbols and properties we
export), and compiled together with the OpenLayers library.
Compiling the examples together with the library makes it mandatory to declare dependencies with `goog.require` statements.

View File

@@ -1,45 +0,0 @@
{
"exports": [],
"src": [
"src/**/*.js",
"build/ol.ext/*.js",
"build/examples/{{id}}.js"
],
"compile": {
"js": [
"externs/olx.js",
"externs/oli.js"
],
"externs": [
"externs/bingmaps.js",
"externs/cartodb.js",
"externs/bootstrap.js",
"externs/closure-compiler.js",
"externs/esrijson.js",
"externs/example.js",
"externs/geojson.js",
"externs/jquery-1.9.js",
"externs/proj4js.js",
"externs/tilejson.js",
"externs/topojson.js"
],
"jscomp_error": [
"*"
],
"jscomp_off": [
"lintChecks",
"analyzerChecks",
"missingProvide",
"unknownDefines"
],
"extra_annotation_name": [
"api", "observable"
],
"rewrite_polyfills": "false",
"compilation_level": "ADVANCED",
"warning_level": "VERBOSE",
"output_wrapper": "(function(){%output%})();",
"use_types_for_optimization": true,
"manage_closure_dependencies": true
}
}

View File

@@ -1,45 +0,0 @@
{
"exports": [],
"src": [
"src/**/*.js",
"build/ol.ext/*.js",
"build/compiled-examples/all.js"
],
"compile": {
"js": [
"externs/olx.js",
"externs/oli.js"
],
"externs": [
"externs/bingmaps.js",
"externs/bootstrap.js",
"externs/cartodb.js",
"externs/closure-compiler.js",
"externs/esrijson.js",
"externs/example.js",
"externs/geojson.js",
"externs/jquery-1.9.js",
"externs/proj4js.js",
"externs/tilejson.js",
"externs/topojson.js"
],
"jscomp_error": [
"*"
],
"jscomp_off": [
"lintChecks",
"analyzerChecks",
"unusedLocalVariables"
],
"extra_annotation_name": [
"api", "observable"
],
"rewrite_polyfills": "false",
"compilation_level": "ADVANCED",
"warning_level": "VERBOSE",
"output_wrapper": "(function(){%output%})();",
"use_types_for_optimization": true,
"manage_closure_dependencies": true
}
}

View File

@@ -1,4 +0,0 @@
{
"exports": ["*"],
"umd": true
}

View File

@@ -1,38 +0,0 @@
{
"exports": ["*"],
"umd": true,
"compile": {
"externs": [
"externs/bingmaps.js",
"externs/cartodb.js",
"externs/closure-compiler.js",
"externs/esrijson.js",
"externs/geojson.js",
"externs/oli.js",
"externs/olx.js",
"externs/proj4js.js",
"externs/tilejson.js",
"externs/topojson.js"
],
"define": [
"ol.DEBUG_WEBGL=false"
],
"jscomp_error": [
"*"
],
"jscomp_off": [
"lintChecks",
"analyzerChecks"
],
"extra_annotation_name": [
"api", "observable"
],
"rewrite_polyfills": "false",
"compilation_level": "ADVANCED",
"warning_level": "VERBOSE",
"use_types_for_optimization": true,
"manage_closure_dependencies": true,
"create_source_map": "build/ol.js.map",
"source_map_format": "V3"
}
}

View File

@@ -1,3 +0,0 @@
# Configuration Files
This directory includes configuration files for the build scripts in and documentation templates.

View File

@@ -9,7 +9,7 @@
],
"homepage": "https://openlayers.org/",
"scripts": {
"lint": "eslint tasks test src/ol examples transforms",
"lint": "eslint tasks test src/ol examples",
"pretest": "npm run lint",
"posttest": "npm run typecheck",
"test": "npm run karma -- --single-run",
@@ -61,7 +61,6 @@
"html-webpack-plugin": "^3.0.1",
"istanbul": "0.4.5",
"jquery": "3.3.1",
"jscodeshift": "^0.4.0",
"jsdoc": "3.5.5",
"karma": "^2.0.0",
"karma-chrome-launcher": "2.2.0",
@@ -82,7 +81,6 @@
"url-polyfill": "^1.0.7",
"walk": "^2.3.9",
"webpack": "3.11.0",
"webpack-dev-server": "2.11.1",
"webpack-merge": "4.1.2"
},
"eslintConfig": {

View File

@@ -1,5 +0,0 @@
{
"parserOptions": {
"sourceType": "module"
}
}

View File

@@ -1,23 +0,0 @@
{
"name": "ol",
"version": "4.6.4",
"description": "OpenLayers as ES2015 modules",
"main": "index.js",
"module": "index.js",
"license": "BSD-2-Clause",
"dependencies": {
"pbf": "3.1.0",
"pixelworks": "1.1.0",
"rbush": "2.0.1"
},
"browserify": {
"transform": [
[
"babelify",
{
"plugins": ["transform-es2015-modules-commonjs"]
}
]
]
}
}

View File

@@ -1,49 +0,0 @@
# ol
OpenLayers as ES2015 modules.
## Usage
Add the `ol` package as a dependency to your project.
npm install ol --save
Import just what you need for your application:
```js
import Map from 'ol/map';
import View from 'ol/view';
import TileLayer from 'ol/layer/tile';
import XYZ from 'ol/source/xyz';
new Map({
target: 'map',
layers: [
new TileLayer({
source: new XYZ({
url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png'
})
})
],
view: new View({
center: [0, 0],
zoom: 2
})
});
```
See the following examples for more detail on bundling OpenLayers with your application:
* Using [Rollup & Uglify](https://gist.github.com/tschaub/8beb328ea72b36446fc2198d008287de)
* Using [Rollup & Closure Compiler](https://gist.github.com/tschaub/32a5692bedac5254da24fa3b12072f35)
* Using [Webpack & Uglify](https://gist.github.com/tschaub/79025aef325cd2837364400a105405b8)
* Using [Webpack & Closure Compiler](https://gist.github.com/ahocevar/8ceafc6293455ba491dd9be12c15761f)
* Using [Browserify & Uglify](https://gist.github.com/tschaub/4bfb209a8f809823f1495b2e4436018e)
## Module Identifiers
The module identifiers above (e.g. `ol/map`) are like the `ol.Map` names in the [API documentation](http://openlayers.org/en/latest/apidoc/) with `/` instead of `.` and all lowercase. Each module only has a `default` export (there are no other named exports).
Constructors are exported from dedicated modules. For example, the `ol/layer/tile` module exports the `Tile` layer constructor.
Utility functions are available as properties of the default export from utility modules. For example, the `getCenter` function is a property of the default export from the `ol/extent` utility module.

View File

@@ -1,243 +0,0 @@
const fs = require('fs-extra');
const async = require('async');
const nomnom = require('nomnom');
const generateInfo = require('./generate-info');
/**
* Get the configuration from the config file. If configPath is provided
* it is assumed to be a JSON file with an 'exports' member that is a list
* of symbol names or patterns.
*
* @param {string} configPath Path to config file.
* @param {function(Error, Object)} callback Called with config object.
*/
function getConfig(configPath, callback) {
if (configPath) {
fs.readFile(configPath, function(err, data) {
if (err) {
callback(err);
return;
}
let obj;
try {
obj = JSON.parse(String(data));
} catch (err2) {
callback(new Error('Trouble parsing file as JSON: ' + configPath));
return;
}
const patterns = obj.exports;
if (patterns && !Array.isArray(patterns)) {
callback(new Error('Expected an exports array, got: ' + patterns));
return;
}
const namespace = obj.namespace;
if (namespace && typeof namespace !== 'string') {
callback(new Error('Expected an namespace string, got: ' +
namespace));
return;
}
callback(null, obj);
});
} else {
process.nextTick(function() {
callback(null, {exports: ['*']});
});
}
}
/**
* Read the symbols from info file.
* @param {Array.<string>} patterns List of patterns to pass along.
* @param {function(Error, Array.<string>, Array.<Object>)} callback Called
* with the patterns and symbols (or any error).
*/
function getSymbols(patterns, callback) {
generateInfo(function(err) {
if (err) {
callback(new Error('Trouble generating info: ' + err.message));
return;
}
const symbols = require('../build/info.json').symbols;
callback(null, patterns, symbols);
});
}
/**
* Generate a list of symbol names given a list of patterns. Patterns may
* include a * wildcard at the end of the string, in which case all symbol names
* that start with the preceding string will be matched (e.g 'foo.Bar#*' will
* match all symbol names that start with 'foo.Bar#').
*
* @param {Array.<string>} patterns A list of symbol names to match. Wildcards
* at the end of a string will match multiple names.
* @param {Array.<Object>} symbols List of symbols.
* @param {function(Error, Array.<Object>, Array.<string>)} callback Called with
* the filtered list of symbols and a list of all provides (or any error).
*/
function filterSymbols(patterns, symbols, callback) {
const matches = [];
const provides = {};
const lookup = {};
symbols.forEach(function(symbol) {
lookup[symbol.name] = symbol;
symbol.provides.forEach(function(provide) {
provides[provide] = true;
});
});
patterns.forEach(function(name) {
let match = false;
const pattern = (name.substr(-1) === '*');
if (pattern) {
name = name.substr(0, name.length - 1);
symbols.forEach(function(symbol) {
if (symbol.name.indexOf(name) === 0) {
matches.push(symbol);
match = true;
}
});
} else {
const symbol = lookup[name];
if (symbol) {
matches.push(symbol);
match = true;
}
}
if (!match) {
const message = 'No matching symbol found: ' + name + (pattern ? '*' : '');
callback(new Error(message));
}
});
callback(null, matches, Object.keys(provides).sort());
}
/**
* Generate goog code to export a named symbol.
* @param {string} name Symbol name.
* @param {string|undefined} namespace Target object for exported
* symbols.
* @return {string} Export code.
*/
function formatSymbolExport(name, namespace) {
return 'goog.exportSymbol(\n' +
' \'' + name + '\',\n' +
' ' + name +
(namespace ? ',\n ' + namespace : '') + ');\n';
}
/**
* Generate goog code to export a property.
* @param {string} name Property long name (e.g. foo.Bar#baz).
* @return {string} Export code.
*/
function formatPropertyExport(name) {
const parts = name.split('#');
const prototype = parts[0] + '.prototype';
const property = parts[1];
return 'goog.exportProperty(\n' +
' ' + prototype + ',\n' +
' \'' + property + '\',\n' +
' ' + prototype + '.' + property + ');\n';
}
/**
* Generate export code given a list symbol names.
* @param {Array.<Object>} symbols List of symbols.
* @param {string|undefined} namespace Target object for exported symbols.
* @param {Array.<string>} provides List of all provides.
* @return {string} Export code.
*/
function generateExports(symbols, namespace, provides) {
const blocks = [];
provides.forEach(function(provide) {
blocks.push('goog.require(\'' + provide + '\');');
});
blocks.push('\n\n');
symbols.forEach(function(symbol) {
const name = symbol.name;
if (name.indexOf('#') > 0) {
blocks.push(formatPropertyExport(name));
} else {
blocks.push(formatSymbolExport(name, namespace));
}
});
blocks.unshift(
'/**\n' +
' * @fileoverview Custom exports file.\n' +
' * @suppress {checkVars,extraRequire}\n' +
' */\n');
return blocks.join('\n');
}
/**
* Generate the exports code.
*
* @param {Object} config Config object with exports and (optional) namespace.
* @param {function(Error, string)} callback Called with the exports code or any
* error generating it.
*/
function main(config, callback) {
async.waterfall([
getSymbols.bind(null, config.exports),
filterSymbols,
function(symbols, provides, done) {
let code, err;
try {
code = generateExports(symbols, config.namespace, provides);
} catch (e) {
err = e;
}
done(err, code);
}
], callback);
}
/**
* If running this module directly, read the config file, call the main
* function, and write the output file.
*/
if (require.main === module) {
const options = nomnom.options({
output: {
position: 0,
required: true,
help: 'Output file path'
},
config: {
abbr: 'c',
help: 'Path to JSON config file',
metavar: 'CONFIG'
}
}).parse();
async.waterfall([
getConfig.bind(null, options.config),
main,
fs.outputFile.bind(fs, options.output)
], function(err) {
if (err) {
process.stderr.write(err.message + '\n');
process.exit(1);
} else {
process.exit(0);
}
});
}
/**
* Export main function.
*/
module.exports = main;

View File

@@ -1,228 +0,0 @@
const async = require('async');
const fs = require('fs-extra');
const nomnom = require('nomnom');
const generateInfo = require('./generate-info');
const googRegEx = /^goog\..*$/;
/**
* Read the symbols from info file.
* @param {function(Error, Array.<string>, Array.<Object>)} callback Called
* with the patterns and symbols (or any error).
*/
function getInfo(callback) {
generateInfo(function(err) {
if (err) {
callback(new Error('Trouble generating info: ' + err.message));
return;
}
const info = require('../build/info.json');
callback(null, info.typedefs, info.symbols, info.externs, info.base);
});
}
/**
* Generate externs code given a list symbols.
* @param {Array.<Object>} typedefs List of typedefs.
* @param {Array.<Object>} symbols List of symbols.
* @param {Array.<Object>} externs List of externs.
* @param {Array.<Object>} base List of base.
* @param {string|undefined} namespace Target object for exported symbols.
* @return {string} Export code.
*/
function generateExterns(typedefs, symbols, externs, base) {
const lines = [];
const processedSymbols = {};
const constructors = {};
const constructorOptionsTypes = {};
function addNamespaces(name) {
const parts = name.split('.');
parts.pop();
const namespace = [];
parts.forEach(function(part) {
namespace.push(part);
const partialNamespace = namespace.join('.');
if (!(partialNamespace in processedSymbols ||
partialNamespace in constructors)) {
lines.push('/**');
lines.push(' * @type {Object}');
lines.push(' */');
lines.push(nameToJS(partialNamespace) + ';');
lines.push('\n');
}
});
}
function nameToJS(name) {
processedSymbols[name] = true;
if (name.indexOf('.') === -1) {
name = 'var ' + name;
}
return name;
}
// Store in "constructorOptionsTypes" type names that start
// with "ol." and end with "Options".
function findConstructorOptionsTypes(types) {
types.forEach(function(type) {
if (type.match(/^ol\..*Options$/)) {
constructorOptionsTypes[type] = true;
}
});
}
function processSymbol(symbol) {
addNamespaces(symbol.name.split('#')[0]);
let name = symbol.name;
if (name.indexOf('#') > 0) {
name = symbol.name.replace('#', '.prototype.');
const constructor = symbol.name.split('#')[0];
if (!(constructor in constructors)) {
constructors[constructor] = true;
lines.push('/**');
lines.push(' * @constructor');
lines.push(' */');
lines.push(nameToJS(constructor) + ' = function() {};');
lines.push('\n');
}
}
lines.push('/**');
if (symbol.kind === 'class') {
constructors[name] = true;
lines.push(' * @constructor');
if (symbol.extends && !googRegEx.test(symbol.extends)) {
lines.push(' * @extends {' + symbol.extends + '}');
}
}
if (symbol.types) {
lines.push(' * @type {' + symbol.types.join('|') + '}');
}
const args = [];
if (symbol.params) {
symbol.params.forEach(function(param) {
findConstructorOptionsTypes(param.types);
args.push(param.name);
lines.push(' * @param {' +
(param.variable ? '...' : '') +
param.types.join('|') +
(param.optional ? '=' : '') + (param.nullable ? '!' : '') +
'} ' + param.name);
});
}
if (symbol.returns) {
lines.push(' * @return {' +
(symbol.returns.nullable ? '!' : '') +
symbol.returns.types.join('|') + '}');
}
if (symbol.template) {
lines.push(' * @template ' + symbol.template);
}
lines.push(' */');
if (symbol.kind === 'function' || symbol.kind === 'class') {
lines.push(nameToJS(name) + ' = function(' + args.join(', ') + ') {};');
} else {
lines.push(nameToJS(name) + ';');
}
lines.push('\n');
}
externs.forEach(processSymbol);
base.forEach(processSymbol);
symbols.forEach(processSymbol);
typedefs.forEach(function(typedef) {
// we're about to add a @typedef for "typedef.name" so remove that
// type from constructorOptionsTypes
delete constructorOptionsTypes[typedef.name];
addNamespaces(typedef.name);
lines.push('/**');
lines.push(' * @typedef {' + typedef.types.join('|') + '}');
lines.push(' */');
lines.push(nameToJS(typedef.name) + ';');
lines.push('\n');
});
// At this point constructorOptionsTypes includes options types for which we
// did not have a @typedef yet. For those we add @typedef {Object}.
//
// This is used for abstract base classes. Abstract base classes should be
// defined as types in the ol externs file. But the corresponding @typedef's
// are not marked with an @api annotation because abstract base classes are
// not instantiated by applications. Yet, we need to have a type defined
// in the ol externs file for these options types. So we just use
// @typedef {Object}.
Object.keys(constructorOptionsTypes).forEach(function(key) {
lines.push('/**');
lines.push(' * No `@api` annotation for `' + key + '`, use `Object`.');
lines.push(' * @typedef {Object}');
lines.push(' */');
lines.push(nameToJS(key) + ';');
lines.push('\n');
});
return lines.join('\n');
}
/**
* Generate the exports code.
*
* @param {function(Error, string)} callback Called with the exports code or any
* error generating it.
*/
function main(callback) {
async.waterfall([
getInfo,
function(typedefs, symbols, externs, base, done) {
let code, err;
try {
code = generateExterns(typedefs, symbols, externs, base);
} catch (e) {
err = e;
}
done(err, code);
}
], callback);
}
/**
* If running this module directly, read the config file, call the main
* function, and write the output file.
*/
if (require.main === module) {
const options = nomnom.options({
output: {
position: 0,
required: true,
help: 'Output path for the generated externs file.'
}
}).parse();
async.waterfall([
main,
fs.outputFile.bind(fs, options.output)
], function(err) {
if (err) {
process.stderr.write(err.message + '\n');
process.exit(1);
} else {
process.exit(0);
}
});
}
/**
* Export main function.
*/
module.exports = main;

View File

@@ -1,111 +0,0 @@
# Tasks
This directory contains utility scripts for working with the library.
## `build.js`
Builds the library based on a configuration file. See the `--help` option for more detail.
node tasks/build.js --help
### Build configuration files
Build configuration files are JSON files that are used to determine what should be exported from the library and what options should be passed to the compiler.
**Required configuration properties**
* **exports** - `Array.<string>` An array of symbol names or patterns to be exported (names that are used in your application). For example, including `"ol.Map"` will export the map namespace including the constructor. Method names are prefixed with `#`. So `"ol.Map#getViewport"` will export the map's `getViewport` method. You can use a `*` at the end to match multiple names. The pattern `"ol.Map#*"` will export all exportable map methods.
Note that only the 'exportable' names can be listed here, that is, those that are part of the supported API (see apidoc/readme.md for more details). If you want to include a property or method that is not part of the API (and be aware that these may change or be removed), you will have to specifically export these yourself, for example, with `goog.exportProperty`.
Note too that the supplied observable properties together with their accessors, like `getView` in `ol.Map`, are always exported (with `goog.exportProperty` in the source). You do not have to include these, though it does not harm if you do.
Finally, although the term 'exports' is not relevant for simple and whitespace builds, you should still list the names you use as you would with advanced. A build will be created with those classes/namespaces that contain these exported methods.
**Optional configuration properties**
* **compile** - `Object` An object whose properties are [Closure Compiler options](https://github.com/openlayers/closure-util/blob/master/compiler-options.txt). Property names match the option names without the `--` prefix (e.g. `"compilation_level": "ADVANCED"` would set the `--compilation_level` option). Where an option can be specified multiple times, use an array for the value (e.g. `"externs": ["one.js", "two.js"]`). Where an option is used as a flag, use a boolean value (e.g. `"use_types_for_optimization": true`).
If the **compile** object is not provided, the build task will generate a "debug" build of the library without any variable naming or other minification. This is suitable for development or debugging purposes, but should not be used in production.
* **umd** - `boolean` Optional flag to wrap the build in [UMD syntax](https://github.com/umdjs/umd). If set to `true`, the build output can be used with a CommonJS module loader (e.g. [Browserify](http://browserify.org/)), an AMD script loader (e.g. [RequireJS](http://requirejs.org/)), or just loaded with a `<script>` tag. If this option is specified, the **namespace** and any **compile.output_wrapper** options will be ignored.
* **src** - `Array.<string>` Optional array of [path patterns](https://github.com/isaacs/minimatch/blob/master/README.md) for source files, that is, those that provide the symbols/names included in `exports`. By default, all of the library source files will be included (`'src/**/*.js'`). If you want to provide additional source files to be configured together with the library, you need to provide path patterns to your source files *and* the library source files. Note that these patterns are `/` delimited even on Windows. There is a bit of special handling with the `src` config.
* **cwd** - `string` Optional path to be used as the current working directory. All paths in the `compile` object are assumed to be relative to `cwd`. Default is the root of the OpenLayers repository.
* **namespace** - `string` Optional namespace for exporting the `ol` object. By default, `ol` is assigned to the global object.
* **jvm** - `Array.<string>` Optional array of [command line options](https://github.com/google/closure-compiler/wiki/FAQ#what-are-the-recommended-java-vm-command-line-options) for the compiler. By default, the Compiler is run with `['-server', '-XX:+TieredCompilation']`.
The build task generates a list of source files sorted in dependency order and passes these to the compiler. This takes the place of the `--js` options that you would use when calling the compiler directly. If you want to add additional source files, typically you would use the `src` array described above. This works with sources that have `goog.require` and/or `goog.provide` calls (which are used to sort dependencies). If you want to force the inclusion of files that don't use `goog.require` or `goog.provide`, you can use the `js` property of the `compile` object. Paths in the `js` array will be passed to the compiler **after** all other source files. Note that there is currently no facility for adding files to the build file after compilation; you will have to do this yourself if you want this.
Paths in your config file should be relative to the current working directory (when you call `node tasks/build.js`). Note that this means paths are not necessarily relative to the config file itself.
Below is a complete `build.json` configuration file that would generate a 'full' build including every exportable symbol in the library (much more than you'd ever need).
```json
{
"exports": ["*"],
"compile": {
"externs": [
"externs/bingmaps.js",
"externs/geojson.js",
"externs/oli.js",
"externs/olx.js",
"externs/proj4js.js",
"externs/tilejson.js",
"externs/topojson.js"
],
"compilation_level": "ADVANCED",
"output_wrapper": "(function(){%output%})();",
"use_types_for_optimization": true,
"manage_closure_dependencies": true
}
}
```
To generate a build named `ol.min.js` with the `build.json`, you would run this:
node tasks/build.js build.json ol.min.js
To export the `ol` symbol to somewhere other than the global namespace, a `namespace` option is available. This can e.g. be useful for creating an OpenLayers AMD module, by simply providing a build configuration like the following:
```json
{
"exports": ["*"],
"namespace": "AMD",
"compile": {
"compilation_level": "ADVANCED",
"output_wrapper": "define('ol',function(){var AMD={};%output%return AMD.ol;});"
}
}
```
The `defines` section of `build.json` above lists common settings for the Closure library in production code. The OpenLayers library also defines constants that can be set in this section at compile time. These are all defined in the `ol.js` source file; see the comments in this file to see what effect setting these would have. Some of them can reduce the size of the build in advanced mode.
## `generate-exports.js`
Called internally to generate a `build/exports.js` file optionally with a limited set of exports.
## `generate-externs.js`
Can be called to generate a Closure externs file for the full OpenLayers API.
See the `--help` option for more detail.
node tasks/generate-externs.js --help
This is useful for projects that use the Closure Compiler to build, but want to use OpenLayers as external library rather than building together with OpenLayers.
## `generate-info.js`
Called internally to parse the library for annotations and write out a `build/info.json` file.
## `build-examples.js`
Builds examples and the example index.
## `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,6 +0,0 @@
{
"env": {
"node": true,
"es6": true
}
}

View File

@@ -1,275 +0,0 @@
const parentPackage = require('../package.json');
const thisPackage = require('../package/package.json');
const defines = {
// Compiler defines go here, e.g.
// 'ol.ENABLE_WEBGL': false
};
function rename(name) {
const parts = name.split('.');
return `_${parts.join('_')}_`;
}
function resolve(fromName, toName) {
const fromParts = fromName.split('.');
const toParts = toName.split('.');
if (toParts[0] === 'ol' && toParts[1] === 'ext') {
const name = toParts[2];
let packageName;
let imported;
for (let i = 0, ii = parentPackage.ext.length; i < ii; ++i) {
const dependency = parentPackage.ext[i];
imported = dependency.import;
if (dependency.module === name || dependency.name === name) {
packageName = dependency.module;
// ensure dependency is listed on both package.json
if (
!thisPackage.dependencies[packageName] ||
thisPackage.dependencies[packageName] !== parentPackage.dependencies[packageName]
) {
throw new Error(`Package ${packageName} must appear in all package.json at the same version`);
}
break;
}
}
if (!packageName) {
throw new Error(`Can't find package name for ${toName}`);
}
if (imported) {
return [packageName, imported];
} else {
return packageName;
}
}
if (fromParts[0] === 'examples' || fromParts[0] === 'test') {
fromParts.unshift('root');
toParts.unshift('root', 'src');
}
const fromLength = fromParts.length;
let commonDepth = 1;
while (commonDepth < fromLength - 2) {
if (fromParts[commonDepth] === toParts[commonDepth]) {
++commonDepth;
} else {
break;
}
}
const back = new Array(fromLength - commonDepth).join('../') || './';
let relative = back + toParts.slice(commonDepth).join('/');
if (relative.endsWith('/')) {
relative += 'index';
}
return relative + '.js';
}
function getUnprovided(path) {
path = path.replace(/\.(test\.)?js$/, '');
const parts = path.split('/');
return parts.join('.');
}
function getGoogExpressionStatement(identifier) {
return {
type: 'ExpressionStatement',
expression: {
type: 'CallExpression',
callee: {
type: 'MemberExpression',
object: {
type: 'Identifier',
name: 'goog'
},
property: {
type: 'Identifier',
name: identifier
}
}
}
};
}
const defineMemberExpression = {
type: 'MemberExpression',
object: {
type: 'Identifier',
name: 'ol'
},
property: {
type: 'Identifier'
}
};
function getMemberExpression(name) {
function memberExpression(parts) {
const dotIndex = parts.lastIndexOf('.');
if (dotIndex > 0) {
return {
type: 'MemberExpression',
object: memberExpression(parts.slice(0, dotIndex)),
property: {
type: 'Identifier',
name: parts.slice(dotIndex + 1)
}
};
} else {
return {
type: 'Identifier',
name: parts
};
}
}
return memberExpression(name);
}
function getMemberExpressionAssignment(name) {
return {
type: 'ExpressionStatement',
expression: {
type: 'AssignmentExpression',
left: getMemberExpression(name)
}
};
}
module.exports = function(info, api) {
const j = api.jscodeshift;
const root = j(info.source);
// store any initial comments
const {comments} = root.find(j.Program).get('body', 0).node;
// replace `ol.VERSION = ''` with correct version
root.find(j.ExpressionStatement, getMemberExpressionAssignment('ol.VERSION'))
.forEach(path => {
path.value.expression.right = j.literal('v' + thisPackage.version);
});
const replacements = {};
// replace all uses of defines
root.find(j.MemberExpression, defineMemberExpression)
.filter(path => {
const node = path.value;
const name = `${node.object.name}.${node.property.name}`;
return (name in defines) && path.parentPath.value.type !== 'AssignmentExpression';
})
.replaceWith(path => {
const name = `${path.value.object.name}.${path.value.property.name}`;
const expression = j.literal(defines[name]);
expression.comments = path.value.comments;
return expression;
});
// remove goog.provide()
let provide, unprovided;
root.find(j.ExpressionStatement, getGoogExpressionStatement('provide'))
.forEach(path => {
if (provide) {
throw new Error(`Multiple provides in ${info.path}`);
}
provide = path.value.expression.arguments[0].value;
if (provide.indexOf(' ') > -1) {
throw new Error(`Space in provide "${provide}" in ${info.path}`);
}
}).remove();
if (provide) {
replacements[provide] = rename(provide);
// replace provide assignment with variable declarator
// e.g. `ol.foo.Bar = function() {}` -> `var _ol_foo_Bar_ = function() {}`
let declaredProvide = false;
root.find(j.ExpressionStatement, getMemberExpressionAssignment(provide))
.replaceWith(path => {
declaredProvide = true;
const statement = j.variableDeclaration('var', [
j.variableDeclarator(j.identifier(rename(provide)), path.value.expression.right)
]);
statement.comments = path.value.comments;
return statement;
});
if (!declaredProvide) {
const body = root.find(j.Program).get('body');
body.unshift(
j.variableDeclaration('var', [
j.variableDeclarator(j.identifier(rename(provide)), j.objectExpression([]))
])
);
}
} else {
unprovided = getUnprovided(info.path);
}
// replace `goog.require('foo')` with `import foo from 'foo'`
const imports = [];
root.find(j.ExpressionStatement, getGoogExpressionStatement('require'))
.forEach(path => {
const name = path.value.expression.arguments[0].value;
if (name in replacements) {
throw new Error(`Duplicate require found in ${info.path}: ${name}`);
}
const renamed = rename(name);
replacements[name] = renamed;
const resolved = resolve(provide || unprovided, name);
let specifier, source;
if (Array.isArray(resolved)) {
// import {imported as renamed} from 'source';
specifier = j.importSpecifier(j.identifier(resolved[1]), j.identifier(renamed));
source = resolved[0];
} else {
// import renamed from 'source';
specifier = j.importDefaultSpecifier(j.identifier(renamed));
source = resolved;
}
imports.push(j.importDeclaration([specifier], j.literal(source)));
})
.remove();
const body = root.find(j.Program).get('body');
body.unshift.apply(body, imports);
// replace all uses of required or provided names with renamed identifiers
Object.keys(replacements).sort().reverse().forEach(name => {
if (name.indexOf('.') > 0) {
root.find(j.MemberExpression, getMemberExpression(name))
.replaceWith(path => {
const expression = j.identifier(replacements[name]);
expression.comments = path.value.comments;
return expression;
});
} else {
root.find(j.Identifier, {name: name})
.replaceWith(path => {
const identifier = j.identifier(replacements[name]);
identifier.comments = path.value.comments;
return identifier;
});
}
});
// add export declaration
if (provide) {
root.find(j.Program).get('body').push(
j.exportDefaultDeclaration(j.identifier(rename(provide)))
);
}
// replace any initial comments
root.get().node.comments = comments;
// add @module annotation for src modules
if (info.path.startsWith('src')) {
const name = info.path.replace(/^src\//, '').replace(/\.js$/, '');
const comment = j.commentBlock(`*\n * @module ${name}\n `);
const node = root.get().node;
if (!node.comments) {
node.comments = [comment];
} else {
node.comments.unshift(comment);
}
}
return root.toSource({quote: 'single'});
};