From 386f94e0d4cec45791b586f30961e781ad519564 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sat, 17 Dec 2016 23:06:29 -0700 Subject: [PATCH 01/14] Codemod for CommonJS package --- Makefile | 10 ++++ package.json | 1 + package/package.json | 7 +++ transforms/.eslintrc | 6 ++ transforms/common.js | 134 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 158 insertions(+) create mode 100644 package/package.json create mode 100644 transforms/.eslintrc create mode 100644 transforms/common.js diff --git a/Makefile b/Makefile index bc4332d56a..c194bd0ee5 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,7 @@ clean: rm -f build/test_rendering_requires.js rm -rf build/examples rm -rf build/compiled-examples + rm -rf build/package rm -rf $(BUILD_HOSTED) .PHONY: cleanall @@ -300,3 +301,12 @@ build/test_rendering_requires.js: $(SPEC_RENDERING_JS) %shader.js: %shader.glsl src/ol/webgl/shader.mustache bin/pyglslunit.py build/timestamps/node-modules-timestamp @python bin/pyglslunit.py --input $< | ./node_modules/.bin/mustache - src/ol/webgl/shader.mustache > $@ + +.PHONY: package +package: build/timestamps/node-modules-timestamp + @rm -rf build/package + @mkdir -p build + @cp -r package build + @cd ./src && cp -r ol/* ../build/package + @rm build/package/typedefs.js + ./node_modules/.bin/jscodeshift --transform transforms/common.js build/package diff --git a/package.json b/package.json index 679c47a0c8..e17a60c5ce 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "gaze": "^1.0.0", "istanbul": "0.4.5", "jquery": "3.1.1", + "jscodeshift": "^0.3.30", "mocha": "3.2.0", "mocha-phantomjs-core": "^2.1.0", "mustache": "2.3.0", diff --git a/package/package.json b/package/package.json new file mode 100644 index 0000000000..e9bc8208d7 --- /dev/null +++ b/package/package.json @@ -0,0 +1,7 @@ +{ + "name": "ol", + "version": "3.20.0-beta.1", + "description": "OpenLayers", + "main": "index.js", + "license": "BSD-2-Clause" +} diff --git a/transforms/.eslintrc b/transforms/.eslintrc new file mode 100644 index 0000000000..13e216f583 --- /dev/null +++ b/transforms/.eslintrc @@ -0,0 +1,6 @@ +{ + "env": { + "node": true, + "es6": true + } +} diff --git a/transforms/common.js b/transforms/common.js new file mode 100644 index 0000000000..5cc4dab91d --- /dev/null +++ b/transforms/common.js @@ -0,0 +1,134 @@ +function rename(name) { + const parts = name.split('.'); + return `_${parts.join('_')}_`; +} + +function resolve(fromName, toName) { + const fromParts = fromName.split('.'); + const toParts = toName.split('.'); + var commonDepth = 1; + var fromLength = fromParts.length; + while (commonDepth < fromLength - 1) { + if (fromParts[commonDepth] === toParts[commonDepth]) { + ++commonDepth; + } else { + break; + } + } + + var back = new Array(fromLength - commonDepth).join('../') || './'; + return back + toParts.slice(commonDepth).join('/').toLowerCase(); +} + +function getGoogExpressionStatement(identifier) { + return { + type: 'ExpressionStatement', + expression: { + type: 'CallExpression', + callee: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'goog' + }, + property: { + type: 'Identifier', + name: 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); +} + +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 goog.provide() + let provide; + root.find(j.ExpressionStatement, getGoogExpressionStatement('provide')) + .replaceWith(path => { + if (provide) { + throw new Error(`Multiple provides in ${info.path}`); + } + provide = path.value.expression.arguments[0].value; + return j.variableDeclaration('var', [ + j.variableDeclarator(j.identifier(rename(provide)), j.objectExpression([])) + ]); + }); + + if (!provide) { + throw new Error(`No provide found in ${info.path}`); + } + + // replace all uses of provided name with renamed identifier + root.find(j.MemberExpression, getMemberExpression(provide)) + .replaceWith(j.identifier(rename(provide))); + + // replace goog.require() + const requires = {}; + root.find(j.ExpressionStatement, getGoogExpressionStatement('require')) + .replaceWith(path => { + const name = path.value.expression.arguments[0].value; + if (name in requires) { + throw new Error(`Duplicate require found in ${info.path}: ${name}`); + } + const renamed = rename(name); + requires[name] = renamed; + return j.variableDeclaration('var', [ + j.variableDeclarator(j.identifier(renamed), j.callExpression( + j.identifier('require'), [j.literal(resolve(provide, name))] + )) + ]); + }); + + // replace all uses of required names with renamed identifiers + Object.keys(requires).sort().reverse().forEach(name => { + if (name.indexOf('.') > 0) { + root.find(j.MemberExpression, getMemberExpression(name)) + .replaceWith(j.identifier(requires[name])); + } else { + root.find(j.Identifier, {name: name}) + .replaceWith(j.identifier(requires[name])); + } + }); + + // add module.exports + root.find(j.Program).get('body').push(j.expressionStatement( + j.assignmentExpression( + '=', + j.memberExpression(j.identifier('module'), j.identifier('exports')), + j.identifier(rename(provide)) + ) + )); + + // replace any initial comments + root.get().node.comments = comments; + + return root.toSource({quote: 'single'}); +}; From 815af723eae7b4096f895a09a84a91cb4f28e171 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sun, 18 Dec 2016 14:35:16 -0700 Subject: [PATCH 02/14] Require ol.ext dependencies directly --- package/package.json | 8 +++++++- transforms/common.js | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/package/package.json b/package/package.json index e9bc8208d7..6101038245 100644 --- a/package/package.json +++ b/package/package.json @@ -3,5 +3,11 @@ "version": "3.20.0-beta.1", "description": "OpenLayers", "main": "index.js", - "license": "BSD-2-Clause" + "license": "BSD-2-Clause", + "dependencies": { + "pbf": "3.0.5", + "pixelworks": "1.1.0", + "rbush": "2.0.1", + "vector-tile": "1.3.0" + } } diff --git a/transforms/common.js b/transforms/common.js index 5cc4dab91d..8935e21c9b 100644 --- a/transforms/common.js +++ b/transforms/common.js @@ -1,3 +1,5 @@ +var pkg = require('../package.json'); + function rename(name) { const parts = name.split('.'); return `_${parts.join('_')}_`; @@ -6,6 +8,24 @@ function rename(name) { function resolve(fromName, toName) { const fromParts = fromName.split('.'); const toParts = toName.split('.'); + if (toParts[0] === 'ol' && toParts[1] === 'ext') { + let name = toParts[2]; + let packageName; + for (let i = 0, ii = pkg.ext.length; i < ii; ++i) { + const dependency = pkg.ext[i]; + if (dependency.module === name) { + packageName = name; + break; + } else if (dependency.name === name) { + packageName = dependency.module; + break; + } + } + if (!packageName) { + throw new Error(`Can't find package name for ${toName}`); + } + return packageName; + } var commonDepth = 1; var fromLength = fromParts.length; while (commonDepth < fromLength - 1) { From d20e9ca8dfe2164b1710ec87ed4c31d520df687b Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sun, 18 Dec 2016 14:35:44 -0700 Subject: [PATCH 03/14] Add a readme --- package/package.json | 2 +- package/readme.md | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 package/readme.md diff --git a/package/package.json b/package/package.json index 6101038245..c1c1e2aff7 100644 --- a/package/package.json +++ b/package/package.json @@ -1,6 +1,6 @@ { "name": "ol", - "version": "3.20.0-beta.1", + "version": "3.21.0-beta.1", "description": "OpenLayers", "main": "index.js", "license": "BSD-2-Clause", diff --git a/package/readme.md b/package/readme.md new file mode 100644 index 0000000000..eaec0eb92b --- /dev/null +++ b/package/readme.md @@ -0,0 +1,33 @@ +# `ol` + +[OpenLayers](https://openlayers.org/) for CommonJS module loaders. + +**Note: This is still a work in progress. Not yet ready for production.** + +## Usage + +Add the `ol` package as a dependency to your project. + + npm install ol@beta --save + +Require just what you need for your application: + +```js +var OLMap = require('ol/Map'); +var View = require('ol/View'); +var TileLayer = require('ol/layer/Tile'); +var OSM = require('ol/source/OSM'); + +var map = new OLMap({ + target: 'map', + layers: [ + new TileLayer({ + source: new OSM() + }) + ], + view: new View({ + center: [0, 0], + zoom: 2 + }) +}); +``` From 04639842f2efbd7f8af56d5ded1c338590e152b2 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sun, 18 Dec 2016 14:57:55 -0700 Subject: [PATCH 04/14] Safer relative paths --- package/package.json | 2 +- transforms/common.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/package.json b/package/package.json index c1c1e2aff7..dc45cc1652 100644 --- a/package/package.json +++ b/package/package.json @@ -1,6 +1,6 @@ { "name": "ol", - "version": "3.21.0-beta.1", + "version": "3.21.0-beta.2", "description": "OpenLayers", "main": "index.js", "license": "BSD-2-Clause", diff --git a/transforms/common.js b/transforms/common.js index 8935e21c9b..12b43c61dc 100644 --- a/transforms/common.js +++ b/transforms/common.js @@ -28,7 +28,7 @@ function resolve(fromName, toName) { } var commonDepth = 1; var fromLength = fromParts.length; - while (commonDepth < fromLength - 1) { + while (commonDepth < fromLength - 2) { if (fromParts[commonDepth] === toParts[commonDepth]) { ++commonDepth; } else { From 329ec70836610ae04db73b126914812fdf215850 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sun, 18 Dec 2016 15:08:41 -0700 Subject: [PATCH 05/14] Handle ol provide --- transforms/common.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/transforms/common.js b/transforms/common.js index 12b43c61dc..fea14b7b77 100644 --- a/transforms/common.js +++ b/transforms/common.js @@ -107,8 +107,13 @@ module.exports = function(info, api) { } // replace all uses of provided name with renamed identifier - root.find(j.MemberExpression, getMemberExpression(provide)) - .replaceWith(j.identifier(rename(provide))); + if (provide.indexOf('.') > 0) { + root.find(j.MemberExpression, getMemberExpression(provide)) + .replaceWith(j.identifier(rename(provide))); + } else { + root.find(j.Identifier, {name: provide}) + .replaceWith(j.identifier(rename(provide))); + } // replace goog.require() const requires = {}; From ea04523bb94af8b9d7b3dbbc4972a7f7d83fa62e Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sun, 18 Dec 2016 15:14:25 -0700 Subject: [PATCH 06/14] Sort and replace provide and requires in one pass --- transforms/common.js | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/transforms/common.js b/transforms/common.js index fea14b7b77..983c5481ea 100644 --- a/transforms/common.js +++ b/transforms/common.js @@ -89,6 +89,8 @@ module.exports = function(info, api) { // store any initial comments const {comments} = root.find(j.Program).get('body', 0).node; + const replacements = {}; + // replace goog.provide() let provide; root.find(j.ExpressionStatement, getGoogExpressionStatement('provide')) @@ -105,26 +107,17 @@ module.exports = function(info, api) { if (!provide) { throw new Error(`No provide found in ${info.path}`); } - - // replace all uses of provided name with renamed identifier - if (provide.indexOf('.') > 0) { - root.find(j.MemberExpression, getMemberExpression(provide)) - .replaceWith(j.identifier(rename(provide))); - } else { - root.find(j.Identifier, {name: provide}) - .replaceWith(j.identifier(rename(provide))); - } + replacements[provide] = rename(provide); // replace goog.require() - const requires = {}; root.find(j.ExpressionStatement, getGoogExpressionStatement('require')) .replaceWith(path => { const name = path.value.expression.arguments[0].value; - if (name in requires) { + if (name in replacements) { throw new Error(`Duplicate require found in ${info.path}: ${name}`); } const renamed = rename(name); - requires[name] = renamed; + replacements[name] = renamed; return j.variableDeclaration('var', [ j.variableDeclarator(j.identifier(renamed), j.callExpression( j.identifier('require'), [j.literal(resolve(provide, name))] @@ -132,14 +125,14 @@ module.exports = function(info, api) { ]); }); - // replace all uses of required names with renamed identifiers - Object.keys(requires).sort().reverse().forEach(name => { + // 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(j.identifier(requires[name])); + .replaceWith(j.identifier(replacements[name])); } else { root.find(j.Identifier, {name: name}) - .replaceWith(j.identifier(requires[name])); + .replaceWith(j.identifier(replacements[name])); } }); From d17e809039e6c54b8341ef7ac241ff3fb1d84e4f Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sun, 18 Dec 2016 15:34:49 -0700 Subject: [PATCH 07/14] Rewrite boolean defines as globals --- Makefile | 1 + package/package.json | 2 +- transforms/common.js | 65 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c194bd0ee5..60271e5609 100644 --- a/Makefile +++ b/Makefile @@ -306,6 +306,7 @@ build/test_rendering_requires.js: $(SPEC_RENDERING_JS) package: build/timestamps/node-modules-timestamp @rm -rf build/package @mkdir -p build + @node tasks/generate-info.js @cp -r package build @cd ./src && cp -r ol/* ../build/package @rm build/package/typedefs.js diff --git a/package/package.json b/package/package.json index dc45cc1652..e8bedaee3f 100644 --- a/package/package.json +++ b/package/package.json @@ -1,6 +1,6 @@ { "name": "ol", - "version": "3.21.0-beta.2", + "version": "3.21.0-beta.4", "description": "OpenLayers", "main": "index.js", "license": "BSD-2-Clause", diff --git a/transforms/common.js b/transforms/common.js index 983c5481ea..c4c167aaeb 100644 --- a/transforms/common.js +++ b/transforms/common.js @@ -1,10 +1,18 @@ -var pkg = require('../package.json'); +const pkg = require('../package.json'); +const defines = require('../build/info.json').defines; + +const defineLookup = {}; +defines.forEach(define => defineLookup[define.name] = define); function rename(name) { const parts = name.split('.'); return `_${parts.join('_')}_`; } +function renameDefine(name) { + return name.replace('.', '_').toUpperCase(); +} + function resolve(fromName, toName) { const fromParts = fromName.split('.'); const toParts = toName.split('.'); @@ -60,6 +68,34 @@ function getGoogExpressionStatement(identifier) { }; } +const defineAssignment = { + type: 'AssignmentExpression', + left: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'ol' + }, + property: { + type: 'Identifier' + } + }, + right: { + type: 'Literal' + } +}; + +const defineMemberExpression = { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'ol' + }, + property: { + type: 'Identifier' + } +}; + function getMemberExpression(name) { function memberExpression(parts) { const dotIndex = parts.lastIndexOf('.'); @@ -91,6 +127,33 @@ module.exports = function(info, api) { const replacements = {}; + // replace assignments for boolean defines (e.g. ol.FOO = true -> global.OL_FOO = true) + root.find(j.AssignmentExpression, defineAssignment) + .filter(path => { + const node = path.value; + const defineName = `${node.left.object.name}.${node.left.property.name}`; + return defineName in defineLookup; + }) + .replaceWith(path => { + const node = path.value; + const defineName = `${node.left.object.name}.${node.left.property.name}`; + return j.assignmentExpression( + '=', + j.memberExpression(j.identifier('global'), j.identifier(renameDefine(defineName))), + j.literal(node.right.value)); + }); + + // replace all uses of boolean defines with renamed define + root.find(j.MemberExpression, defineMemberExpression) + .filter(path => { + const node = path.value; + const defineName = `${node.object.name}.${node.property.name}`; + return defineName in defineLookup; + }) + .replaceWith(path => { + return j.identifier(renameDefine(`${path.value.object.name}.${path.value.property.name}`)); + }); + // replace goog.provide() let provide; root.find(j.ExpressionStatement, getGoogExpressionStatement('provide')) From 91c1857d83028a66c8f8efc933836af020a6792f Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sat, 24 Dec 2016 08:19:29 -0700 Subject: [PATCH 08/14] Update transform to generate ES-2015 modules --- Makefile | 2 +- package/package.json | 3 +- transforms/{common.js => module.js} | 50 ++++++++++++++++------------- 3 files changed, 31 insertions(+), 24 deletions(-) rename transforms/{common.js => module.js} (84%) diff --git a/Makefile b/Makefile index 60271e5609..79e6c90f71 100644 --- a/Makefile +++ b/Makefile @@ -310,4 +310,4 @@ package: build/timestamps/node-modules-timestamp @cp -r package build @cd ./src && cp -r ol/* ../build/package @rm build/package/typedefs.js - ./node_modules/.bin/jscodeshift --transform transforms/common.js build/package + ./node_modules/.bin/jscodeshift --transform transforms/module.js build/package diff --git a/package/package.json b/package/package.json index e8bedaee3f..c52932d161 100644 --- a/package/package.json +++ b/package/package.json @@ -1,8 +1,9 @@ { "name": "ol", - "version": "3.21.0-beta.4", + "version": "3.21.0-beta.5", "description": "OpenLayers", "main": "index.js", + "module": "index.js", "license": "BSD-2-Clause", "dependencies": { "pbf": "3.0.5", diff --git a/transforms/common.js b/transforms/module.js similarity index 84% rename from transforms/common.js rename to transforms/module.js index c4c167aaeb..473f9ecdb5 100644 --- a/transforms/common.js +++ b/transforms/module.js @@ -34,8 +34,8 @@ function resolve(fromName, toName) { } return packageName; } - var commonDepth = 1; - var fromLength = fromParts.length; + const fromLength = fromParts.length; + let commonDepth = 1; while (commonDepth < fromLength - 2) { if (fromParts[commonDepth] === toParts[commonDepth]) { ++commonDepth; @@ -44,8 +44,12 @@ function resolve(fromName, toName) { } } - var back = new Array(fromLength - commonDepth).join('../') || './'; - return back + toParts.slice(commonDepth).join('/').toLowerCase(); + const back = new Array(fromLength - commonDepth).join('../') || './'; + let relative = back + toParts.slice(commonDepth).join('/').toLowerCase(); + if (relative.endsWith('/')) { + relative += 'index'; + } + return relative; } function getGoogExpressionStatement(identifier) { @@ -127,7 +131,7 @@ module.exports = function(info, api) { const replacements = {}; - // replace assignments for boolean defines (e.g. ol.FOO = true -> global.OL_FOO = true) + // replace assignments for boolean defines (e.g. ol.FOO = true -> window.OL_FOO = true) root.find(j.AssignmentExpression, defineAssignment) .filter(path => { const node = path.value; @@ -139,7 +143,7 @@ module.exports = function(info, api) { const defineName = `${node.left.object.name}.${node.left.property.name}`; return j.assignmentExpression( '=', - j.memberExpression(j.identifier('global'), j.identifier(renameDefine(defineName))), + j.memberExpression(j.identifier('window'), j.identifier(renameDefine(defineName))), j.literal(node.right.value)); }); @@ -172,21 +176,27 @@ module.exports = function(info, api) { } replacements[provide] = rename(provide); - // replace goog.require() + // replace `goog.require('foo')` with `import foo from 'foo'` + const imports = []; root.find(j.ExpressionStatement, getGoogExpressionStatement('require')) - .replaceWith(path => { + .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; - return j.variableDeclaration('var', [ - j.variableDeclarator(j.identifier(renamed), j.callExpression( - j.identifier('require'), [j.literal(resolve(provide, name))] - )) - ]); - }); + imports.push( + j.importDeclaration( + [j.importDefaultSpecifier(j.identifier(renamed))], + j.literal(resolve(provide, name)) + ) + ); + }) + .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 => { @@ -199,14 +209,10 @@ module.exports = function(info, api) { } }); - // add module.exports - root.find(j.Program).get('body').push(j.expressionStatement( - j.assignmentExpression( - '=', - j.memberExpression(j.identifier('module'), j.identifier('exports')), - j.identifier(rename(provide)) - ) - )); + // add export declaration + root.find(j.Program).get('body').push( + j.exportDefaultDeclaration(j.identifier(rename(provide))) + ); // replace any initial comments root.get().node.comments = comments; From b73ab8914a803e976c4cf44e068c5a8d9ce7daf4 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sun, 25 Dec 2016 17:46:50 -0700 Subject: [PATCH 09/14] Replace define assignment with variable declaration --- package/package.json | 2 +- transforms/module.js | 47 ++++++++++++++++++++++++-------------------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/package/package.json b/package/package.json index c52932d161..2185469324 100644 --- a/package/package.json +++ b/package/package.json @@ -1,6 +1,6 @@ { "name": "ol", - "version": "3.21.0-beta.5", + "version": "3.21.0-beta.6", "description": "OpenLayers", "main": "index.js", "module": "index.js", diff --git a/transforms/module.js b/transforms/module.js index 473f9ecdb5..3383c9e299 100644 --- a/transforms/module.js +++ b/transforms/module.js @@ -72,20 +72,23 @@ function getGoogExpressionStatement(identifier) { }; } -const defineAssignment = { - type: 'AssignmentExpression', - left: { - type: 'MemberExpression', - object: { - type: 'Identifier', - name: 'ol' +const defineStatement = { + type: 'ExpressionStatement', + expression: { + type: 'AssignmentExpression', + left: { + type: 'MemberExpression', + object: { + type: 'Identifier', + name: 'ol' + }, + property: { + type: 'Identifier' + } }, - property: { - type: 'Identifier' + right: { + type: 'Literal' } - }, - right: { - type: 'Literal' } }; @@ -132,19 +135,21 @@ module.exports = function(info, api) { const replacements = {}; // replace assignments for boolean defines (e.g. ol.FOO = true -> window.OL_FOO = true) - root.find(j.AssignmentExpression, defineAssignment) + root.find(j.ExpressionStatement, defineStatement) .filter(path => { - const node = path.value; - const defineName = `${node.left.object.name}.${node.left.property.name}`; + const expression = path.value.expression; + const defineName = `${expression.left.object.name}.${expression.left.property.name}`; return defineName in defineLookup; }) .replaceWith(path => { - const node = path.value; - const defineName = `${node.left.object.name}.${node.left.property.name}`; - return j.assignmentExpression( - '=', - j.memberExpression(j.identifier('window'), j.identifier(renameDefine(defineName))), - j.literal(node.right.value)); + const expression = path.value.expression; + const defineName = `${expression.left.object.name}.${expression.left.property.name}`; + const comments = path.value.comments; + const statement = j.variableDeclaration('var', [ + j.variableDeclarator(j.identifier(renameDefine(defineName)), j.literal(expression.right.value)) + ]); + statement.comments = comments; + return statement; }); // replace all uses of boolean defines with renamed define From b2a4b69d13dbe9d75a25e6b07eb9c1befbb82404 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Mon, 26 Dec 2016 10:47:26 -0700 Subject: [PATCH 10/14] Transform all defines --- Makefile | 8 +++++--- package.json | 1 + package/package.json | 2 +- package/readme.md | 10 +++++----- tasks/generate-defines.js | 31 +++++++++++++++++++++++++++++++ transforms/module.js | 21 +++++++++++---------- 6 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 tasks/generate-defines.js diff --git a/Makefile b/Makefile index 79e6c90f71..730b781666 100644 --- a/Makefile +++ b/Makefile @@ -302,11 +302,13 @@ build/test_rendering_requires.js: $(SPEC_RENDERING_JS) %shader.js: %shader.glsl src/ol/webgl/shader.mustache bin/pyglslunit.py build/timestamps/node-modules-timestamp @python bin/pyglslunit.py --input $< | ./node_modules/.bin/mustache - src/ol/webgl/shader.mustache > $@ +build/defines.json: src/ol/index.js build/timestamps/node-modules-timestamp + @node tasks/generate-defines.js + .PHONY: package -package: build/timestamps/node-modules-timestamp +package: build/defines.json @rm -rf build/package - @mkdir -p build - @node tasks/generate-info.js + @node tasks/generate-defines.js @cp -r package build @cd ./src && cp -r ol/* ../build/package @rm build/package/typedefs.js diff --git a/package.json b/package.json index e17a60c5ce..5e6022e939 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "eslint": "3.14.1", "eslint-config-openlayers": "7.0.0", "eslint-plugin-openlayers-internal": "^3.1.0", + "esprima": "2.x", "expect.js": "0.3.1", "gaze": "^1.0.0", "istanbul": "0.4.5", diff --git a/package/package.json b/package/package.json index 2185469324..5575d9a321 100644 --- a/package/package.json +++ b/package/package.json @@ -1,6 +1,6 @@ { "name": "ol", - "version": "3.21.0-beta.6", + "version": "3.21.0-beta.8", "description": "OpenLayers", "main": "index.js", "module": "index.js", diff --git a/package/readme.md b/package/readme.md index eaec0eb92b..cba32e5f66 100644 --- a/package/readme.md +++ b/package/readme.md @@ -10,13 +10,13 @@ Add the `ol` package as a dependency to your project. npm install ol@beta --save -Require just what you need for your application: +Import just what you need for your application: ```js -var OLMap = require('ol/Map'); -var View = require('ol/View'); -var TileLayer = require('ol/layer/Tile'); -var OSM = require('ol/source/OSM'); +import Map from 'ol/Map'; +import View from 'ol/View'; +import TileLayer from 'ol/layer/Tile'; +import OSM from 'ol/source/OSM'; var map = new OLMap({ target: 'map', diff --git a/tasks/generate-defines.js b/tasks/generate-defines.js new file mode 100644 index 0000000000..3b1bd8af6b --- /dev/null +++ b/tasks/generate-defines.js @@ -0,0 +1,31 @@ +var fs = require('fs'); +var path = require('path'); +var esprima = require('esprima'); + +var mainPath = path.join(__dirname, '..', 'src', 'ol', 'index.js'); +var mainSource = fs.readFileSync(mainPath, 'utf8'); +var definesPath = path.join(__dirname, '..', 'build', 'defines.json'); + +function isDefineLikeStatement(statement) { + return statement.type === 'ExpressionStatement' && + statement.expression && statement.expression.type === 'AssignmentExpression' && + statement.expression.left.type === 'MemberExpression' && + statement.expression.right.type === 'Literal' && + statement.leadingComments; +} + +var ast = esprima.parse(mainSource, {attachComment: true}); +var defines = {}; +ast.body.forEach(function(statement) { + if (isDefineLikeStatement(statement)) { + var comment = statement.leadingComments[statement.leadingComments.length - 1].value; + if (comment.indexOf('* @define {') >= 0) { + var expression = statement.expression; + var name = expression.left.object.name + '.' + expression.left.property.name; + var value = expression.right.value; + defines[name] = value; + } + } +}); + +fs.writeFileSync(definesPath, JSON.stringify(defines, null, 2)); diff --git a/transforms/module.js b/transforms/module.js index 3383c9e299..5acf4d396d 100644 --- a/transforms/module.js +++ b/transforms/module.js @@ -1,8 +1,5 @@ const pkg = require('../package.json'); -const defines = require('../build/info.json').defines; - -const defineLookup = {}; -defines.forEach(define => defineLookup[define.name] = define); +const defineLookup = require('../build/defines.json'); function rename(name) { const parts = name.split('.'); @@ -134,7 +131,7 @@ module.exports = function(info, api) { const replacements = {}; - // replace assignments for boolean defines (e.g. ol.FOO = true -> window.OL_FOO = true) + // replace assignments defines (e.g. ol.FOO = true -> window.OL_FOO = true) root.find(j.ExpressionStatement, defineStatement) .filter(path => { const expression = path.value.expression; @@ -145,14 +142,17 @@ module.exports = function(info, api) { const expression = path.value.expression; const defineName = `${expression.left.object.name}.${expression.left.property.name}`; const comments = path.value.comments; - const statement = j.variableDeclaration('var', [ - j.variableDeclarator(j.identifier(renameDefine(defineName)), j.literal(expression.right.value)) - ]); + const statement = j.expressionStatement( + j.assignmentExpression('=', + j.memberExpression(j.identifier('window'), j.identifier(renameDefine(defineName))), + j.literal(expression.right.value) + ) + ); statement.comments = comments; return statement; }); - // replace all uses of boolean defines with renamed define + // replace all uses of defines with renamed define root.find(j.MemberExpression, defineMemberExpression) .filter(path => { const node = path.value; @@ -160,7 +160,8 @@ module.exports = function(info, api) { return defineName in defineLookup; }) .replaceWith(path => { - return j.identifier(renameDefine(`${path.value.object.name}.${path.value.property.name}`)); + const defineName = `${path.value.object.name}.${path.value.property.name}`; + return j.memberExpression(j.identifier('window'), j.identifier(renameDefine(defineName))); }); // replace goog.provide() From 3eaa0f412ecbf172b6ebc709419be270987754fe Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 27 Dec 2016 08:38:18 -0700 Subject: [PATCH 11/14] Opinionated defines --- package/package.json | 2 +- package/readme.md | 4 ++-- transforms/module.js | 57 ++++++++------------------------------------ 3 files changed, 13 insertions(+), 50 deletions(-) diff --git a/package/package.json b/package/package.json index 5575d9a321..db40fddf01 100644 --- a/package/package.json +++ b/package/package.json @@ -1,6 +1,6 @@ { "name": "ol", - "version": "3.21.0-beta.8", + "version": "3.21.0-beta.10", "description": "OpenLayers", "main": "index.js", "module": "index.js", diff --git a/package/readme.md b/package/readme.md index cba32e5f66..d141397e76 100644 --- a/package/readme.md +++ b/package/readme.md @@ -1,6 +1,6 @@ # `ol` -[OpenLayers](https://openlayers.org/) for CommonJS module loaders. +[OpenLayers](https://openlayers.org/) for module loaders. **Note: This is still a work in progress. Not yet ready for production.** @@ -18,7 +18,7 @@ import View from 'ol/View'; import TileLayer from 'ol/layer/Tile'; import OSM from 'ol/source/OSM'; -var map = new OLMap({ +var map = new Map({ target: 'map', layers: [ new TileLayer({ diff --git a/transforms/module.js b/transforms/module.js index 5acf4d396d..b0c8485e9e 100644 --- a/transforms/module.js +++ b/transforms/module.js @@ -1,5 +1,9 @@ const pkg = require('../package.json'); -const defineLookup = require('../build/defines.json'); + +const defines = { + 'ol.DEBUG': false, + 'ol.ENABLE_WEBGL': false +}; function rename(name) { const parts = name.split('.'); @@ -69,26 +73,6 @@ function getGoogExpressionStatement(identifier) { }; } -const defineStatement = { - type: 'ExpressionStatement', - expression: { - type: 'AssignmentExpression', - left: { - type: 'MemberExpression', - object: { - type: 'Identifier', - name: 'ol' - }, - property: { - type: 'Identifier' - } - }, - right: { - type: 'Literal' - } - } -}; - const defineMemberExpression = { type: 'MemberExpression', object: { @@ -131,37 +115,16 @@ module.exports = function(info, api) { const replacements = {}; - // replace assignments defines (e.g. ol.FOO = true -> window.OL_FOO = true) - root.find(j.ExpressionStatement, defineStatement) - .filter(path => { - const expression = path.value.expression; - const defineName = `${expression.left.object.name}.${expression.left.property.name}`; - return defineName in defineLookup; - }) - .replaceWith(path => { - const expression = path.value.expression; - const defineName = `${expression.left.object.name}.${expression.left.property.name}`; - const comments = path.value.comments; - const statement = j.expressionStatement( - j.assignmentExpression('=', - j.memberExpression(j.identifier('window'), j.identifier(renameDefine(defineName))), - j.literal(expression.right.value) - ) - ); - statement.comments = comments; - return statement; - }); - - // replace all uses of defines with renamed define + // replace all uses of defines root.find(j.MemberExpression, defineMemberExpression) .filter(path => { const node = path.value; - const defineName = `${node.object.name}.${node.property.name}`; - return defineName in defineLookup; + const name = `${node.object.name}.${node.property.name}`; + return (name in defines) && path.parentPath.value.type !== 'AssignmentExpression'; }) .replaceWith(path => { - const defineName = `${path.value.object.name}.${path.value.property.name}`; - return j.memberExpression(j.identifier('window'), j.identifier(renameDefine(defineName))); + const name = `${path.value.object.name}.${path.value.property.name}`; + return j.literal(defines[name]); }); // replace goog.provide() From 490f42d5281197525462e7797f32d41ce1b6296c Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Tue, 27 Dec 2016 18:25:16 -0700 Subject: [PATCH 12/14] Avoid extra assignment for default export --- Makefile | 6 +----- package/package.json | 4 ++-- package/readme.md | 29 ++++++++++++++++++------- tasks/generate-defines.js | 31 --------------------------- transforms/module.js | 45 ++++++++++++++++++++++++++++++--------- 5 files changed, 59 insertions(+), 56 deletions(-) delete mode 100644 tasks/generate-defines.js diff --git a/Makefile b/Makefile index 730b781666..d6742d2187 100644 --- a/Makefile +++ b/Makefile @@ -302,13 +302,9 @@ build/test_rendering_requires.js: $(SPEC_RENDERING_JS) %shader.js: %shader.glsl src/ol/webgl/shader.mustache bin/pyglslunit.py build/timestamps/node-modules-timestamp @python bin/pyglslunit.py --input $< | ./node_modules/.bin/mustache - src/ol/webgl/shader.mustache > $@ -build/defines.json: src/ol/index.js build/timestamps/node-modules-timestamp - @node tasks/generate-defines.js - .PHONY: package -package: build/defines.json +package: @rm -rf build/package - @node tasks/generate-defines.js @cp -r package build @cd ./src && cp -r ol/* ../build/package @rm build/package/typedefs.js diff --git a/package/package.json b/package/package.json index db40fddf01..68bce09451 100644 --- a/package/package.json +++ b/package/package.json @@ -1,7 +1,7 @@ { "name": "ol", - "version": "3.21.0-beta.10", - "description": "OpenLayers", + "version": "3.21.0-beta.16", + "description": "OpenLayers as ES2015 modules", "main": "index.js", "module": "index.js", "license": "BSD-2-Clause", diff --git a/package/readme.md b/package/readme.md index d141397e76..0305a2f391 100644 --- a/package/readme.md +++ b/package/readme.md @@ -1,6 +1,6 @@ -# `ol` +# ol -[OpenLayers](https://openlayers.org/) for module loaders. +OpenLayers as ES2015 modules. **Note: This is still a work in progress. Not yet ready for production.** @@ -13,16 +13,18 @@ Add the `ol` package as a dependency to your project. 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 OSM from 'ol/source/OSM'; +import Map from 'ol/map'; +import View from 'ol/view'; +import TileLayer from 'ol/layer/tile'; +import XYZ from 'ol/source/xyz'; -var map = new Map({ +new Map({ target: 'map', layers: [ new TileLayer({ - source: new OSM() + source: new XYZ({ + url: 'https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png' + }) }) ], view: new View({ @@ -31,3 +33,14 @@ var map = new Map({ }) }); ``` + +Note that 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. + +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 [Browserify & Uglify](https://gist.github.com/tschaub/4bfb209a8f809823f1495b2e4436018e) + +This is still a work in progress. See [openlayers/openlayers#6302](https://github.com/openlayers/openlayers/pull/6302) for ongoing discussion. diff --git a/tasks/generate-defines.js b/tasks/generate-defines.js deleted file mode 100644 index 3b1bd8af6b..0000000000 --- a/tasks/generate-defines.js +++ /dev/null @@ -1,31 +0,0 @@ -var fs = require('fs'); -var path = require('path'); -var esprima = require('esprima'); - -var mainPath = path.join(__dirname, '..', 'src', 'ol', 'index.js'); -var mainSource = fs.readFileSync(mainPath, 'utf8'); -var definesPath = path.join(__dirname, '..', 'build', 'defines.json'); - -function isDefineLikeStatement(statement) { - return statement.type === 'ExpressionStatement' && - statement.expression && statement.expression.type === 'AssignmentExpression' && - statement.expression.left.type === 'MemberExpression' && - statement.expression.right.type === 'Literal' && - statement.leadingComments; -} - -var ast = esprima.parse(mainSource, {attachComment: true}); -var defines = {}; -ast.body.forEach(function(statement) { - if (isDefineLikeStatement(statement)) { - var comment = statement.leadingComments[statement.leadingComments.length - 1].value; - if (comment.indexOf('* @define {') >= 0) { - var expression = statement.expression; - var name = expression.left.object.name + '.' + expression.left.property.name; - var value = expression.right.value; - defines[name] = value; - } - } -}); - -fs.writeFileSync(definesPath, JSON.stringify(defines, null, 2)); diff --git a/transforms/module.js b/transforms/module.js index b0c8485e9e..ca913825bc 100644 --- a/transforms/module.js +++ b/transforms/module.js @@ -10,10 +10,6 @@ function rename(name) { return `_${parts.join('_')}_`; } -function renameDefine(name) { - return name.replace('.', '_').toUpperCase(); -} - function resolve(fromName, toName) { const fromParts = fromName.split('.'); const toParts = toName.split('.'); @@ -106,6 +102,16 @@ function getMemberExpression(name) { 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); @@ -127,24 +133,43 @@ module.exports = function(info, api) { return j.literal(defines[name]); }); - // replace goog.provide() + // remove goog.provide() let provide; root.find(j.ExpressionStatement, getGoogExpressionStatement('provide')) - .replaceWith(path => { + .forEach(path => { if (provide) { throw new Error(`Multiple provides in ${info.path}`); } provide = path.value.expression.arguments[0].value; - return j.variableDeclaration('var', [ - j.variableDeclarator(j.identifier(rename(provide)), j.objectExpression([])) - ]); - }); + }).remove(); if (!provide) { throw new Error(`No provide found in ${info.path}`); } 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([])) + ]) + ); + } + // replace `goog.require('foo')` with `import foo from 'foo'` const imports = []; root.find(j.ExpressionStatement, getGoogExpressionStatement('require')) From b59342b567594b87ce85afd7fdadb8240afae46d Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Fri, 3 Feb 2017 17:08:17 -0700 Subject: [PATCH 13/14] Note that the WebGL renderer is not available --- package/package.json | 2 +- package/readme.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/package.json b/package/package.json index 68bce09451..44ac1e5cb6 100644 --- a/package/package.json +++ b/package/package.json @@ -1,6 +1,6 @@ { "name": "ol", - "version": "3.21.0-beta.16", + "version": "3.21.0-beta.17", "description": "OpenLayers as ES2015 modules", "main": "index.js", "module": "index.js", diff --git a/package/readme.md b/package/readme.md index 0305a2f391..b655e8d0d8 100644 --- a/package/readme.md +++ b/package/readme.md @@ -34,7 +34,7 @@ new Map({ }); ``` -Note that 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. +Note that 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. Also note that the, WebGL renderer is not available in this package. See the following examples for more detail on bundling OpenLayers with your application: From 629d295e7a9495209ee72a73e26cdb5378a45971 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Sat, 4 Feb 2017 16:53:35 -0700 Subject: [PATCH 14/14] Additional package documentation --- package/readme.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/package/readme.md b/package/readme.md index b655e8d0d8..703e2cd25d 100644 --- a/package/readme.md +++ b/package/readme.md @@ -2,13 +2,13 @@ OpenLayers as ES2015 modules. -**Note: This is still a work in progress. Not yet ready for production.** +**Note: This package is in beta and the API is subject to change before a final stable release.** ## Usage Add the `ol` package as a dependency to your project. - npm install ol@beta --save + npm install ol --save Import just what you need for your application: @@ -34,8 +34,6 @@ new Map({ }); ``` -Note that 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. Also note that the, WebGL renderer is not available in this package. - See the following examples for more detail on bundling OpenLayers with your application: * Using [Rollup & Uglify](https://gist.github.com/tschaub/8beb328ea72b36446fc2198d008287de) @@ -43,4 +41,15 @@ See the following examples for more detail on bundling OpenLayers with your appl * Using [Webpack & Uglify](https://gist.github.com/tschaub/79025aef325cd2837364400a105405b8) * Using [Browserify & Uglify](https://gist.github.com/tschaub/4bfb209a8f809823f1495b2e4436018e) -This is still a work in progress. See [openlayers/openlayers#6302](https://github.com/openlayers/openlayers/pull/6302) for ongoing discussion. +## 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. + +## Caveats + + * Module identifiers and the structure of the exports are subject to change while this package is in beta. + * The WebGL renderer is not available in this package.