[OLINGO-442] Create packaging tool and remove browserify
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/commit/87e35975 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/tree/87e35975 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/diff/87e35975 Branch: refs/heads/master Commit: 87e35975d7c71819e69d591daba23f5c8c07b1f3 Parents: 5e973c8 Author: Sven Kobler <[email protected]> Authored: Mon Oct 20 09:26:58 2014 +0200 Committer: Sven Kobler <[email protected]> Committed: Mon Oct 20 09:38:52 2014 +0200 ---------------------------------------------------------------------- odatajs/Gruntfile.js | 121 +- .../stripheader/package.json | 42 - .../stripheader/stripheader.js | 42 - .../custom-tasks/rat/extern-tools/info.md | 4 +- .../grunt-config/custom-tasks/rat/package.json | 18 - odatajs/grunt-config/custom-tasks/toBrowser.js | 23 + .../custom-tasks/toBrowser/toBrowser.js | 78 ++ .../custom-tasks/toBrowser/wrapper-tpl.js | 43 + odatajs/grunt-config/release.js | 28 +- odatajs/grunt-config/sign.js | 1 - odatajs/package.json | 4 +- odatajs/src/browser-lib-tpl.js | 43 + odatajs/src/index-browser.js | 36 + odatajs/src/index-node.js | 47 + odatajs/src/index.js | 21 +- odatajs/src/lib/cache.js | 11 +- odatajs/src/lib/cache/source.js | 2 +- odatajs/src/lib/deferred.js | 189 +++ odatajs/src/lib/odata.js | 4 +- odatajs/src/lib/odata/batch.js | 4 +- odatajs/src/lib/odata/handler.js | 4 +- odatajs/src/lib/odata/json.js | 4 +- odatajs/src/lib/odata/metadata.js | 4 +- odatajs/src/lib/odata/net.js | 2 +- odatajs/src/lib/odata/odatautils.js | 1265 ++++++++++++++++++ odatajs/src/lib/odata/utils.js | 1265 ------------------ odatajs/src/lib/odatajs/deferred.js | 189 --- odatajs/src/lib/odatajs/utils.js | 582 -------- odatajs/src/lib/odatajs/xml.js | 816 ----------- odatajs/src/lib/store/dom.js | 2 +- odatajs/src/lib/store/indexeddb.js | 2 +- odatajs/src/lib/store/memory.js | 2 +- odatajs/src/lib/utils.js | 582 ++++++++ odatajs/src/lib/xml.js | 816 +++++++++++ odatajs/test-node/test.html | 29 + odatajs/test-node/test.js | 22 + odatajs/tests/odata-qunit-tests.htm | 2 +- olingojs-4.0.0-beta-01.exports.json | 917 +++++++++++++ 38 files changed, 4194 insertions(+), 3072 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/Gruntfile.js ---------------------------------------------------------------------- diff --git a/odatajs/Gruntfile.js b/odatajs/Gruntfile.js index 5b66d60..435584d 100644 --- a/odatajs/Gruntfile.js +++ b/odatajs/Gruntfile.js @@ -26,56 +26,53 @@ module.exports = function(grunt) { (pkg.postfix.length > 0 ? "-" : "") + pkg.postfix + (pkg.releaseCandidate.length > 0 ? "-" : "") + pkg.releaseCandidate; + //options var init = { pkg: pkg, banner: grunt.file.read('src/banner.txt'), artifactname : artifactname, - "browserify": { // convert code from nodejs style to browser style - src: { - files: { 'build/lib/<%= artifactname %>.js': ['src/index.js'] }, - options: { // remove apache license headers before contatenating - transform: ['./grunt-config/browserify_transforms/stripheader/stripheader.js'], - } + "toBrowser" : { + "release" : { + options: { index : "src/index-browser.js" }, + files: [{ + src: ["src/lib/**/*.js"], + dest: "build/lib/<%= artifactname %>.js", + }] } }, "uglify": { // uglify and minify the lib options: { sourceMap : true, - sourceMapName : 'build/lib/<%= artifactname %>.map', + sourceMapName : "build/lib/<%= artifactname %>.map", sourceMapIncludeSources : true, }, build: { - src: 'build/lib/<%= artifactname %>.js', - dest: 'build/lib/<%= artifactname %>.min.js' + src: "build/lib/<%= artifactname %>.js", + dest: "build/lib/<%= artifactname %>.min.js" } }, "concat" : { // add the apache license headers options : { - banner : '<%= banner %>' + banner : "<%= banner %>" }, licence: { - src: 'build/lib/<%= artifactname %>.js', - dest: 'build/lib/<%= artifactname %>.js', + src: "build/lib/<%= artifactname %>.js", + dest: "build/lib/<%= artifactname %>.js", }, licence_min: { - src: 'build/lib/<%= artifactname %>.min.js', - dest: 'build/lib/<%= artifactname %>.min.js', - }, - src: { - src: ['src/**/*.js'], - dest: 'build/lib/<%= artifactname %>.js', + src: "build/lib/<%= artifactname %>.min.js", + dest: "build/lib/<%= artifactname %>.min.js", }, - }, - "jsdoc" : { // generate documentation + "jsdoc" : { src : { - src: ['src/**/*.js'], - options: { destination: 'build/doc-src', verbose : false } + src: ["src/**/*.js"], + options: { destination: "build/doc-src", verbose : false } }, test : { - src: ['tests/**/*.js'], - options: { destination: 'build/doc-test', verbose : false } + src: ["tests/**/*.js"], + options: { destination: "build/doc-test", verbose : false } } }, "nugetpack" : { // create nuget pagckage @@ -84,57 +81,43 @@ module.exports = function(grunt) { dest: 'build/' } }, - 'copy' : { - 'to-latest' : { + "copy" : { + "to-latest" : { files: [ { - src :'build/lib/<%= artifactname %>.js', - dest: 'build/lib/odatajs-latest.js' }, - ] - } - + src :"build/lib/<%= artifactname %>.js", + dest: "build/lib/odatajs-latest.js" }, + ] + } }, "npm-clean": { options: {force: true}, "build": { - src: [ "build"], - }, - "lib": { - src: [ "build/lib"] - }, - "tmp": { - src: [ "build/tmp"] - }, - "doc": { - src: ["build/doc"], - }, - "doc-test": { - src: ["build/doc-test"], + src: [ "build"] }, }, "curl": { - 'license': { + "license": { src: { - url: 'http://apache.org/licenses/LICENSE-2.0.txt', - proxy: 'http://proxy:8080' + url: "http://apache.org/licenses/LICENSE-2.0.txt", + proxy: "http://proxy:8080" }, - dest: 'LICENSE' + dest: "LICENSE" } - } + } }; - /*** Join local configuration for proxies and local test servers ***/ + // Join local configuration for proxies and local test servers if (grunt.file.exists('localgrunt.config')) { console.log("merge localgrunt.config"); var localGrundConfig = grunt.file.read('localgrunt.config'); init.connect['test-browser'].proxies = init.connect['test-browser'].proxies.concat(JSON.parse(localGrundConfig).proxies); } - /*** Init ***/ + // Init config grunt.initConfig(init); - /*** Load tasks from npm modules ***/ - grunt.loadNpmTasks('grunt-browserify'); + // Load tasks from npm modules ***/ grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks("grunt-contrib-copy"); grunt.loadNpmTasks("grunt-contrib-concat"); @@ -143,10 +126,8 @@ module.exports = function(grunt) { grunt.loadNpmTasks("grunt-jsdoc"); grunt.loadNpmTasks("grunt-nuget"); - // Start Qunit tests direcly in node js, internally qunit (npm qunit) - // is used, no phantomjs instance required - //grunt.loadNpmTasks('grunt-node-qunit'); - //grunt.loadNpmTasks('grunt-contrib-clean'); + // Load the custom-* tasks from the grunt-config directory + grunt.loadTasks('grunt-config/custom-tasks'); // Load the custom-* tasks from the grunt-config directory grunt.loadTasks('grunt-config'); @@ -158,9 +139,9 @@ module.exports = function(grunt) { process.env['JAVA_TOOL_OPTIONS'] = ''; }); - /*** E N D U S E R T A S K S ***/ + // E N D U S E R T A S K S - grunt.registerTask('clean', ['npm-clean']); + grunt.registerTask('clean', ['npm-clean:build']); // Runs the license header check to verify the any source file contains a license header grunt.registerTask('license-check', ['rat:manual']); @@ -170,14 +151,32 @@ module.exports = function(grunt) { grunt.registerTask('doc-test', ['clearEnv', 'jsdoc:test']); // Build the odatajs library - grunt.registerTask('build', ['clean:lib','browserify:src', 'uglify:build', 'concat:licence','concat:licence_min','copy:to-latest','nugetpack']); - grunt.registerTask('build2', ['clean:lib','concat:src', 'uglify:build', 'concat:licence','concat:licence_min','nugetpack']); + grunt.registerTask('test-browser', ['configureProxies:test-browser', 'connect:test-browser']); grunt.registerTask('test-node', ['node-qunit:default-tests']); //grunt.registerTask('release', ['build','doc','compress']); //grunt.registerTask('update-legal', ['curl:license']); + + grunt.registerTask('build', ['clean:lib','toBrowser:release', 'uglify:build', 'concat:licence_min','copy:to-latest','nugetpack']); + + grunt.registerTask('get-licence', ['curl:license']); + + // R E L E A S E T A S K S + grunt.registerTask('release',[ + 'npm-clean:release-dist', + 'build', + 'doc', + 'copy:release-lib','copy:release-doc','copy:release-sources', + 'rat:dist', // check the license headers + 'compress:release-lib','compress:release-doc','compress:release-sources', + ]); + + grunt.registerTask('release:sign',[ + 'sign:release','sign:asc','sign:asc-verify' + ]); + }; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/grunt-config/browserify_transforms/stripheader/package.json ---------------------------------------------------------------------- diff --git a/odatajs/grunt-config/browserify_transforms/stripheader/package.json b/odatajs/grunt-config/browserify_transforms/stripheader/package.json deleted file mode 100644 index a86cfca..0000000 --- a/odatajs/grunt-config/browserify_transforms/stripheader/package.json +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -{ - "name": "grunt-rat", - "version": "0.0.1", - "description": "Transform vor removing license headers", - "license": "Apache", - "author": { - "name": "Sven Kobler-Morris", - "email": "[email protected]" - }, - "files": [ - "tasks" - ], - "dependencies": { - "through": "^2.3.4" - }, - "devDependencies": { - }, - "peerDependencies": { - "grunt": "~0.4.0" - }, - "engines": { - "node": ">=0.8.0" - } -} http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/grunt-config/browserify_transforms/stripheader/stripheader.js ---------------------------------------------------------------------- diff --git a/odatajs/grunt-config/browserify_transforms/stripheader/stripheader.js b/odatajs/grunt-config/browserify_transforms/stripheader/stripheader.js deleted file mode 100644 index b4f6f35..0000000 --- a/odatajs/grunt-config/browserify_transforms/stripheader/stripheader.js +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -var through = require('through'); - -module.exports = function (file) { - //if (/\.json$/.test(file)) return through(); - //console.log('strip header from ' + file); - var data = ""; - - - return through( - function (buf) { data += buf; }, - function () { - try { - //console.log('\nin--------------\na'+data.substring(0,1000)); - var out = data.replace(/(\/\*(.|\n|\r)*?\*\/)/i,""); - //console.log('\nout--------------\n'+out.substring(0,300)); - this.queue(out); - } catch (er) { - this.emit("error", new Error(er.toString().replace("Error: ", "") + " (" + file + ")")); - } - this.queue(null); - } - ); -}; - http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/grunt-config/custom-tasks/rat/extern-tools/info.md ---------------------------------------------------------------------- diff --git a/odatajs/grunt-config/custom-tasks/rat/extern-tools/info.md b/odatajs/grunt-config/custom-tasks/rat/extern-tools/info.md index f925cb2..f48049e 100644 --- a/odatajs/grunt-config/custom-tasks/rat/extern-tools/info.md +++ b/odatajs/grunt-config/custom-tasks/rat/extern-tools/info.md @@ -16,5 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -Place apache-rat-0.11.jar in ./apache-rat-0.11/apache-rat-0.11.jar. +Place apache-rat-0.11.jar from http://creadur.apache.org/rat/download_rat.cgi +in ./apache-rat-0.11/apache-rat-0.11.jar. + See ./../readme.md for details \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/grunt-config/custom-tasks/rat/package.json ---------------------------------------------------------------------- diff --git a/odatajs/grunt-config/custom-tasks/rat/package.json b/odatajs/grunt-config/custom-tasks/rat/package.json index f5fa8bb..0c374c7 100644 --- a/odatajs/grunt-config/custom-tasks/rat/package.json +++ b/odatajs/grunt-config/custom-tasks/rat/package.json @@ -1,21 +1,3 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ { "name": "grunt-rat", "version": "0.0.1", http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/grunt-config/custom-tasks/toBrowser.js ---------------------------------------------------------------------- diff --git a/odatajs/grunt-config/custom-tasks/toBrowser.js b/odatajs/grunt-config/custom-tasks/toBrowser.js new file mode 100644 index 0000000..4712a87 --- /dev/null +++ b/odatajs/grunt-config/custom-tasks/toBrowser.js @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +module.exports = function(grunt) { + require('./toBrowser/toBrowser.js')(grunt); +}; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/grunt-config/custom-tasks/toBrowser/toBrowser.js ---------------------------------------------------------------------- diff --git a/odatajs/grunt-config/custom-tasks/toBrowser/toBrowser.js b/odatajs/grunt-config/custom-tasks/toBrowser/toBrowser.js new file mode 100644 index 0000000..eccaf35 --- /dev/null +++ b/odatajs/grunt-config/custom-tasks/toBrowser/toBrowser.js @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +module.exports = function(grunt) { + + var stripHeader = function(input) { + return input.replace(/(\/\*(.|\n|\r)*?\*\/)/i,""); + }; + + grunt.registerMultiTask('toBrowser', function() { + var self = this; + + var path = require('path'); + var fs = require( 'fs' ); + + var globalDone = this.async(); + + var options = this.options({ }); + + var workLoad = []; + var writeToLogOk = function(data) { grunt.log.ok(data.toString()); }; + + + // fill workLoad + for(var i = 0; i < this.files.length; i++) { + for(var ii = 0; ii < this.files[i].src.length; ii++) { + var srcFile = this.files[i].src[ii]; + workLoad.push({ + srcFile : srcFile, + name : srcFile.substring(srcFile.lastIndexOf('/')+1,srcFile.length-3) + }); + } + + var concat = '{'; + for(var x = 0; x < workLoad.length; x++) { + var src = grunt.file.read(workLoad[x].srcFile); + // remove the first comment + src = stripHeader(src); + + if (x > 0) { + concat+= ', '; + } + + concat+= '"' + workLoad[x].name + '" : '; + concat+= 'function(exports, module, require) {'; + concat+= src +'}'; + } + concat+= '}'; + + var tpl = grunt.file.read('./grunt-config/custom-tasks/toBrowser/wrapper-tpl.js'); + var init = stripHeader(grunt.file.read(options.index)); + + tpl = tpl.replace('\'<% initFunction %>\'',init); + tpl = tpl.replace('\'<% filesAsFunctionList %>\'',concat); + + grunt.file.write(this.files[i].dest, tpl); + } + + globalDone(); + }); +}; + http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/grunt-config/custom-tasks/toBrowser/wrapper-tpl.js ---------------------------------------------------------------------- diff --git a/odatajs/grunt-config/custom-tasks/toBrowser/wrapper-tpl.js b/odatajs/grunt-config/custom-tasks/toBrowser/wrapper-tpl.js new file mode 100644 index 0000000..9c335db --- /dev/null +++ b/odatajs/grunt-config/custom-tasks/toBrowser/wrapper-tpl.js @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var init = function(exports, module, require) { + '<% initFunction %>' +}; + +var datas = '<% filesAsFunctionList %>'; + +var modules = {}; + +var require = function(path) { + var name = path.substring(path.lastIndexOf('/')+1,path.length-3); + if (modules[name]) { return modules[name].exports; } + + modules[name] = { exports : {}}; + console.log(name); + if (name === 'sou') { + var i = 0; + } + datas[name].call(this,modules[name].exports,modules[name],require); + return modules[name].exports; + }; + +window.odatajs = {}; +init.call(this,window.odatajs,window.odatajs,require); + + http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/grunt-config/release.js ---------------------------------------------------------------------- diff --git a/odatajs/grunt-config/release.js b/odatajs/grunt-config/release.js index 99edb19..f163ca0 100644 --- a/odatajs/grunt-config/release.js +++ b/odatajs/grunt-config/release.js @@ -166,34 +166,8 @@ module.exports = function(grunt) { }, }); - - - /* - //sign - grunt.config.merge( { - sign : { - 'release-lib': { // just the lib - options: {archive: './../dist/<%= artifactname %>/<%= artifactname %>-lib.zip'}, - files: [{expand: true, cwd: './../dist/<%= artifactname %>/lib', src: ['**'], dest: '/'}] - }, - } - }); -*/ grunt.loadNpmTasks('grunt-contrib-compress'); - - //tasks - grunt.registerTask('release',[ - 'npm-clean:release-dist', - 'build', - 'doc', - 'copy:release-lib','copy:release-doc','copy:release-sources', - 'rat:dist', // check the license headers - 'compress:release-lib','compress:release-doc','compress:release-sources', - ]); - grunt.registerTask('release:sign',[ - 'sign:release','sign:asc','sign:asc-verify' - ]); - + }; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/grunt-config/sign.js ---------------------------------------------------------------------- diff --git a/odatajs/grunt-config/sign.js b/odatajs/grunt-config/sign.js index 188d019..5a676ab 100644 --- a/odatajs/grunt-config/sign.js +++ b/odatajs/grunt-config/sign.js @@ -19,7 +19,6 @@ module.exports = function(grunt) { - //sign grunt.config.merge( { 'sign' : { http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/package.json ---------------------------------------------------------------------- diff --git a/odatajs/package.json b/odatajs/package.json index 8f1e577..ea387d9 100644 --- a/odatajs/package.json +++ b/odatajs/package.json @@ -7,7 +7,8 @@ "title": "Olingo OData Client for JavaScript", "description": "the Olingo OData Client for JavaScript library is a new cross-browser JavaScript library that enables data-centric web applications by leveraging modern protocols such as JSON and OData and HTML5-enabled browser features. It's designed to be small, fast and easy to use.", "homepage": "http://olingo.apache.org", - "main": "index.js", + "main": "index-node.js", + "main-browser": "index.js", "repository": { "type": "git", "url": "http://git-wip-us.apache.org/repos/asf/olingo-odata4-js.git" @@ -31,7 +32,6 @@ ], "scripts": {}, "devDependencies": { - "browserify": "^4.1.5", "grunt": "^0.4.5", "grunt-browserify": "^2.1.0", "grunt-connect-proxy": "^0.1.10", http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/browser-lib-tpl.js ---------------------------------------------------------------------- diff --git a/odatajs/src/browser-lib-tpl.js b/odatajs/src/browser-lib-tpl.js new file mode 100644 index 0000000..9c335db --- /dev/null +++ b/odatajs/src/browser-lib-tpl.js @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +var init = function(exports, module, require) { + '<% initFunction %>' +}; + +var datas = '<% filesAsFunctionList %>'; + +var modules = {}; + +var require = function(path) { + var name = path.substring(path.lastIndexOf('/')+1,path.length-3); + if (modules[name]) { return modules[name].exports; } + + modules[name] = { exports : {}}; + console.log(name); + if (name === 'sou') { + var i = 0; + } + datas[name].call(this,modules[name].exports,modules[name],require); + return modules[name].exports; + }; + +window.odatajs = {}; +init.call(this,window.odatajs,window.odatajs,require); + + http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/index-browser.js ---------------------------------------------------------------------- diff --git a/odatajs/src/index-browser.js b/odatajs/src/index-browser.js new file mode 100644 index 0000000..1f52e6b --- /dev/null +++ b/odatajs/src/index-browser.js @@ -0,0 +1,36 @@ +/*1 + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +// version information +exports.version = { major: 4, minor: 0, build: 0 }; + +// core stuff, always needed +exports.deferred = require('./lib/deferred.js'); +exports.utils = require('./lib/utils.js'); + +// only needed for xml metadata +exports.xml = require('./lib/ext/xml.js'); + +// only need in browser case +exports.oData = require('./lib/odata.js'); +exports.store = require('./lib/store.js'); +exports.cache = require('./lib/cache.js'); + + + http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/index-node.js ---------------------------------------------------------------------- diff --git a/odatajs/src/index-node.js b/odatajs/src/index-node.js new file mode 100644 index 0000000..28bf066 --- /dev/null +++ b/odatajs/src/index-node.js @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +var odatajs = {}; + +odatajs.version = { + major: 4, + minor: 0, + build: 0 +}; + +// core stuff, alway needed +odatajs.deferred = require('./lib/deferred.js'); +odatajs.utils = require('./lib/utils.js'); + +// only neede for xml metadata +odatajs.xml = require('./lib/ext/xml.js'); + +// only need in browser case +odatajs.oData = require('./lib/odata.js'); +odatajs.store = require('./lib/store.js'); +odatajs.cache = require('./lib/cache.js'); + +if (typeof window !== 'undefined') { + //expose to browsers window object + window.odatajs = odatajs; +} else { + //expose in commonjs style + odatajs.node = "node"; + module.exports = odatajs; +} http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/index.js ---------------------------------------------------------------------- diff --git a/odatajs/src/index.js b/odatajs/src/index.js index 42615d3..d939da2 100644 --- a/odatajs/src/index.js +++ b/odatajs/src/index.js @@ -17,18 +17,27 @@ * under the License. */ +//console.log('main starting'); +//var a = require('./a.js'); +//var b = require('./b.js'); +//console.log('in main, a.done=%j, b.done=%j', a.done, b.done); + var odatajs = {}; odatajs.version = { - major: 1, - minor: 1, - build: 1 + major: 4, + minor: 0, + build: 0 }; -odatajs.deferred = require('./lib/odatajs/deferred.js'); -odatajs.utils = require('./lib/odatajs/utils.js'); -odatajs.xml = require('./lib/odatajs/xml.js'); +// core stuff, alway needed +odatajs.deferred = require('./lib/deferred.js'); +odatajs.utils = require('./lib/utils.js'); + +// only neede for xml metadata +odatajs.xml = require('./lib/ext/xml.js'); +// only need in browser case odatajs.oData = require('./lib/odata.js'); odatajs.store = require('./lib/store.js'); odatajs.cache = require('./lib/cache.js'); http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/cache.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/cache.js b/odatajs/src/lib/cache.js index 92a740d..9912865 100644 --- a/odatajs/src/lib/cache.js +++ b/odatajs/src/lib/cache.js @@ -20,10 +20,10 @@ /** @module cache */ //var odatajs = require('./odatajs/utils.js'); -var utils = require('./odatajs/utils.js'); -var deferred = require('./odatajs/deferred.js'); +var utils = require('./utils.js'); +var deferred = require('./deferred.js'); var storeReq = require('./store.js'); -var cacheSource = require('./cache/source'); +var cacheSource = require('./cache/source.js'); var assigned = utils.assigned; @@ -1447,4 +1447,7 @@ function createDataCache (options) { exports.estimateSize = estimateSize; /** createDataCache */ -exports.createDataCache = createDataCache; \ No newline at end of file +exports.createDataCache = createDataCache; + + + http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/cache/source.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/cache/source.js b/odatajs/src/lib/cache/source.js index eccf5d9..af878c6 100644 --- a/odatajs/src/lib/cache/source.js +++ b/odatajs/src/lib/cache/source.js @@ -19,7 +19,7 @@ /** @module cache/source */ -var utils = require("./../odatajs/utils.js"); +var utils = require("./../utils.js"); var odataRequest = require("./../odata.js"); var parseInt10 = utils.parseInt10; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/deferred.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/deferred.js b/odatajs/src/lib/deferred.js new file mode 100644 index 0000000..7d5fd68 --- /dev/null +++ b/odatajs/src/lib/deferred.js @@ -0,0 +1,189 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** @module datajs/deferred */ + + + +/** Creates a new function to forward a call. + * @param {Object} thisValue - Value to use as the 'this' object. + * @param {String} name - Name of function to forward to. + * @param {Object} returnValue - Return value for the forward call (helps keep identity when chaining calls). + * @returns {Function} A new function that will forward a call. + */ +function forwardCall(thisValue, name, returnValue) { + return function () { + thisValue[name].apply(thisValue, arguments); + return returnValue; + }; +} + +/** Initializes a new DjsDeferred object. + * <ul> + * <li> Compability Note A - Ordering of callbacks through chained 'then' invocations <br> + * + * The Wiki entry at http://wiki.commonjs.org/wiki/Promises/A + * implies that .then() returns a distinct object. + * + * For compatibility with http://api.jquery.com/category/deferred-object/ + * we return this same object. This affects ordering, as + * the jQuery version will fire callbacks in registration + * order regardless of whether they occur on the result + * or the original object. + * </li> + * <li>Compability Note B - Fulfillment value <br> + * + * The Wiki entry at http://wiki.commonjs.org/wiki/Promises/A + * implies that the result of a success callback is the + * fulfillment value of the object and is received by + * other success callbacks that are chained. + * + * For compatibility with http://api.jquery.com/category/deferred-object/ + * we disregard this value instead. + * </li></ul> + * @class DjsDeferred + */ + function DjsDeferred() { + this._arguments = undefined; + this._done = undefined; + this._fail = undefined; + this._resolved = false; + this._rejected = false; +} + + +DjsDeferred.prototype = { + + /** Adds success and error callbacks for this deferred object. + * See Compatibility Note A. + * @method DjsDeferred#then + * @param {function} [fulfilledHandler] - Success callback ( may be null) + * @param {function} [errorHandler] - Error callback ( may be null) + */ + then: function (fulfilledHandler, errorHandler) { + + if (fulfilledHandler) { + if (!this._done) { + this._done = [fulfilledHandler]; + } else { + this._done.push(fulfilledHandler); + } + } + + if (errorHandler) { + if (!this._fail) { + this._fail = [errorHandler]; + } else { + this._fail.push(errorHandler); + } + } + + //// See Compatibility Note A in the DjsDeferred constructor. + //// if (!this._next) { + //// this._next = createDeferred(); + //// } + //// return this._next.promise(); + + if (this._resolved) { + this.resolve.apply(this, this._arguments); + } else if (this._rejected) { + this.reject.apply(this, this._arguments); + } + + return this; + }, + + /** Invokes success callbacks for this deferred object. + * All arguments are forwarded to success callbacks. + * @method DjsDeferred#resolve + */ + resolve: function (/* args */) { + if (this._done) { + var i, len; + for (i = 0, len = this._done.length; i < len; i++) { + //// See Compability Note B - Fulfillment value. + //// var nextValue = + this._done[i].apply(null, arguments); + } + + //// See Compatibility Note A in the DjsDeferred constructor. + //// this._next.resolve(nextValue); + //// delete this._next; + + this._done = undefined; + this._resolved = false; + this._arguments = undefined; + } else { + this._resolved = true; + this._arguments = arguments; + } + }, + + /** Invokes error callbacks for this deferred object. + * All arguments are forwarded to error callbacks. + * @method DjsDeferred#reject + */ + reject: function (/* args */) { + + if (this._fail) { + var i, len; + for (i = 0, len = this._fail.length; i < len; i++) { + this._fail[i].apply(null, arguments); + } + + this._fail = undefined; + this._rejected = false; + this._arguments = undefined; + } else { + this._rejected = true; + this._arguments = arguments; + } + }, + + /** Returns a version of this object that has only the read-only methods available. + * @method DjsDeferred#promise + * @returns An object with only the promise object. + */ + + promise: function () { + var result = {}; + result.then = forwardCall(this, "then", result); + return result; + } +}; + +/** Creates a deferred object. + * @returns {DjsDeferred} A new deferred object. If jQuery is installed, then a jQueryDeferred object is returned, which provides a superset of features. +*/ +function createDeferred() { + if (window.jQuery && window.jQuery.Deferred) { + return new window.jQuery.Deferred(); + } else { + return new DjsDeferred(); + } +}; + + + + +/** createDeferred (see {@link module:datajs/deferred~createDeferred}) */ +exports.createDeferred = createDeferred; + +/** DjsDeferred (see {@link DjsDeferred}) */ +exports.DjsDeferred = DjsDeferred; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/odata.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata.js b/odatajs/src/lib/odata.js index 8999bb2..7ea728b 100644 --- a/odatajs/src/lib/odata.js +++ b/odatajs/src/lib/odata.js @@ -20,7 +20,7 @@ /** @module odata */ // Imports -var odataUtils = exports.utils = require('./odata/utils.js'); +var odataUtils = exports.utils = require('./odata/odatautils.js'); var odataHandler = exports.handler = require('./odata/handler.js'); var odataMetadata = exports.metadata = require('./odata/metadata.js'); var odataNet = exports.net = require('./odata/net.js'); @@ -29,7 +29,7 @@ var odataJson = exports.json = require('./odata/json.js'); -var utils = require('./odatajs/utils.js'); +var utils = require('./utils.js'); var assigned = utils.assigned; var defined = utils.defined; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/odata/batch.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/batch.js b/odatajs/src/lib/odata/batch.js index 59fb1f8..c71fc31 100644 --- a/odatajs/src/lib/odata/batch.js +++ b/odatajs/src/lib/odata/batch.js @@ -19,8 +19,8 @@ /** @module odata/batch */ -var utils = require('./../odatajs/utils.js'); -var odataUtils = require('./utils.js'); +var utils = require('./../utils.js'); +var odataUtils = require('./odatautils.js'); var odataHandler = require('./handler.js'); var extend = utils.extend; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/odata/handler.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/handler.js b/odatajs/src/lib/odata/handler.js index d2b62d4..cbd09c6 100644 --- a/odatajs/src/lib/odata/handler.js +++ b/odatajs/src/lib/odata/handler.js @@ -20,8 +20,8 @@ /** @module odata/handler */ -var utils = require('./../odatajs/utils.js'); -var oDataUtils = require('./utils.js'); +var utils = require('./../utils.js'); +var oDataUtils = require('./odatautils.js'); // Imports. var assigned = utils.assigned; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/odata/json.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/json.js b/odatajs/src/lib/odata/json.js index d003e2b..6955cbe 100644 --- a/odatajs/src/lib/odata/json.js +++ b/odatajs/src/lib/odata/json.js @@ -21,8 +21,8 @@ -var utils = require('./../odatajs/utils.js'); -var oDataUtils = require('./utils.js'); +var utils = require('./../utils.js'); +var oDataUtils = require('./odatautils.js'); var oDataHandler = require('./handler.js'); var odataNs = "odata"; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/odata/metadata.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/metadata.js b/odatajs/src/lib/odata/metadata.js index fb34286..e37161f 100644 --- a/odatajs/src/lib/odata/metadata.js +++ b/odatajs/src/lib/odata/metadata.js @@ -19,8 +19,8 @@ /** @module odata/metadata */ -var utils = require('./../odatajs/utils.js'); -var oDSxml = require('./../odatajs/xml.js'); +var utils = require('./../utils.js'); +var oDSxml = require('./../xml.js'); var odataHandler = require('./handler.js'); http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/odata/net.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/net.js b/odatajs/src/lib/odata/net.js index 0dbbce0..6e0f6c8 100644 --- a/odatajs/src/lib/odata/net.js +++ b/odatajs/src/lib/odata/net.js @@ -21,7 +21,7 @@ -var utils = require('./../odatajs/utils.js'); +var utils = require('./../utils.js'); // Imports. var defined = utils.defined; http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/87e35975/odatajs/src/lib/odata/odatautils.js ---------------------------------------------------------------------- diff --git a/odatajs/src/lib/odata/odatautils.js b/odatajs/src/lib/odata/odatautils.js new file mode 100644 index 0000000..a44fa05 --- /dev/null +++ b/odatajs/src/lib/odata/odatautils.js @@ -0,0 +1,1265 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + /** @module odata/utils */ + +var utils = require('./../utils.js'); + +// Imports +var assigned = utils.assigned; +var contains = utils.contains; +var find = utils.find; +var isArray = utils.isArray; +var isDate = utils.isDate; +var isObject = utils.isObject; +var parseInt10 = utils.parseInt10; + + +/** Gets the type name of a data item value that belongs to a feed, an entry, a complex type property, or a collection property + * @param {string} value - Value of the data item from which the type name is going to be retrieved. + * @param {object} [metadata] - Object containing metadata about the data tiem. + * @returns {string} Data item type name; null if the type name cannot be found within the value or the metadata + * This function will first try to get the type name from the data item's value itself if it is an object with a __metadata property; otherwise + * it will try to recover it from the metadata. If both attempts fail, it will return null. + */ +var dataItemTypeName = function (value, metadata) { + var valueTypeName = ((value && value.__metadata) || {}).type; + return valueTypeName || (metadata ? metadata.type : null); +}; + +var EDM = "Edm."; +var EDM_BOOLEAN = EDM + "Boolean"; +var EDM_BYTE = EDM + "Byte"; +var EDM_SBYTE = EDM + "SByte"; +var EDM_INT16 = EDM + "Int16"; +var EDM_INT32 = EDM + "Int32"; +var EDM_INT64 = EDM + "Int64"; +var EDM_SINGLE = EDM + "Single"; +var EDM_DOUBLE = EDM + "Double"; +var EDM_DECIMAL = EDM + "Decimal"; +var EDM_STRING = EDM + "String"; + +var EDM_BINARY = EDM + "Binary"; +var EDM_DATE = EDM + "Date"; +var EDM_DATETIMEOFFSET = EDM + "DateTimeOffset"; +var EDM_DURATION = EDM + "Duration"; +var EDM_GUID = EDM + "Guid"; +var EDM_TIMEOFDAY = EDM + "Time"; + +var GEOGRAPHY = "Geography"; +var EDM_GEOGRAPHY = EDM + GEOGRAPHY; +var EDM_GEOGRAPHY_POINT = EDM_GEOGRAPHY + "Point"; +var EDM_GEOGRAPHY_LINESTRING = EDM_GEOGRAPHY + "LineString"; +var EDM_GEOGRAPHY_POLYGON = EDM_GEOGRAPHY + "Polygon"; +var EDM_GEOGRAPHY_COLLECTION = EDM_GEOGRAPHY + "Collection"; +var EDM_GEOGRAPHY_MULTIPOLYGON = EDM_GEOGRAPHY + "MultiPolygon"; +var EDM_GEOGRAPHY_MULTILINESTRING = EDM_GEOGRAPHY + "MultiLineString"; +var EDM_GEOGRAPHY_MULTIPOINT = EDM_GEOGRAPHY + "MultiPoint"; + +var GEOGRAPHY_POINT = GEOGRAPHY + "Point"; +var GEOGRAPHY_LINESTRING = GEOGRAPHY + "LineString"; +var GEOGRAPHY_POLYGON = GEOGRAPHY + "Polygon"; +var GEOGRAPHY_COLLECTION = GEOGRAPHY + "Collection"; +var GEOGRAPHY_MULTIPOLYGON = GEOGRAPHY + "MultiPolygon"; +var GEOGRAPHY_MULTILINESTRING = GEOGRAPHY + "MultiLineString"; +var GEOGRAPHY_MULTIPOINT = GEOGRAPHY + "MultiPoint"; + +var GEOMETRY = "Geometry"; +var EDM_GEOMETRY = EDM + GEOMETRY; +var EDM_GEOMETRY_POINT = EDM_GEOMETRY + "Point"; +var EDM_GEOMETRY_LINESTRING = EDM_GEOMETRY + "LineString"; +var EDM_GEOMETRY_POLYGON = EDM_GEOMETRY + "Polygon"; +var EDM_GEOMETRY_COLLECTION = EDM_GEOMETRY + "Collection"; +var EDM_GEOMETRY_MULTIPOLYGON = EDM_GEOMETRY + "MultiPolygon"; +var EDM_GEOMETRY_MULTILINESTRING = EDM_GEOMETRY + "MultiLineString"; +var EDM_GEOMETRY_MULTIPOINT = EDM_GEOMETRY + "MultiPoint"; + +var GEOMETRY_POINT = GEOMETRY + "Point"; +var GEOMETRY_LINESTRING = GEOMETRY + "LineString"; +var GEOMETRY_POLYGON = GEOMETRY + "Polygon"; +var GEOMETRY_COLLECTION = GEOMETRY + "Collection"; +var GEOMETRY_MULTIPOLYGON = GEOMETRY + "MultiPolygon"; +var GEOMETRY_MULTILINESTRING = GEOMETRY + "MultiLineString"; +var GEOMETRY_MULTIPOINT = GEOMETRY + "MultiPoint"; + +var GEOJSON_POINT = "Point"; +var GEOJSON_LINESTRING = "LineString"; +var GEOJSON_POLYGON = "Polygon"; +var GEOJSON_MULTIPOINT = "MultiPoint"; +var GEOJSON_MULTILINESTRING = "MultiLineString"; +var GEOJSON_MULTIPOLYGON = "MultiPolygon"; +var GEOJSON_GEOMETRYCOLLECTION = "GeometryCollection"; + +var primitiveEdmTypes = [ + EDM_STRING, + EDM_INT32, + EDM_INT64, + EDM_BOOLEAN, + EDM_DOUBLE, + EDM_SINGLE, + EDM_DATE, + EDM_DATETIMEOFFSET, + EDM_DURATION, + EDM_TIMEOFDAY, + EDM_DECIMAL, + EDM_GUID, + EDM_BYTE, + EDM_INT16, + EDM_SBYTE, + EDM_BINARY +]; + +var geometryEdmTypes = [ + EDM_GEOMETRY, + EDM_GEOMETRY_POINT, + EDM_GEOMETRY_LINESTRING, + EDM_GEOMETRY_POLYGON, + EDM_GEOMETRY_COLLECTION, + EDM_GEOMETRY_MULTIPOLYGON, + EDM_GEOMETRY_MULTILINESTRING, + EDM_GEOMETRY_MULTIPOINT +]; + +var geometryTypes = [ + GEOMETRY, + GEOMETRY_POINT, + GEOMETRY_LINESTRING, + GEOMETRY_POLYGON, + GEOMETRY_COLLECTION, + GEOMETRY_MULTIPOLYGON, + GEOMETRY_MULTILINESTRING, + GEOMETRY_MULTIPOINT +]; + +var geographyEdmTypes = [ + EDM_GEOGRAPHY, + EDM_GEOGRAPHY_POINT, + EDM_GEOGRAPHY_LINESTRING, + EDM_GEOGRAPHY_POLYGON, + EDM_GEOGRAPHY_COLLECTION, + EDM_GEOGRAPHY_MULTIPOLYGON, + EDM_GEOGRAPHY_MULTILINESTRING, + EDM_GEOGRAPHY_MULTIPOINT +]; + +var geographyTypes = [ + GEOGRAPHY, + GEOGRAPHY_POINT, + GEOGRAPHY_LINESTRING, + GEOGRAPHY_POLYGON, + GEOGRAPHY_COLLECTION, + GEOGRAPHY_MULTIPOLYGON, + GEOGRAPHY_MULTILINESTRING, + GEOGRAPHY_MULTIPOINT +]; + +/** Invokes a function once per schema in metadata. + * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. + * @param {Function} callback - Callback function to invoke once per schema. + * @returns The first truthy value to be returned from the callback; null or the last falsy value otherwise. + */ +function forEachSchema(metadata, callback) { + + + if (!metadata) { + return null; + } + + if (isArray(metadata)) { + var i, len, result; + for (i = 0, len = metadata.length; i < len; i++) { + result = forEachSchema(metadata[i], callback); + if (result) { + return result; + } + } + + return null; + } else { + if (metadata.dataServices) { + return forEachSchema(metadata.dataServices.schema, callback); + } + + return callback(metadata); + } +} + +/** Formats a millisecond and a nanosecond value into a single string. + * @param {Numaber} ms - Number of milliseconds to format.</param> + * @param {Numaber} ns - Number of nanoseconds to format.</param> + * @returns {String} Formatted text. + * If the value is already as string it's returned as-is.</remarks> + */ +function formatMilliseconds(ms, ns) { + + // Avoid generating milliseconds if not necessary. + if (ms === 0) { + ms = ""; + } else { + ms = "." + formatNumberWidth(ms.toString(), 3); + } + if (ns > 0) { + if (ms === "") { + ms = ".000"; + } + ms += formatNumberWidth(ns.toString(), 4); + } + return ms; +} + +function formatDateTimeOffsetJSON(value) { + return "\/Date(" + value.getTime() + ")\/"; +} + +/** Formats a DateTime or DateTimeOffset value a string. + * @param {Date} value - Value to format + * @returns {String} Formatted text. + * If the value is already as string it's returned as-is +´*/ +function formatDateTimeOffset(value) { + + if (typeof value === "string") { + return value; + } + + var hasOffset = isDateTimeOffset(value); + var offset = getCanonicalTimezone(value.__offset); + if (hasOffset && offset !== "Z") { + // We're about to change the value, so make a copy. + value = new Date(value.valueOf()); + + var timezone = parseTimezone(offset); + var hours = value.getUTCHours() + (timezone.d * timezone.h); + var minutes = value.getUTCMinutes() + (timezone.d * timezone.m); + + value.setUTCHours(hours, minutes); + } else if (!hasOffset) { + // Don't suffix a 'Z' for Edm.DateTime values. + offset = ""; + } + + var year = value.getUTCFullYear(); + var month = value.getUTCMonth() + 1; + var sign = ""; + if (year <= 0) { + year = -(year - 1); + sign = "-"; + } + + var ms = formatMilliseconds(value.getUTCMilliseconds(), value.__ns); + + return sign + + formatNumberWidth(year, 4) + "-" + + formatNumberWidth(month, 2) + "-" + + formatNumberWidth(value.getUTCDate(), 2) + "T" + + formatNumberWidth(value.getUTCHours(), 2) + ":" + + formatNumberWidth(value.getUTCMinutes(), 2) + ":" + + formatNumberWidth(value.getUTCSeconds(), 2) + + ms + offset; +} + +/** Converts a duration to a string in xsd:duration format. + * @param {Object} value - Object with ms and __edmType properties. + * @returns {String} String representation of the time object in xsd:duration format. + */ +function formatDuration(value) { + + var ms = value.ms; + + var sign = ""; + if (ms < 0) { + sign = "-"; + ms = -ms; + } + + var days = Math.floor(ms / 86400000); + ms -= 86400000 * days; + var hours = Math.floor(ms / 3600000); + ms -= 3600000 * hours; + var minutes = Math.floor(ms / 60000); + ms -= 60000 * minutes; + var seconds = Math.floor(ms / 1000); + ms -= seconds * 1000; + + return sign + "P" + + formatNumberWidth(days, 2) + "DT" + + formatNumberWidth(hours, 2) + "H" + + formatNumberWidth(minutes, 2) + "M" + + formatNumberWidth(seconds, 2) + + formatMilliseconds(ms, value.ns) + "S"; +} + +/** Formats the specified value to the given width. + * @param {Number} value - Number to format (non-negative). + * @param {Number} width - Minimum width for number. + * @param {Boolean} append - Flag indicating if the value is padded at the beginning (false) or at the end (true). + * @returns {String} Text representation. + */ +function formatNumberWidth(value, width, append) { + var result = value.toString(10); + while (result.length < width) { + if (append) { + result += "0"; + } else { + result = "0" + result; + } + } + + return result; +} + +/** Gets the canonical timezone representation. + * @param {String} timezone - Timezone representation. + * @returns {String} An 'Z' string if the timezone is absent or 0; the timezone otherwise. + */ +function getCanonicalTimezone(timezone) { + + return (!timezone || timezone === "Z" || timezone === "+00:00" || timezone === "-00:00") ? "Z" : timezone; +} + +/** Gets the type of a collection type name. + * @param {String} typeName - Type name of the collection. + * @returns {String} Type of the collection; null if the type name is not a collection type. + */ +function getCollectionType(typeName) { + + if (typeof typeName === "string") { + var end = typeName.indexOf(")", 10); + if (typeName.indexOf("Collection(") === 0 && end > 0) { + return typeName.substring(11, end); + } + } + return null; +} + +/** Sends a request containing OData payload to a server. +* @param request - Object that represents the request to be sent.. +* @param success - Callback for a successful read operation. +* @param error - Callback for handling errors. +* @param handler - Handler for data serialization. +* @param httpClient - HTTP client layer. +* @param context - Context used for processing the request +*/ +function invokeRequest(request, success, error, handler, httpClient, context) { + + return httpClient.request(request, function (response) { + try { + if (response.headers) { + normalizeHeaders(response.headers); + } + + if (response.data === undefined && response.statusCode !== 204) { + handler.read(response, context); + } + } catch (err) { + if (err.request === undefined) { + err.request = request; + } + if (err.response === undefined) { + err.response = response; + } + error(err); + return; + } + // errors in success handler for sync requests result in error handler calls. So here we fix this. + try { + success(response.data, response); + } catch (err) { + err.bIsSuccessHandlerError = true; + throw err; + } + }, error); +} + +/** Tests whether a value is a batch object in the library's internal representation. + * @param value - Value to test. + * @returns {Boolean} True is the value is a batch object; false otherwise. + */ +function isBatch(value) { + + return isComplex(value) && isArray(value.__batchRequests); +} + +// Regular expression used for testing and parsing for a collection type. +var collectionTypeRE = /Collection\((.*)\)/; + +/** Tests whether a value is a collection value in the library's internal representation. + * @param value - Value to test. + * @param {Sting} typeName - Type name of the value. This is used to disambiguate from a collection property value. + * @returns {Boolean} True is the value is a feed value; false otherwise. + */ +function isCollection(value, typeName) { + + var colData = value && value.results || value; + return !!colData && + (isCollectionType(typeName)) || + (!typeName && isArray(colData) && !isComplex(colData[0])); +} + +/** Checks whether the specified type name is a collection type. + * @param {String} typeName - Name of type to check. + * @returns {Boolean} True if the type is the name of a collection type; false otherwise. + */ +function isCollectionType(typeName) { + return collectionTypeRE.test(typeName); +} + +/** Tests whether a value is a complex type value in the library's internal representation. + * @param value - Value to test. + * @returns {Boolean} True is the value is a complex type value; false otherwise. + */ +function isComplex(value) { + + return !!value && + isObject(value) && + !isArray(value) && + !isDate(value); +} + +/** Checks whether a Date object is DateTimeOffset value + * @param {Date} value - Value to check + * @returns {Boolean} true if the value is a DateTimeOffset, false otherwise. + */ +function isDateTimeOffset(value) { + return (value.__edmType === "Edm.DateTimeOffset" || (!value.__edmType && value.__offset)); +} + +/** Tests whether a value is a deferred navigation property in the library's internal representation. + * @param value - Value to test. + * @returns {Boolean} True is the value is a deferred navigation property; false otherwise. + */ +function isDeferred(value) { + + if (!value && !isComplex(value)) { + return false; + } + var metadata = value.__metadata || {}; + var deferred = value.__deferred || {}; + return !metadata.type && !!deferred.uri; +} + +/** Tests whether a value is an entry object in the library's internal representation. + * @param value - Value to test. + * @returns {Boolean} True is the value is an entry object; false otherwise. + */ +function isEntry(value) { + + return isComplex(value) && value.__metadata && "uri" in value.__metadata; +} + +/** Tests whether a value is a feed value in the library's internal representation. + * @param value - Value to test. + * @param {Sting} typeName - Type name of the value. This is used to disambiguate from a collection property value. + * @returns {Boolean} True is the value is a feed value; false otherwise. + */ +function isFeed(value, typeName) { + + var feedData = value && value.results || value; + return isArray(feedData) && ( + (!isCollectionType(typeName)) && + (isComplex(feedData[0])) + ); +} + +/** Checks whether the specified type name is a geography EDM type. + * @param {String} typeName - Name of type to check. + * @returns {Boolean} True if the type is a geography EDM type; false otherwise. + */ +function isGeographyEdmType(typeName) { + + //check with edm + var ret = contains(geographyEdmTypes, typeName) || + (typeName.indexOf('.') === -1 && contains(geographyTypes, typeName)); + return ret; + +} + +/** Checks whether the specified type name is a geometry EDM type. + * @param {String} typeName - Name of type to check. + * @returns {Boolean} True if the type is a geometry EDM type; false otherwise. + */ +function isGeometryEdmType(typeName) { + + var ret = contains(geometryEdmTypes, typeName) || + (typeName.indexOf('.') === -1 && contains(geometryTypes, typeName)); + return ret; +} + +/** Tests whether a value is a named stream value in the library's internal representation. + * @param value - Value to test. + * @returns {Boolean} True is the value is a named stream; false otherwise. + */ +function isNamedStream(value) { + + if (!value && !isComplex(value)) { + return false; + } + var metadata = value.__metadata; + var mediaResource = value.__mediaresource; + return !metadata && !!mediaResource && !!mediaResource.media_src; +} + +/** Tests whether a value is a primitive type value in the library's internal representation. + * @param value - Value to test. + * @returns {Boolean} True is the value is a primitive type value. + * Date objects are considered primitive types by the library. + */ +function isPrimitive(value) { + + return isDate(value) || + typeof value === "string" || + typeof value === "number" || + typeof value === "boolean"; +} + +/** Checks whether the specified type name is a primitive EDM type. + * @param {String} typeName - Name of type to check. + * @returns {Boolean} True if the type is a primitive EDM type; false otherwise. + */ +function isPrimitiveEdmType(typeName) { + + return contains(primitiveEdmTypes, typeName); +} + +/** Gets the kind of a navigation property value. + * @param value - Value of the navigation property. + * @param {Object} [propertyModel] - Object that describes the navigation property in an OData conceptual schema. + * @returns {String} String value describing the kind of the navigation property; null if the kind cannot be determined. + */ +function navigationPropertyKind(value, propertyModel) { + + if (isDeferred(value)) { + return "deferred"; + } + if (isEntry(value)) { + return "entry"; + } + if (isFeed(value)) { + return "feed"; + } + if (propertyModel && propertyModel.relationship) { + if (value === null || value === undefined || !isFeed(value)) { + return "entry"; + } + return "feed"; + } + return null; +} + +/** Looks up a property by name. + * @param {Array} properties - Array of property objects as per EDM metadata (may be null) + * @param {String} name - Name to look for. + * @returns {Object} The property object; null if not found. + */ +function lookupProperty(properties, name) { + + return find(properties, function (property) { + return property.name === name; + }); +} + +/** Looks up a type object by name. + * @param {String} name - Name, possibly null or empty. + * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. + * @param {String} kind - Kind of object to look for as per EDM metadata. + * @returns An type description if the name is found; null otherwise + */ +function lookupInMetadata(name, metadata, kind) { + + return (name) ? forEachSchema(metadata, function (schema) { + return lookupInSchema(name, schema, kind); + }) : null; +} + +/** Looks up a entity set by name. + * @param {Array} properties - Array of entity set objects as per EDM metadata( may be null) + * @param {String} name - Name to look for. + * @returns {Object} The entity set object; null if not found. + */ +function lookupEntitySet(entitySets, name) { + + return find(entitySets, function (entitySet) { + return entitySet.name === name; + }); +} + +/** Looks up a entity set by name. + * @param {Array} properties - Array of entity set objects as per EDM metadata (may be null) + * @param {String} name - Name to look for. + * @returns {Object} The entity set object; null if not found. + */ +function lookupSingleton(singletons, name) { + + return find(singletons, function (singleton) { + return singleton.name === name; + }); +} + +/** Looks up a complex type object by name. + * @param {String} name - Name, possibly null or empty. + * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. + * @returns A complex type description if the name is found; null otherwise.</returns> + */ +function lookupComplexType(name, metadata) { + + return lookupInMetadata(name, metadata, "complexType"); +} + +/** Looks up an entity type object by name. + * @param {String} name - Name, possibly null or empty. + * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. + * @returns An entity type description if the name is found; null otherwise.</returns> + */ +function lookupEntityType(name, metadata) { + + return lookupInMetadata(name, metadata, "entityType"); +} + + +/** Looks up an + * @param {String} name - Name, possibly null or empty. + * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. + * @returns An entity container description if the name is found; null otherwise.</returns> + */ +function lookupDefaultEntityContainer(metadata) { + + return forEachSchema(metadata, function (schema) { + if (isObject(schema.entityContainer)) { + return schema.entityContainer; + } + }); +} + +/** Looks up an entity container object by name. + * @param {String} name - Name, possibly null or empty. + * @param metadata - Metadata store; one of edmx, schema, or an array of any of them. + * @returns An entity container description if the name is found; null otherwise.</returns> + */ +function lookupEntityContainer(name, metadata) { + + return lookupInMetadata(name, metadata, "entityContainer"); +} + +/** Looks up a function import by name. + * @param {Array} properties - Array of function import objects as per EDM metadata (May be null) + * @param {String} name - Name to look for. + * @returns {Object} The entity set object; null if not found. + */ +function lookupFunctionImport(functionImports, name) { + return find(functionImports, function (functionImport) { + return functionImport.name === name; + }); +} + +/** Looks up the target entity type for a navigation property. + * @param {Object} navigationProperty - + * @param {Object} metadata - + * @returns {String} The entity type name for the specified property, null if not found. + */ +function lookupNavigationPropertyType(navigationProperty, metadata) { + + var result = null; + if (navigationProperty) { + var rel = navigationProperty.relationship; + var association = forEachSchema(metadata, function (schema) { + // The name should be the namespace qualified name in 'ns'.'type' format. + var nameOnly = removeNamespace(schema.namespace, rel); + var associations = schema.association; + if (nameOnly && associations) { + var i, len; + for (i = 0, len = associations.length; i < len; i++) { + if (associations[i].name === nameOnly) { + return associations[i]; + } + } + } + return null; + }); + + if (association) { + var end = association.end[0]; + if (end.role !== navigationProperty.toRole) { + end = association.end[1]; + // For metadata to be valid, end.role === navigationProperty.toRole now. + } + result = end.type; + } + } + return result; +} + +/** Looks up the target entityset name for a navigation property. + * @param {Object} navigationProperty - + * @param {Object} metadata - + * @returns {String} The entityset name for the specified property, null if not found. + */ +function lookupNavigationPropertyEntitySet(navigationProperty, sourceEntitySetName, metadata) { + + if (navigationProperty) { + var rel = navigationProperty.relationship; + var associationSet = forEachSchema(metadata, function (schema) { + var containers = schema.entityContainer; + for (var i = 0; i < containers.length; i++) { + var associationSets = containers[i].associationSet; + if (associationSets) { + for (var j = 0; j < associationSets.length; j++) { + if (associationSets[j].association == rel) { + return associationSets[j]; + } + } + } + } + return null; + }); + if (associationSet && associationSet.end[0] && associationSet.end[1]) { + return (associationSet.end[0].entitySet == sourceEntitySetName) ? associationSet.end[1].entitySet : associationSet.end[0].entitySet; + } + } + return null; +} + +/** Gets the entitySet info, container name and functionImports for an entitySet + * @param {Object} navigationProperty - + * @param {Object} metadata - + * @returns {Object} The info about the entitySet. + */ +function getEntitySetInfo(entitySetName, metadata) { + + var info = forEachSchema(metadata, function (schema) { + var container = schema.entityContainer; + var entitySets = container.entitySet; + if (entitySets) { + for (var j = 0; j < entitySets.length; j++) { + if (entitySets[j].name == entitySetName) { + return { entitySet: entitySets[j], containerName: container.name, functionImport: container.functionImport }; + } + } + } + return null; + }); + + return info; +} + +/** Given an expected namespace prefix, removes it from a full name. + * @param {String} ns - Expected namespace. + * @param {String} fullName - Full name in 'ns'.'name' form. + * @returns {String} The local name, null if it isn't found in the expected namespace. + */ +function removeNamespace(ns, fullName) { + + if (fullName.indexOf(ns) === 0 && fullName.charAt(ns.length) === ".") { + return fullName.substr(ns.length + 1); + } + + return null; +} + +/** Looks up a schema object by name. + * @param {String} name - Name (assigned). + * @param schema - Schema object as per EDM metadata. + * @param {String} kind - Kind of object to look for as per EDM metadata. + * @returns An entity type description if the name is found; null otherwise.</returns> + */ +function lookupInSchema(name, schema, kind) { + + if (name && schema) { + // The name should be the namespace qualified name in 'ns'.'type' format. + var nameOnly = removeNamespace(schema.namespace, name); + if (nameOnly) { + return find(schema[kind], function (item) { + return item.name === nameOnly; + }); + } + } + return null; +} + +/** Compares to version strings and returns the higher one. + * @param {String} left - Version string in the form "major.minor.rev" + * @param {String} right - Version string in the form "major.minor.rev" + * @returns {String} The higher version string. + */ +function maxVersion(left, right) { + + if (left === right) { + return left; + } + + var leftParts = left.split("."); + var rightParts = right.split("."); + + var len = (leftParts.length >= rightParts.length) ? + leftParts.length : + rightParts.length; + + for (var i = 0; i < len; i++) { + var leftVersion = leftParts[i] && parseInt10(leftParts[i]); + var rightVersion = rightParts[i] && parseInt10(rightParts[i]); + if (leftVersion > rightVersion) { + return left; + } + if (leftVersion < rightVersion) { + return right; + } + } +} + +var normalHeaders = { + // Headers shared by request and response + "content-type": "Content-Type", + "content-encoding": "Content-Encoding", + "content-length": "Content-Length", + "odata-version": "OData-Version", + + // Headers used by request + "accept": "Accept", + "accept-charset": "Accept-Charset", + "if-match": "If-Match", + "if-none-match": "If-None-Match", + "odata-isolation": "OData-Isolation", + "odata-maxversion": "OData-MaxVersion", + "prefer": "Prefer", + "content-id": "Content-ID", + "content-transfer-encoding": "Content-Transfer-Encoding", + + // Headers used by response + "etag": "ETag", + "location": "Location", + "odata-entityid": "OData-EntityId", + "preference-applied": "Preference-Applied", + "retry-after": "Retry-After" +}; + +/** Normalizes headers so they can be found with consistent casing. + * @param {Object} headers - Dictionary of name/value pairs. + */ +function normalizeHeaders(headers) { + + for (var name in headers) { + var lowerName = name.toLowerCase(); + var normalName = normalHeaders[lowerName]; + if (normalName && name !== normalName) { + var val = headers[name]; + delete headers[name]; + headers[normalName] = val; + } + } +} + +/** Parses a string into a boolean value. + * @param propertyValue - Value to parse. + * @returns {Boolean} true if the property value is 'true'; false otherwise. + */ +function parseBool(propertyValue) { + + if (typeof propertyValue === "boolean") { + return propertyValue; + } + + return typeof propertyValue === "string" && propertyValue.toLowerCase() === "true"; +} + + +// The captured indices for this expression are: +// 0 - complete input +// 1,2,3 - year with optional minus sign, month, day +// 4,5,6 - hours, minutes, seconds +// 7 - optional milliseconds +// 8 - everything else (presumably offset information) +var parseDateTimeRE = /^(-?\d{4,})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?(?:\.(\d+))?(.*)$/; + +/** Parses a string into a DateTime value. + * @param {String} value - Value to parse. + * @param {Boolean} withOffset - Whether offset is expected. + * @returns {Date} The parsed value. + */ +function parseDateTimeMaybeOffset(value, withOffset, nullOnError) { + + // We cannot parse this in cases of failure to match or if offset information is specified. + var parts = parseDateTimeRE.exec(value); + var offset = (parts) ? getCanonicalTimezone(parts[8]) : null; + + if (!parts || (!withOffset && offset !== "Z")) { + if (nullOnError) { + return null; + } + throw { message: "Invalid date/time value" }; + } + + // Pre-parse years, account for year '0' being invalid in dateTime. + var year = parseInt10(parts[1]); + if (year <= 0) { + year++; + } + + // Pre-parse optional milliseconds, fill in default. Fail if value is too precise. + var ms = parts[7]; + var ns = 0; + if (!ms) { + ms = 0; + } else { + if (ms.length > 7) { + if (nullOnError) { + return null; + } + throw { message: "Cannot parse date/time value to given precision." }; + } + + ns = formatNumberWidth(ms.substring(3), 4, true); + ms = formatNumberWidth(ms.substring(0, 3), 3, true); + + ms = parseInt10(ms); + ns = parseInt10(ns); + } + + // Pre-parse other time components and offset them if necessary. + var hours = parseInt10(parts[4]); + var minutes = parseInt10(parts[5]); + var seconds = parseInt10(parts[6]) || 0; + if (offset !== "Z") { + // The offset is reversed to get back the UTC date, which is + // what the API will eventually have. + var timezone = parseTimezone(offset); + var direction = -(timezone.d); + hours += timezone.h * direction; + minutes += timezone.m * direction; + } + + // Set the date and time separately with setFullYear, so years 0-99 aren't biased like in Date.UTC. + var result = new Date(); + result.setUTCFullYear( + year, // Year. + parseInt10(parts[2]) - 1, // Month (zero-based for Date.UTC and setFullYear). + parseInt10(parts[3]) // Date. + ); + result.setUTCHours(hours, minutes, seconds, ms); + + if (isNaN(result.valueOf())) { + if (nullOnError) { + return null; + } + throw { message: "Invalid date/time value" }; + } + + if (withOffset) { + result.__edmType = "Edm.DateTimeOffset"; + result.__offset = offset; + } + + if (ns) { + result.__ns = ns; + } + + return result; +} + +/** Parses a string into a Date object. + * @param {String} propertyValue - Value to parse. + * @returns {Date} The parsed with year, month, day set, time values are set to 0 + */ +function parseDate(propertyValue, nullOnError) { + var parts = propertyValue.split('-'); + + if (parts.length != 3 && nullOnError) { + return null; + } + return new Date( + parseInt10(parts[0]), // Year. + parseInt10(parts[1]) - 1, // Month (zero-based for Date.UTC and setFullYear). + parseInt10(parts[2], + 0,0,0,0) // Date. + ); + +} + +var parseTimeOfDayRE = /^(\d+):(\d+)(:(\d+)(.(\d+))?)?$/; + +function parseTimeOfDay(propertyValue, nullOnError) { + var parts = parseTimeOfDayRE.exec(propertyValue); + + + return { + 'h' :parseInt10(parts[1]), + 'm' :parseInt10(parts[2]), + 's' :parseInt10(parts[4]), + 'ms' :parseInt10(parts[6]), + }; +} + +/** Parses a string into a DateTimeOffset value. + * @param {String} propertyValue - Value to parse. + * @returns {Date} The parsed value. + + + * The resulting object is annotated with an __edmType property and + * an __offset property reflecting the original intended offset of + * the value. The time is adjusted for UTC time, as the current + * timezone-aware Date APIs will only work with the local timezone. + */ +function parseDateTimeOffset(propertyValue, nullOnError) { + + + return parseDateTimeMaybeOffset(propertyValue, true, nullOnError); +} + +// The captured indices for this expression are: +// 0 - complete input +// 1 - direction +// 2,3,4 - years, months, days +// 5,6,7,8 - hours, minutes, seconds, miliseconds + +var parseTimeRE = /^([+-])?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?/; + +function isEdmDurationValue(value) { + parseTimeRE.test(value); +} + +/** Parses a string in xsd:duration format. + * @param {String} duration - Duration value. + + * This method will throw an exception if the input string has a year or a month component. + + * @returns {Object} Object representing the time + */ +function parseDuration(duration) { + + var parts = parseTimeRE.exec(duration); + + if (parts === null) { + throw { message: "Invalid duration value." }; + } + + var years = parts[2] || "0"; + var months = parts[3] || "0"; + var days = parseInt10(parts[4] || 0); + var hours = parseInt10(parts[5] || 0); + var minutes = parseInt10(parts[6] || 0); + var seconds = parseFloat(parts[7] || 0); + + if (years !== "0" || months !== "0") { + throw { message: "Unsupported duration value." }; + } + + var ms = parts[8]; + var ns = 0; + if (!ms) { + ms = 0; + } else { + if (ms.length > 7) { + throw { message: "Cannot parse duration value to given precision." }; + } + + ns = formatNumberWidth(ms.substring(3), 4, true); + ms = formatNumberWidth(ms.substring(0, 3), 3, true); + + ms = parseInt10(ms); + ns = parseInt10(ns); + } + + ms += seconds * 1000 + minutes * 60000 + hours * 3600000 + days * 86400000; + + if (parts[1] === "-") { + ms = -ms; + } + + var result = { ms: ms, __edmType: "Edm.Time" }; + + if (ns) { + result.ns = ns; + } + return result; +} + +/** Parses a timezone description in (+|-)nn:nn format. + * @param {String} timezone - Timezone offset. + * @returns {Object} An object with a (d)irection property of 1 for + and -1 for -, offset (h)ours and offset (m)inutes. + */ +function parseTimezone(timezone) { + + var direction = timezone.substring(0, 1); + direction = (direction === "+") ? 1 : -1; + + var offsetHours = parseInt10(timezone.substring(1)); + var offsetMinutes = parseInt10(timezone.substring(timezone.indexOf(":") + 1)); + return { d: direction, h: offsetHours, m: offsetMinutes }; +} + +/** Prepares a request object so that it can be sent through the network. +* @param request - Object that represents the request to be sent. +* @param handler - Handler for data serialization +* @param context - Context used for preparing the request +*/ +function prepareRequest(request, handler, context) { + + // Default to GET if no method has been specified. + if (!request.method) { + request.method = "GET"; + } + + if (!request.headers) { + request.headers = {}; + } else { + normalizeHeaders(request.headers); + } + + if (request.headers.Accept === undefined) { + request.headers.Accept = handler.accept; + } + + if (assigned(request.data) && request.body === undefined) { + handler.write(request, context); + } + + if (!assigned(request.headers["OData-MaxVersion"])) { + request.headers["OData-MaxVersion"] = handler.maxDataServiceVersion || "4.0"; + } + + if (request.async === undefined) { + request.async = true; + } + +} + +/** Traverses a tree of objects invoking callback for every value. + * @param {Object} item - Object or array to traverse. + * @param {Function} callback - Callback function with key and value, similar to JSON.parse reviver. + * @returns {Object} The object with traversed properties. + Unlike the JSON reviver, this won't delete null members.</remarks> +*/ +function traverseInternal(item, owner, callback) { + + if (item && typeof item === "object") { + for (var name in item) { + var value = item[name]; + var result = traverseInternal(value, name, callback); + result = callback(name, result, owner); + if (result !== value) { + if (value === undefined) { + delete item[name]; + } else { + item[name] = result; + } + } + } + } + + return item; +} + +/** Traverses a tree of objects invoking callback for every value. + * @param {Object} item - Object or array to traverse. + * @param {Function} callback - Callback function with key and value, similar to JSON.parse reviver. + * @returns {Object} The traversed object. + * Unlike the JSON reviver, this won't delete null members.</remarks> +*/ +function traverse(item, callback) { + + return callback("", traverseInternal(item, "", callback)); +} + +exports.dataItemTypeName = dataItemTypeName; +exports.EDM_BINARY = EDM_BINARY; +exports.EDM_BOOLEAN = EDM_BOOLEAN; +exports.EDM_BYTE = EDM_BYTE; +exports.EDM_DATE = EDM_DATE; +exports.EDM_DATETIMEOFFSET = EDM_DATETIMEOFFSET; +exports.EDM_DURATION = EDM_DURATION; +exports.EDM_DECIMAL = EDM_DECIMAL; +exports.EDM_DOUBLE = EDM_DOUBLE; +exports.EDM_GEOGRAPHY = EDM_GEOGRAPHY; +exports.EDM_GEOGRAPHY_POINT = EDM_GEOGRAPHY_POINT; +exports.EDM_GEOGRAPHY_LINESTRING = EDM_GEOGRAPHY_LINESTRING; +exports.EDM_GEOGRAPHY_POLYGON = EDM_GEOGRAPHY_POLYGON; +exports.EDM_GEOGRAPHY_COLLECTION = EDM_GEOGRAPHY_COLLECTION; +exports.EDM_GEOGRAPHY_MULTIPOLYGON = EDM_GEOGRAPHY_MULTIPOLYGON; +exports.EDM_GEOGRAPHY_MULTILINESTRING = EDM_GEOGRAPHY_MULTILINESTRING; +exports.EDM_GEOGRAPHY_MULTIPOINT = EDM_GEOGRAPHY_MULTIPOINT; +exports.EDM_GEOMETRY = EDM_GEOMETRY; +exports.EDM_GEOMETRY_POINT = EDM_GEOMETRY_POINT; +exports.EDM_GEOMETRY_LINESTRING = EDM_GEOMETRY_LINESTRING; +exports.EDM_GEOMETRY_POLYGON = EDM_GEOMETRY_POLYGON; +exports.EDM_GEOMETRY_COLLECTION = EDM_GEOMETRY_COLLECTION; +exports.EDM_GEOMETRY_MULTIPOLYGON = EDM_GEOMETRY_MULTIPOLYGON; +exports.EDM_GEOMETRY_MULTILINESTRING = EDM_GEOMETRY_MULTILINESTRING; +exports.EDM_GEOMETRY_MULTIPOINT = EDM_GEOMETRY_MULTIPOINT; +exports.EDM_GUID = EDM_GUID; +exports.EDM_INT16 = EDM_INT16; +exports.EDM_INT32 = EDM_INT32; +exports.EDM_INT64 = EDM_INT64; +exports.EDM_SBYTE = EDM_SBYTE; +exports.EDM_SINGLE = EDM_SINGLE; +exports.EDM_STRING = EDM_STRING; +exports.EDM_TIMEOFDAY = EDM_TIMEOFDAY; +exports.GEOJSON_POINT = GEOJSON_POINT; +exports.GEOJSON_LINESTRING = GEOJSON_LINESTRING; +exports.GEOJSON_POLYGON = GEOJSON_POLYGON; +exports.GEOJSON_MULTIPOINT = GEOJSON_MULTIPOINT; +exports.GEOJSON_MULTILINESTRING = GEOJSON_MULTILINESTRING; +exports.GEOJSON_MULTIPOLYGON = GEOJSON_MULTIPOLYGON; +exports.GEOJSON_GEOMETRYCOLLECTION = GEOJSON_GEOMETRYCOLLECTION; +exports.forEachSchema = forEachSchema; +exports.formatDateTimeOffset = formatDateTimeOffset; +exports.formatDateTimeOffsetJSON = formatDateTimeOffsetJSON; +exports.formatDuration = formatDuration; +exports.formatNumberWidth = formatNumberWidth; +exports.getCanonicalTimezone = getCanonicalTimezone; +exports.getCollectionType = getCollectionType; +exports.invokeRequest = invokeRequest; +exports.isBatch = isBatch; +exports.isCollection = isCollection; +exports.isCollectionType = isCollectionType; +exports.isComplex = isComplex; +exports.isDateTimeOffset = isDateTimeOffset; +exports.isDeferred = isDeferred; +exports.isEntry = isEntry; +exports.isFeed = isFeed; +exports.isGeographyEdmType = isGeographyEdmType; +exports.isGeometryEdmType = isGeometryEdmType; +exports.isNamedStream = isNamedStream; +exports.isPrimitive = isPrimitive; +exports.isPrimitiveEdmType = isPrimitiveEdmType; +exports.lookupComplexType = lookupComplexType; +exports.lookupDefaultEntityContainer = lookupDefaultEntityContainer; +exports.lookupEntityContainer = lookupEntityContainer; +exports.lookupEntitySet = lookupEntitySet; +exports.lookupSingleton = lookupSingleton; +exports.lookupEntityType = lookupEntityType; +exports.lookupFunctionImport = lookupFunctionImport; +exports.lookupNavigationPropertyType = lookupNavigationPropertyType; +exports.lookupNavigationPropertyEntitySet = lookupNavigationPropertyEntitySet; +exports.lookupInSchema = lookupInSchema; +exports.lookupProperty = lookupProperty; +exports.lookupInMetadata = lookupInMetadata; +exports.getEntitySetInfo = getEntitySetInfo; +exports.maxVersion = maxVersion; +exports.navigationPropertyKind = navigationPropertyKind; +exports.normalizeHeaders = normalizeHeaders; +exports.parseBool = parseBool; + + +exports.parseDate = parseDate; +exports.parseDateTimeOffset = parseDateTimeOffset; +exports.parseDuration = parseDuration; +exports.parseTimeOfDay = parseTimeOfDay; + +exports.parseInt10 = parseInt10; +exports.prepareRequest = prepareRequest; +exports.removeNamespace = removeNamespace; +exports.traverse = traverse; +
