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'}); +};