notu 0.2.1 → 0.2.2

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.
@@ -1,153 +0,0 @@
1
- import { expect, test } from 'vitest';
2
- import { splitQuery, identifyTags, identifyAttrs } from './QueryParser';
3
-
4
-
5
- test('splitQuery should split out string into where, order', () => {
6
- const result = splitQuery('#Test AND #Info ORDER BY @Price DESC');
7
-
8
- expect(result.where).toBe('#Test AND #Info');
9
- expect(result.order).toBe('@Price DESC');
10
- });
11
-
12
- test('splitQuery should leave order null if not specified', () => {
13
- const result = splitQuery('#Test AND #Info');
14
-
15
- expect(result.where).toBe('#Test AND #Info');
16
- expect(result.order).toBeNull();
17
- });
18
-
19
- test('splitQuery should leave where null if not specified', () => {
20
- const result = splitQuery('ORDER BY @Price DESC');
21
-
22
- expect(result.where).toBeNull();
23
- expect(result.order).toBe('@Price DESC');
24
- });
25
-
26
-
27
- test('identifyTags should correctly identify multiple tags in query', () => {
28
- const result = splitQuery('#Test AND ~Info OR #~Me');
29
-
30
- result.where = identifyTags(result.where, result);
31
-
32
- expect(result.where).toBe('{tag0} AND {tag1} OR {tag2}');
33
- expect(result.tags[0].space).toBeNull();
34
- expect(result.tags[0].name).toBe('Test');
35
- expect(result.tags[0].includeOwner).toBe(false);
36
- expect(result.tags[0].searchDepth).toBe(1);
37
- expect(result.tags[0].strictSearchDepth).toBe(true);
38
- expect(result.tags[1].space).toBeNull();
39
- expect(result.tags[1].name).toBe('Info');
40
- expect(result.tags[1].includeOwner).toBe(true);
41
- expect(result.tags[1].searchDepth).toBe(0);
42
- expect(result.tags[1].strictSearchDepth).toBe(true);
43
- expect(result.tags[2].space).toBeNull();
44
- expect(result.tags[2].name).toBe('Me');
45
- expect(result.tags[2].includeOwner).toBe(true);
46
- expect(result.tags[2].searchDepth).toBe(1);
47
- expect(result.tags[2].strictSearchDepth).toBe(true);
48
- });
49
-
50
- test('identifyTags handles spaces in tag names if wrapped in brackets', () => {
51
- const result = splitQuery('#[I Am Long]');
52
-
53
- result.where = identifyTags(result.where, result);
54
-
55
- expect(result.where).toBe('{tag0}');
56
- expect(result.tags[0].space).toBeNull();
57
- expect(result.tags[0].name).toBe('I Am Long');
58
- expect(result.tags[0].includeOwner).toBe(false);
59
- expect(result.tags[0].searchDepth).toBe(1);
60
- expect(result.tags[0].strictSearchDepth).toBe(true);
61
- });
62
-
63
- test('identifyTags can identify tag spaces', () => {
64
- const result = splitQuery('#Space1.Tag1 AND #[Space 2.Tag 2]');
65
-
66
- result.where = identifyTags(result.where, result);
67
-
68
- expect(result.where).toBe('{tag0} AND {tag1}');
69
- expect(result.tags[0].space).toBe('Space1');
70
- expect(result.tags[0].name).toBe('Tag1');
71
- expect(result.tags[0].includeOwner).toBe(false);
72
- expect(result.tags[0].searchDepth).toBe(1);
73
- expect(result.tags[0].strictSearchDepth).toBe(true);
74
- expect(result.tags[1].space).toBe('Space 2');
75
- expect(result.tags[1].name).toBe('Tag 2');
76
- expect(result.tags[1].includeOwner).toBe(false);
77
- expect(result.tags[1].searchDepth).toBe(1);
78
- expect(result.tags[1].strictSearchDepth).toBe(true);
79
- });
80
-
81
- test('identifyAttrs can correctly identify multiple attrs in query', () => {
82
- const result = splitQuery('@Count > 3 AND @Depth < 4');
83
-
84
- result.where = identifyAttrs(result.where, result);
85
-
86
- expect(result.where).toBe('{attr0} > 3 AND {attr1} < 4');
87
- expect(result.attrs[0].space).toBeNull();
88
- expect(result.attrs[0].name).toBe('Count');
89
- expect(result.attrs[0].exists).toBe(false);
90
- expect(result.attrs[1].space).toBeNull();
91
- expect(result.attrs[1].name).toBe('Depth');
92
- expect(result.attrs[1].exists).toBe(false);
93
- });
94
-
95
- test('identifyAttrs can identify space names', () => {
96
- const result = splitQuery('@MySpace.Count = 123');
97
-
98
- result.where = identifyAttrs(result.where, result);
99
-
100
- expect(result.where).toBe('{attr0} = 123');
101
- expect(result.attrs[0].space).toBe('MySpace');
102
- expect(result.attrs[0].name).toBe('Count');
103
- expect(result.attrs[0].exists).toBe(false);
104
- });
105
-
106
- test('identifyAttrs can identify exists queries', () => {
107
- const result = splitQuery('@Help.Exists()');
108
-
109
- result.where = identifyAttrs(result.where, result);
110
-
111
- expect(result.where).toBe('{attr0}');
112
- expect(result.attrs[0].space).toBeNull();
113
- expect(result.attrs[0].name).toBe('Help');
114
- expect(result.attrs[0].exists).toBe(true);
115
- });
116
-
117
- test('identifyAttrs can identify on tag filters', () => {
118
- const result = splitQuery('@Abc.On(MyTag) > 1');
119
-
120
- result.where = identifyAttrs(result.where, result);
121
-
122
- expect(result.where).toBe('{attr0} > 1');
123
- expect(result.attrs[0].name).toBe('Abc');
124
- expect(result.attrs[0].exists).toBe(false);
125
- expect(result.attrs[0].tagNameFilters[0].name).toBe('MyTag');
126
- });
127
-
128
- test('identifyAttrs can handle attr and space names with spaces in them', () => {
129
- const result = splitQuery('@[My Space.Test Test] = 123');
130
-
131
- result.where = identifyAttrs(result.where, result);
132
-
133
- expect(result.where).toBe('{attr0} = 123');
134
- expect(result.attrs[0].space).toBe('My Space');
135
- expect(result.attrs[0].name).toBe('Test Test');
136
- });
137
-
138
- test('identifyAttrs can support multiple pipe-separated on(tag) filters', () => {
139
- const result = splitQuery('@Abc.Exists().On(Tag1|#Space2.Tag2)');
140
-
141
- result.where = identifyAttrs(result.where, result);
142
-
143
- expect(result.where).toBe('{attr0}');
144
- expect(result.attrs[0].name).toBe('Abc');
145
- expect(result.attrs[0].exists).toBe(true);
146
- expect(result.attrs[0].tagNameFilters.length).toBe(2);
147
- expect(result.attrs[0].tagNameFilters[0].name).toBe('Tag1');
148
- expect(result.attrs[0].tagNameFilters[0].space).toBeNull();
149
- expect(result.attrs[0].tagNameFilters[0].searchDepth).toBe(0);
150
- expect(result.attrs[0].tagNameFilters[1].name).toBe('Tag2');
151
- expect(result.attrs[0].tagNameFilters[1].space).toBe('Space2');
152
- expect(result.attrs[0].tagNameFilters[1].searchDepth).toBe(1);
153
- });
@@ -1,137 +0,0 @@
1
- 'use strict';
2
-
3
-
4
- export class ParsedQuery {
5
- where: string = null;
6
- order: string = null;
7
- tags: Array<ParsedTag> = [];
8
- attrs: Array<ParsedAttr> = [];
9
- }
10
-
11
- class ParsedTag {
12
- space: string = null;
13
- name: string = null;
14
- searchDepth: number = 0;
15
- strictSearchDepth: boolean = true;
16
- includeOwner: boolean = false;
17
- }
18
-
19
- class ParsedAttr {
20
- space: string = null;
21
- name: string = null;
22
- exists: boolean = false;
23
- tagNameFilters: Array<ParsedTag> = null;
24
- }
25
-
26
-
27
- export default function parseQuery(query: string): ParsedQuery {
28
- const output = splitQuery(query);
29
-
30
- output.where = identifyTags(output.where, output);
31
- output.order = identifyTags(output.order, output);
32
-
33
- output.where = identifyAttrs(output.where, output);
34
- output.order = identifyAttrs(output.order, output);
35
-
36
- return output;
37
- }
38
-
39
-
40
- export function splitQuery(query: string): ParsedQuery {
41
- query = ' ' + query + ' ';
42
- const output = new ParsedQuery();
43
-
44
- const orderByIndex = query.toUpperCase().indexOf(' ORDER BY ');
45
- if (orderByIndex < 0) {
46
- output.where = query.trim();
47
- }
48
- else {
49
- output.where = query.substring(0, orderByIndex).trim();
50
- output.order = query.substring(orderByIndex + ' ORDER BY '.length).trim();
51
- }
52
- if (output.where == '')
53
- output.where = null;
54
- return output;
55
- }
56
-
57
-
58
- export function identifyTags(query: string, parsedQuery: ParsedQuery): string {
59
- const regexes: Array<RegExp> = [
60
- /(#+\??~?|~)([\w\d]+\.)?([\w\d]+)/, //Single word tags and space names
61
- /(#+\??~?|~)\[([\w\d\s]+\.)?([\w\d\s]+)\]/ //Multi-word tags and space names wrapped in []
62
- ];
63
- for (const regex of regexes) {
64
- while (true) {
65
- const match = regex.exec(query);
66
- if (!match)
67
- break;
68
-
69
- const hashPrefix = match[1];
70
- const parsedTag = new ParsedTag();
71
- parsedTag.space = !!match[2] ? match[2].substring(0, match[2].length - 1) : null;
72
- parsedTag.name = match[3];
73
- parsedTag.includeOwner = hashPrefix.includes('~');
74
- parsedTag.searchDepth = (hashPrefix.match(/#/g)||[]).length;
75
- parsedTag.strictSearchDepth = !hashPrefix.includes('?');
76
-
77
- const fullMatch = match[0];
78
- const matchStart = query.indexOf(fullMatch);
79
- const matchEnd = matchStart + fullMatch.length;
80
- query = query.substring(0, matchStart) + `{tag${parsedQuery.tags.length}}` + query.substring(matchEnd);
81
- parsedQuery.tags.push(parsedTag);
82
- }
83
- }
84
- return query;
85
- }
86
-
87
-
88
- export function identifyAttrs(query: string, parsedQuery: ParsedQuery): string {
89
- const regexes: Array<RegExp> = [
90
- /@([\w\d]+\.(?!Exists\(|On\())?([\w\d]+)/,
91
- /@\[([\w\d\s]+\.)?([\w\d\s]+)\]/
92
- ];
93
- for (const regex of regexes) {
94
- while (true) {
95
- //If no more matches to be found, continue to next regex test
96
- const match = regex.exec(query);
97
- if (!match)
98
- break;
99
-
100
- //Build up basic properties of ParsedAttr object
101
- const parsedAttr = new ParsedAttr();
102
- parsedAttr.space = !!match[1] ? match[1].substring(0, match[1].length - 1) : null;
103
- parsedAttr.name = match[2];
104
-
105
- //Record the positions of where the match starts and ends
106
- const matchStart = query.indexOf(match[0]);
107
- let matchEnd = matchStart + match[0].length;
108
-
109
- //Check if there's a test for existance of the attribute on notes
110
- if (query.substring(matchEnd, matchEnd + '.Exists()'.length) == '.Exists()') {
111
- parsedAttr.exists = true;
112
- matchEnd += '.Exists()'.length;
113
- }
114
-
115
- //Check if there's any conditions about which tags to look for the attribute on
116
- if (query.substring(matchEnd, matchEnd + '.On('.length) == '.On(') {
117
- let tagFilterStart = matchEnd + '.On('.length;
118
- matchEnd = query.indexOf(')', tagFilterStart);
119
- if (matchEnd < 0)
120
- throw Error('Unclosed bracket detected');
121
- let tagNameFilters = query.substring(tagFilterStart, matchEnd).split('|');
122
- const dummyParsedQuery = new ParsedQuery();
123
- for (let tagNameFilter of tagNameFilters) {
124
- if (!tagNameFilter.startsWith('~'))
125
- tagNameFilter = '~' + tagNameFilter;
126
- identifyTags(tagNameFilter, dummyParsedQuery);
127
- }
128
- parsedAttr.tagNameFilters = dummyParsedQuery.tags;
129
- matchEnd++;
130
- }
131
-
132
- query = query.substring(0, matchStart) + `{attr${parsedQuery.attrs.length}}` + query.substring(matchEnd);
133
- parsedQuery.attrs.push(parsedAttr);
134
- }
135
- }
136
- return query;
137
- }
package/tsconfig.json DELETED
@@ -1,23 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "useDefineForClassFields": true,
5
- "module": "ESNext",
6
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
7
- "skipLibCheck": true,
8
-
9
- /* Bundler mode */
10
- "moduleResolution": "bundler",
11
- "allowImportingTsExtensions": true,
12
- "resolveJsonModule": true,
13
- "isolatedModules": true,
14
- "noEmit": true,
15
-
16
- /* Linting */
17
- "strict": false,
18
- "noUnusedLocals": true,
19
- "noUnusedParameters": false,
20
- "noFallthroughCasesInSwitch": true
21
- },
22
- "include": ["src"]
23
- }
package/vite.config.ts DELETED
@@ -1,10 +0,0 @@
1
- import { defineConfig } from 'vite';
2
-
3
- export default defineConfig({
4
- build: {
5
- lib: {
6
- name: 'notu',
7
- entry: './src/index.ts'
8
- }
9
- }
10
- });