als-document 0.1.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/query/query.js ADDED
@@ -0,0 +1,147 @@
1
+ class Query {
2
+ static get(query) {
3
+ let q = new Query(query)
4
+ return q.selectors
5
+ }
6
+
7
+ constructor(query) {
8
+ this.query = query
9
+ this.selectors = []
10
+ this.getQueries(query.split(','))
11
+ }
12
+
13
+ getQueries(selectors) {
14
+ selectors.forEach(selector => {
15
+ let originalSelector = selector
16
+ selector = this.removeSpaces(selector)
17
+ this.stringValues = []
18
+ selector = selector.replace(/\[.*?\]/g,(value) => {
19
+ this.stringValues.push(value)
20
+ return `[${this.stringValues.length-1}]`
21
+ })
22
+ let [element,ancestors] = this.splitAndCutLast(selector,' ') // \s - ancestor
23
+ element = this.getFamily(element)
24
+ if(ancestors.length > 0)
25
+ element.ancestors = ancestors.map(ancestor => this.getFamily(ancestor))
26
+ element.group = originalSelector
27
+ this.selectors.push(element)
28
+ });
29
+ }
30
+
31
+ splitAndCutLast(string,splitBy) {
32
+ let array = string.split(splitBy)
33
+ let last
34
+ if(array.length == 1) {
35
+ last = array[0]
36
+ array = []
37
+ } else last = array.splice(array.length-1,array.length-1)[0]
38
+ return [last,array]
39
+ }
40
+
41
+ getFamily(group,element,prev,prevAny,sign) {
42
+ if(group.match(/\~|\+/) !== null) {
43
+ let [last,prevBrothers] = this.splitAndCutLast(group,/\~|\+/)
44
+ let signs = group.replace(last,'')
45
+ prevBrothers.forEach(el => signs = signs.replace(el,''))
46
+ signs = signs.match(/\~|\+/g)
47
+ if(signs.length == 1) {
48
+ sign = signs[0]
49
+ } else if(signs.length > 1){
50
+ sign = signs.splice(signs.length-1,signs.length-1)[0]
51
+ prevBrothers[0] = prevBrothers.map((b,i) => {
52
+ if(i<prevBrothers.length-1) b += signs[i]
53
+ return b
54
+ }).join('')
55
+ prevBrothers[0] = this.getFamily(prevBrothers[0])
56
+ }
57
+ if(sign == '~') prevAny = prevBrothers[0] // ~ - any prev brother
58
+ else if(sign == '+') prev = prevBrothers[0] // + - prev brother
59
+ element = last
60
+ } else element = group
61
+ let family
62
+ if(prev || prevAny) {
63
+ family = this.getParents(element)
64
+ if(prev) family.prev = this.getParents(prev)
65
+ if(prevAny) family.prevAny = this.getParents(prevAny)
66
+ } else family = this.getParents(element)
67
+ if(family.query !== group) family.group = group
68
+ return family
69
+ }
70
+
71
+ getParents(selector) {
72
+ if(typeof selector == 'string') {
73
+ let [element,parents] = this.splitAndCutLast(selector,'>')
74
+ element = this.buildElement(element)
75
+ parents = parents.map(parent => this.buildElement(parent))
76
+ if(parents.length > 0) element.parents = parents
77
+ return element
78
+ } else return selector
79
+ }
80
+
81
+
82
+ buildElement(element,id=null,tag=null,classList=[]) {
83
+ let query = element
84
+ element = element.replace(/\#(\w-?)*/,$id => {
85
+ id = $id.replace(/^\#/,''); return ''
86
+ })
87
+ element = element.replace(/\.(\w-?)*/,$class => {
88
+ classList.push($class.replace(/^\./,'')); return ''
89
+ })
90
+ element = element.replace(/(\w-?)*/,$tag => {
91
+ tag = $tag == '' ? null : $tag; return ''
92
+ })
93
+ let attribs = this.getAttributes(element)
94
+ element = {query}
95
+ if(id) element.id = id
96
+ if(tag) element.tag = tag
97
+ if(classList.length > 0) element.classList = classList
98
+ if(attribs.length > 0) element.attribs = attribs
99
+ return element
100
+ }
101
+
102
+ getAttributes(element) {
103
+ let attribs = this.stringValues.filter((value,index) => {
104
+ let searchValue = `[${index}]`
105
+ if(element.match(searchValue)) return true
106
+ else return false
107
+ })
108
+ attribs = attribs.map(attrib => {
109
+ let query = attrib
110
+ attrib = attrib.replace('[','').replace(']','')
111
+ let [name,value] = attrib.split(/[\~\|\^\$\*]?\=/)
112
+ let sign = attrib.replace(name,'').replace(value,'')
113
+ attrib = {query}
114
+ if(name) attrib.name = name
115
+ if(value) attrib.value = value.trim().replace(/^\"/,'').replace(/\"$/,'')
116
+ if(sign) {
117
+ attrib.sign = sign
118
+ attrib.check = this.getAttribFn(sign).bind(attrib)
119
+ }
120
+ return attrib
121
+ });
122
+ return attribs
123
+ }
124
+
125
+ getAttribFn(sign) {
126
+ if(sign == '=') return function(value) {return value == this.value ? true : false}
127
+ if(sign == '*=') return function(value) {return value.includes(this.value) ? true : false}
128
+ if(sign == '^=') return function(value) {return value.startsWith(this.value) ? true : false}
129
+ if(sign == '$=') return function(value) {return value.endsWith(this.value) ? true : false}
130
+ if(sign == '|=') return function(value) {
131
+ return value.trim().split(' ').length == 1
132
+ && (value.startsWith(this.value) || value.startsWith(this.value+'-'))
133
+ ? true : false
134
+ }
135
+ if(sign == '~=') return function(value) { // includes whole word only
136
+ return this.value.trim().split(' ').length == 1 && value.includes(this.value) ? true : false
137
+ }
138
+ }
139
+
140
+ removeSpaces(selector) {
141
+ selector = selector.replace(/\s{2}/g,' ') // remove double spaces
142
+ selector = selector.replace(/\s?\^?\$?\|?\~?\*?\=\s*/g,(m) => m.trim()) // remove spaces inside []
143
+ selector = selector.replace(/\s?(\+|\~|\>)\s?/g,(m) => m.trim()) // remove spaces around +|~|>
144
+ return selector
145
+ }
146
+ }
147
+ try {module.exports = Query} catch {}
@@ -0,0 +1,131 @@
1
+ ## Query
2
+ Query is a class for parsing selectors inside html query. Query not supporting pseudo selectors so far.
3
+ You can use Query on frontend and on backend.
4
+
5
+ Query can be used on fronten and on backend.
6
+
7
+ Frontend:
8
+ ```html
9
+ <script src="/node_modules/als-document/query/query.js"></script>
10
+ ```
11
+
12
+ Backend:
13
+ ```javascript
14
+ let {Query} = require('als-document')
15
+ ```
16
+
17
+ ### Syntax
18
+
19
+ ```javascript
20
+ let queryObj = new Query(qeury:string): instanceof Query
21
+ let selectors = queryObj.selectors:string
22
+ // or
23
+ let selectors = Query.get(q1:string):string
24
+ ```
25
+
26
+ ``query`` - html/css query
27
+
28
+
29
+ ### Example
30
+
31
+ ```javascript
32
+ let q1 = 'html>body>div.tabs~.some[type $= "radio and some"]>p+div>.some-id .tab-content~input[disabled] div.some'
33
+ let result = new Query(q1).selectors
34
+ let result1 = Query.get(q1)
35
+ // result and result1 has to be same
36
+ console.log(result)
37
+ ```
38
+
39
+ Result:
40
+ ```javascript
41
+ [
42
+ {
43
+ "query": "div.some",
44
+ "tag": "div",
45
+ "classList": [
46
+ "some"
47
+ ],
48
+ "ancestors": [
49
+ {
50
+ "query": ".some-id",
51
+ "classList": [
52
+ "some-id"
53
+ ],
54
+ "parents": [
55
+ {
56
+ "query": "div",
57
+ "tag": "div"
58
+ }
59
+ ],
60
+ "prev": {
61
+ "query": "p",
62
+ "tag": "p",
63
+ "parents": [
64
+ {
65
+ "query": ".some[0]",
66
+ "classList": [
67
+ "some"
68
+ ],
69
+ "attribs": [
70
+ {
71
+ check:(f),
72
+ "query": "[type$=\"radio and some\"]",
73
+ "name": "type",
74
+ "value": "radio and some",
75
+ "sign": "$="
76
+ }
77
+ ]
78
+ }
79
+ ],
80
+ "prevAny": {
81
+ "query": "div.tabs",
82
+ "tag": "div",
83
+ "classList": [
84
+ "tabs"
85
+ ],
86
+ "parents": [
87
+ {
88
+ "query": "html",
89
+ "tag": "html"
90
+ },
91
+ {
92
+ "query": "body",
93
+ "tag": "body"
94
+ }
95
+ ]
96
+ },
97
+ "group": "html>body>div.tabs~.some[0]>p"
98
+ },
99
+ "group": "html>body>div.tabs~.some[0]>p+div>.some-id"
100
+ },
101
+ {
102
+ "query": "input[1]",
103
+ "tag": "input",
104
+ "attribs": [
105
+ {
106
+ "query": "[disabled]",
107
+ "name": "disabled"
108
+ }
109
+ ],
110
+ "prevAny": {
111
+ "query": ".tab-content",
112
+ "classList": [
113
+ "tab-content"
114
+ ]
115
+ },
116
+ "group": ".tab-content~input[1]"
117
+ }
118
+ ],
119
+ "group": "html>body>div.tabs~.some[type $= \"radio and some\"]>p+div>.some-id .tab-content~input[disabled] div.some"
120
+ }
121
+ ]
122
+ ```
123
+
124
+ ### Attribs and check function
125
+ if attribute has value, attrib object will contain check function with one parameter for value to check.
126
+
127
+ ```javascript
128
+ let s = Query.get('[test^="some"]')[0]
129
+ console.log(s.attribs[0].check('some value test')) // true
130
+ ```
131
+
package/query/test.js ADDED
@@ -0,0 +1,143 @@
1
+ let Test = require('als-test')
2
+ let {equal,greater,smaller,$greater, $smaller} = Test
3
+ let Query = require('./query')
4
+
5
+ module.exports = new Test('Query tests',[
6
+ {
7
+ title:'Build query',
8
+ result:function(){
9
+ this.vars.q1 = 'html>body>div.tabs~.some[type $= "some"][test]>p+div>.some-id .tab-content~input[disabled] div.some'
10
+ this.vars.s1 = Query.get(this.vars.q1)[0]
11
+ },
12
+ },
13
+ {
14
+ title:'Check target',
15
+ expected:'div.some',
16
+ result:function({s1}){
17
+ let {tag,classList} = s1
18
+ return `${tag}.${classList[0]}`
19
+ },
20
+ action:equal
21
+ },
22
+ {
23
+ title:'Check ancestors length',
24
+ expected:2,
25
+ result:function({s1}){
26
+ return s1.ancestors.length
27
+ },
28
+ action:equal
29
+ },
30
+ {
31
+ title:'Check prev group',
32
+ expected:function({s1}) {
33
+ return s1.ancestors[0].group.split('+')[0]
34
+ },
35
+ result:function({s1}){
36
+ return s1.ancestors[0].prev.group
37
+ },
38
+ action:equal
39
+ },
40
+ {
41
+ title:'Check parents length',
42
+ expected:1,
43
+ result:async function({s1}){
44
+ return s1.ancestors[0].parents.length
45
+ },
46
+ action:equal
47
+ },
48
+ {
49
+ title:'Check prev any, prev and classList',
50
+ expected:'tabs',
51
+ result:async function({s1}){
52
+ return s1.ancestors[0].prev.prevAny.classList[0]
53
+ },
54
+ action:equal
55
+ },
56
+ {
57
+ title:'Check attributes length',
58
+ expected:2,
59
+ result:async function({s1}){
60
+ return s1.ancestors[0].prev.parents[0].attribs.length
61
+ },
62
+ action:equal
63
+ },
64
+ {
65
+ title:'Check attributes fn $',
66
+ expected:true,
67
+ result:async function({s1}){
68
+ return s1.ancestors[0].prev.parents[0].attribs[0].check('test and some')
69
+ },
70
+ action:equal
71
+ },
72
+ {
73
+ title:'Check attributes fn *=',
74
+ expected:true,
75
+ result:async function({s1}){
76
+ return s1.ancestors[0].prev.parents[0].attribs[0].check('some')
77
+ },
78
+ action:equal
79
+ },
80
+ {
81
+ title:'Check attributes fn *=',
82
+ expected:true,
83
+ result:async function(){
84
+ let s = Query.get('[test*="some value"]')[0]
85
+ return s.attribs[0].check('some value test')
86
+ },
87
+ action:equal
88
+ },
89
+ {
90
+ title:'Check attributes fn ~= prase instead single word',
91
+ expected:false,
92
+ result:async function(){
93
+ let s = Query.get('[test~="some value"]')[0]
94
+ return s.attribs[0].check('some value test')
95
+ },
96
+ action:equal
97
+ },
98
+ {
99
+ title:'Check attributes fn ~=',
100
+ expected:true,
101
+ result:async function(){
102
+ let s = Query.get('[test~="value"]')[0]
103
+ return s.attribs[0].check('some value test')
104
+ },
105
+ action:equal
106
+ },
107
+ {
108
+ title:'Check attributes fn ^=',
109
+ expected:true,
110
+ result:async function(){
111
+ let s = Query.get('[test^="some"]')[0]
112
+ return s.attribs[0].check('some value test')
113
+ },
114
+ action:equal
115
+ },
116
+ {
117
+ title:'Check attributes fn |= with few words',
118
+ expected:false,
119
+ result:async function(){
120
+ let s = Query.get('[test|="some value test"]')[0]
121
+ return s.attribs[0].check('some')
122
+ },
123
+ action:equal
124
+ },
125
+ {
126
+ title:'Check attributes fn |=word',
127
+ expected:true,
128
+ result:async function(){
129
+ let s = Query.get('[test|="some"]')[0]
130
+ return s.attribs[0].check('some')
131
+ },
132
+ action:equal
133
+ },
134
+ {
135
+ title:'Check attributes fn |=word-word',
136
+ expected:true,
137
+ result:async function(){
138
+ let s = Query.get('[test|="some"]')[0]
139
+ return s.attribs[0].check('some-value')
140
+ },
141
+ action:equal
142
+ },
143
+ ])