diff src/implab/Uri.js @ 0:fc2517695ee1

Initial commit, draft import of existing work
author cin
date Thu, 01 Jun 2017 13:20:03 +0300
parents
children 00779cb63b12
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/implab/Uri.js	Thu Jun 01 13:20:03 2017 +0300
@@ -0,0 +1,232 @@
+define(
+    [ "dojo/_base/declare" ],
+    function(declare) {
+        function parseURI(uri) {
+            var schema, host, port, path, query, hash, i;
+            if (typeof (uri) == "string") {
+                if ((i = uri.indexOf(":")) >= 0 &&
+                    uri.substr(0, i).match(/^\w+$/)) {
+                    schema = uri.substr(0, i);
+                    uri = uri.substr(i + 1);
+                }
+
+                if (uri.indexOf("//") === 0) {
+                    uri = uri.substr(2);
+                    if ((i = uri.indexOf("/")) >= 0) {
+                        host = uri.substr(0, i);
+                        uri = uri.substr(i);
+                    } else {
+                        host = uri;
+                        uri = "";
+                    }
+                }
+
+                if ((i = uri.indexOf("?")) >= 0) {
+                    path = uri.substr(0, i);
+                    uri = uri.substr(i + 1);
+
+                } else {
+                    path = uri;
+                    uri = "";
+
+                    if ((i = path.indexOf("#")) >= 0) {
+                        hash = path.substr(i + 1);
+                        path = path.substr(0, i);
+                    }
+                }
+
+                if ((i = uri.indexOf("#")) >= 0) {
+                    query = uri.substr(0, i);
+                    hash = uri.substr(i + 1);
+                } else {
+                    query = uri;
+                }
+            }
+
+            if (host && (i = host.lastIndexOf(":")) >= 0) {
+                port = host.substr(i + 1);
+                host = host.substr(0, i);
+            }
+
+            return {
+                schema : schema,
+                host : host,
+                port : port,
+                path : path,
+                query : query,
+                hash : hash
+            };
+        }
+
+        function makeURI(options) {
+            var uri = [];
+
+            if (options.schema)
+                uri.push(options.schema, ":");
+            if (options.host)
+                uri.push("//", options.host);
+            if (options.host && options.port)
+                uri.push(":", options.port);
+
+            if (options.path) {
+                if (options.host && options.path[0] != "/")
+                    uri.push("/");
+                uri.push(options.path);
+            } else if (options.host) {
+                uri.push("/");
+            }
+
+            if (options.query)
+                uri.push("?", options.query);
+            if (options.hash)
+                uri.push("#", options.hash);
+
+            return uri.join("");
+        }
+
+        function reducePath(parts) {
+            var balance = 0, result = [], isRoot;
+
+            for (var i = 0; i < parts.length; i++) {
+                var part = parts[i];
+                switch (part) {
+                case "..":
+                    if (balance > 0) {
+                        result.pop();
+                    } else {
+                        if (isRoot)
+                            throw new Error("Unbalanced path: " + parts);
+
+                        result.push(part);
+                    }
+                    balance--;
+                    break;
+                case ".":
+                    break;
+                case "":
+                    if (i === 0) {
+                        isRoot = true;
+                        result.push(part);
+                    }
+                    break;
+                default:
+                    result.push(part);
+                    balance++;
+                    break;
+                }
+            }
+
+            return result.join("/");
+        }
+
+        var meta = {
+            schema : null,
+            host : null,
+            port : null,
+            path : null,
+            query : null,
+            hash : null
+        };
+
+        var URI = declare(null, {
+            constructor : function(opts) {
+                if (typeof (opts) == "string")
+                    opts = parseURI(opts);
+                for ( var p in meta)
+                    if (p in opts)
+                        this[p] = opts[p];
+            },
+
+            clone : function() {
+                return new URI(this);
+            },
+
+            combine : function(rel) {
+                var me = this;
+
+                if (typeof (rel) === "string")
+                    rel = new URI(rel);
+                else
+                    rel = rel.clone();
+
+                // //some.host:123/path?q=a#123
+                if (rel.host)
+                    return rel;
+
+                // /abs/path?q=a#123
+                if (rel.path && rel.path[0] == "/") {
+                    if (me.host) {
+                        rel.schema = me.schema;
+                        rel.host = me.host;
+                        rel.port = me.port;
+                    }
+                    return rel;
+                }
+
+                var base = me.clone();
+
+                // rel/path?a=b#cd
+                if (rel.path) {
+                    var segments = base.getSegments();
+                    segments.pop();
+                    segments.push.apply(segments, rel.getSegments());
+
+                    base.path = reducePath(segments);
+                }
+
+                // ?q=a#123
+                if (rel.query)
+                    base.query = rel.query;
+                if (rel.hash)
+                    base.hase = rel.hash;
+
+                return base;
+            },
+
+            optimize : function() {
+                this.path = reducePath(this.getSegments());
+            },
+
+            getSegments : function() {
+                if (typeof (this.path) === "string")
+                    return this.path.split("/");
+                else
+                    return [];
+            },
+
+            toString : function() {
+                var uri = [], me = this;
+
+                if (me.schema)
+                    uri.push(me.schema, ":");
+                if (me.host)
+                    uri.push("//", me.host);
+                if (me.host && me.port)
+                    uri.push(":", me.port);
+
+                if (me.path) {
+                    if (me.host && me.path[0] != "/")
+                        uri.push("/");
+                    uri.push(me.path);
+                } else if (me.host) {
+                    uri.push("/");
+                }
+
+                if (me.query)
+                    uri.push("?", me.query);
+                if (me.hash)
+                    uri.push("#", me.hash);
+
+                return uri.join("");
+            }
+
+        });
+
+        URI.combine = function(base, rel) {
+            if (typeof (base) === "string")
+                base = new URI(base);
+            return base.combine(rel).toString();
+        };
+
+        return URI;
+    });
\ No newline at end of file