swdyh / url_pattern.js

A Library for url pattern matches.

This URL has Read+Write access

url_pattern.js / url_pattern.js
100644 107 lines (105 sloc) 3.298 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// A Library for url pattern matches.
// Match patterns: http://dev.chromium.org/developers/design-documents/extensions/match-patterns
//
// The MIT License
// Copyright (c) 2009 swdyh
 
function URLPattern(patterns) {
    var hostTree = { keys: {}, values: [] }
    var filePatterns = []
    for (var i = 0; i < patterns.length; i++) {
        var ps = [].concat(patterns[i])
        for (var j = 0; j < ps.length; j++) {
            try {
                var pt = URLPattern.parse(ps[j])
                if (pt.scheme == 'file') {
                    filePatterns.push([i, j])
                }
                else {
                    URLPattern.addTree(hostTree, pt.host, [i, j])
                }
            }
            catch(e) {
                // console.log(e)
            }
        }
    }
    this.patterns = patterns
    this.hostTree = hostTree
    this.filePatterns = filePatterns
}
URLPattern.addTree = function(tree, host, val) {
    var currentNode = tree
    var tmp = host.split('.').reverse()
    for (var i = 0; i < tmp.length; i++) {
        if (!currentNode.keys[tmp[i]]) {
            currentNode.keys[tmp[i]] = { keys: {}, values: [] }
        }
        if (i != (tmp.length - 1)) {
            currentNode = currentNode.keys[tmp[i]]
        }
        else {
            currentNode.keys[tmp[i]].values.push(val)
        }
    }
    return tree
}
URLPattern.prototype.matches = function(url) {
    try {
        var result = []
        var u = URLPattern.parse(url)
        var hosts = (u.scheme == 'file') ? this.filePatterns :
            URLPattern.searchTree(this.hostTree, u.host)
        for (var i = 0; i < hosts.length; i++) {
            var index = hosts[i][0]
            var patternIndex = hosts[i][1]
            var pt = URLPattern.parse([].concat(this.patterns[index])[patternIndex])
            if ((pt.scheme == u.scheme) &&
                (!pt.path || URLPattern.matchesPath(pt.path, u.path))) {
                result.push(index)
            }
        }
        return result
    }
    catch(e) {
        // console.log(e)
        return []
    }
}
URLPattern.matchesPath = function(pattern, path) {
    var escaped = pattern.replace(/[.+?|()\\[\\]{}\\\\]/g, '\\$1')
    var re = new RegExp(escaped.replace('*', '.*'))
    return re.test(path || '/')
}
URLPattern.searchTree = function(tree, host) {
    var tmp = host.split('.').reverse()
    var currentNode = tree
    var result = []
    for (var i = 0; i < tmp.length; i++) {
        if (currentNode.keys['*']) {
            Array.prototype.push.apply(result, currentNode.keys['*'].values)
        }
        if (currentNode.keys[tmp[i]]) {
            Array.prototype.push.apply(result,
                                       currentNode.keys[tmp[i]].values)
            currentNode = currentNode.keys[tmp[i]]
        }
        else {
            break
        }
    }
    return result
}
URLPattern.parse = function(url) {
    var re = /^(http|https|file|ftp):\/\/([^\/]+)?(\/[^ ]+)?/
    var matched = url.match(re)
    if (matched) {
        return { scheme: matched[1], host: matched[2], path: matched[3] }
    }
    else {
        throw 'not supported url'
    }
}
URLPattern.matches = function(pattern, url) {
    var up = new URLPattern([pattern])
    return up.matches(url).length > 0
}