@dxos/echo-query 0.10.0 → 0.11.0
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/dist/lib/index.mjs +641 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/sandbox.mjs +137 -0
- package/dist/lib/sandbox.mjs.map +1 -0
- package/dist/query-lite/index.d.ts +2315 -1764
- package/dist/query-lite/index.d.ts.map +1 -1
- package/dist/query-lite/index.js +131 -69
- package/dist/query-lite/index.js.map +1 -1
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/query-lite/query-lite.d.ts.map +1 -1
- package/dist/types/src/sandbox/query-sandbox.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -11
- package/src/index.ts +4 -1
- package/src/query-lite/query-lite.ts +148 -77
- package/src/sandbox/query-sandbox.ts +2 -2
- package/dist/lib/neutral/index.mjs +0 -918
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
import { LRParser } from "@lezer/lr";
|
|
2
|
+
import { Filter } from "@dxos/echo";
|
|
3
|
+
import { invariant } from "@dxos/invariant";
|
|
4
|
+
//#region \0rolldown/runtime.js
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __exportAll = (all, no_symbols) => {
|
|
7
|
+
let target = {};
|
|
8
|
+
for (var name in all) __defProp(target, name, {
|
|
9
|
+
get: all[name],
|
|
10
|
+
enumerable: true
|
|
11
|
+
});
|
|
12
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
+
return target;
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/parser/gen/query.ts
|
|
17
|
+
var spec_Identifier = {
|
|
18
|
+
__proto__: null,
|
|
19
|
+
type: 26,
|
|
20
|
+
NOT: 86,
|
|
21
|
+
not: 86,
|
|
22
|
+
"!": 86,
|
|
23
|
+
AND: 88,
|
|
24
|
+
and: 88,
|
|
25
|
+
OR: 90,
|
|
26
|
+
or: 90
|
|
27
|
+
};
|
|
28
|
+
var parser = LRParser.deserialize({
|
|
29
|
+
version: 14,
|
|
30
|
+
states: "(jOVQPOOOnQPO'#ClOOQO'#Cd'#CdOOQO'#Cf'#CfOyQPO'#ChO!OQPO'#CrO!WQPO'#CkOOQO'#Cc'#CcOOQO'#Cz'#CzOOQO'#DW'#DWOVQPO'#DWQ!]QPOOOVQPO'#DWO!mQPO,58xO!rQPO'#DQO!wQPO,59WO#PQPO,59SO#UQPO'#CtOOQO,59^,59^O#ZQPO,59^O#cQQO,59VO#wQPO,59rOOQO'#C{'#C{OOQO'#C|'#C|OOQO'#C}'#C}OVQPO,59rOVQPO,59rOVQPO,59rO$rQPO,59rOVQPO1G.dOOQO,59l,59lOOQO-E7O-E7OOOQO1G.n1G.nO#cQQO,59`O%VQPO'#DRO%[QPO1G.xOOQO1G.x1G.xO%dQQO'#CwOOQO'#Cn'#CnOOQO1G.q1G.qO%kQPO1G/^O&RQPO1G/^O&iQPO1G/^OOQO1G/^1G/^O'PQPO7+$OOOQO1G.z1G.zOOQO,59m,59mOOQO-E7P-E7POOQO7+$d7+$dOOQO,59c,59cO'dQPO,59cOOQO<<Gj<<GjO#cQQO'#DSO'lQPO1G.}OOQO1G.}1G.}OOQO,59n,59nOOQO-E7Q-E7QOOQO7+$i7+$i",
|
|
31
|
+
stateData: "'t~OyOS~ORPOT[OXQOZRO]SOgTO{WO~OS]Oa^O^`X~O^`O~ORaOjbO~O^dO~OrhOshO|fO}gO~PVOTmO~ORnO~Oa^O^`a~ORpO~O^qO~OirOjtO~OZvOcvOdvOevOgTOluO~O{WORzaTzaXzaZza]zagzarzaszawza|za}zaUza~OU{OrhOshO|fO}gO~PVORaO~OirOj!QO~Om!RO~P#cOrzisziwzi|zi}ziUzi~PVO|fOrzisziwzi}ziUzi~PVO|fO}gOrzisziwziUzi~PVOU!TOrhOshO|fO}gO~PVOi!UOm!WO~Oi!UOm!ZO~O",
|
|
32
|
+
goto: "%h{PP|PPPP|!]P!]P!]PP!]!lP!{PPP#XP#nPP#hPP#t$U$]$cPP$h$n$tPPP$zkXOYZ[ijklmxyz|kVOYZ[ijklmxyz|kUOYZ[ijklmxyz|QwdQ}qQ!SuR!X!UjVOYZ[ijklmxyz|Xvdqu!UQcTR!OrmYOYZ[eijklmxyz|ZiZlyz|XjZlz|VkZl|Q_PRo_QscR!PsQ!V!SR!Y!VQZO`eYZelxyz|Ql[QxiQyjQzkR|m",
|
|
33
|
+
nodeNames: "⚠ Query Assignment Identifier = ( ) Filter TagFilter Tag TextFilter String TypeFilter TypeKeyword : PropertyFilter PropertyPath . Value Number Boolean Null ObjectLiteral { ObjectProperty , } ArrayLiteral [ ] Not And Or Relation ArrowRight ArrowLeft",
|
|
34
|
+
maxTerm: 45,
|
|
35
|
+
skippedNodes: [0],
|
|
36
|
+
repeatNodeCount: 3,
|
|
37
|
+
tokenData: "3P~RsX^#`pq#`rs$Tst%qwx&ixy(Qyz(V|}([}!O(a!O!P*Q!Q![(j![!]*V!^!_*[!_!`*g!c!}*l!}#O+W#P#Q+]#R#S*l#T#Y*l#Y#Z+b#Z#b*l#b#c.q#c#h*l#h#i1c#i#o*l#o#p2u#q#r2z#y#z#`$f$g#`#BY#BZ#`$IS$I_#`$I|$JO#`$JT$JU#`$KV$KW#`&FU&FV#`~#eYy~X^#`pq#`#y#z#`$f$g#`#BY#BZ#`$IS$I_#`$I|$JO#`$JT$JU#`$KV$KW#`&FU&FV#`~$WVOr$Trs$ms#O$T#O#P$r#P;'S$T;'S;=`%k<%lO$T~$rOZ~~$uRO;'S$T;'S;=`%O;=`O$T~%RWOr$Trs$ms#O$T#O#P$r#P;'S$T;'S;=`%k;=`<%l$T<%lO$T~%nP;=`<%l$T~%tT}!O&T!Q![&T!c!}&T#R#S&T#T#o&T~&YTX~}!O&T!Q![&T!c!}&T#R#S&T#T#o&T~&lVOw&iwx$mx#O&i#O#P'R#P;'S&i;'S;=`'z<%lO&i~'URO;'S&i;'S;=`'_;=`O&i~'bWOw&iwx$mx#O&i#O#P'R#P;'S&i;'S;=`'z;=`<%l&i<%lO&i~'}P;=`<%l&i~(VOT~~([OU~~(aOi~~(dQ!Q![(j!`!a){~(oSc~!O!P({!Q![(j!g!h)a#X#Y)a~)OP!Q![)R~)WRc~!Q![)R!g!h)a#X#Y)a~)dR{|)m}!O)m!Q![)s~)pP!Q![)s~)xPc~!Q![)s~*QOr~~*VOa~~*[O^~~*_P}!O*b~*gOs~~*lOS~P*qVRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#o*l~+]Ol~~+bOm~R+gWRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#U,P#U#o*lR,UXRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#`*l#`#a,q#a#o*lR,vXRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#g*l#g#h-c#h#o*lR-hXRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#X*l#X#Y.T#Y#o*lR.[VdQRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#o*lR.vXRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#i*l#i#j/c#j#o*lR/hXRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#`*l#`#a0T#a#o*lR0YXRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#`*l#`#a0u#a#o*lR0|VRPeQ}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#o*lR1hXRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#f*l#f#g2T#g#o*lR2YXRP}!O*l!O!P*l!P!Q*l!Q![*l!c!}*l#R#S*l#T#i*l#i#j-c#j#o*l~2zOg~~3POj~",
|
|
38
|
+
tokenizers: [0, 1],
|
|
39
|
+
topRules: { "Query": [0, 1] },
|
|
40
|
+
specialized: [{
|
|
41
|
+
term: 3,
|
|
42
|
+
get: (value) => spec_Identifier[value] || -1
|
|
43
|
+
}],
|
|
44
|
+
tokenPrec: 0
|
|
45
|
+
});
|
|
46
|
+
//#endregion
|
|
47
|
+
//#region src/parser/gen/query.terms.ts
|
|
48
|
+
var query_terms_exports = /* @__PURE__ */ __exportAll({
|
|
49
|
+
And: () => 31,
|
|
50
|
+
ArrayLiteral: () => 27,
|
|
51
|
+
ArrowLeft: () => 35,
|
|
52
|
+
ArrowRight: () => 34,
|
|
53
|
+
Assignment: () => 2,
|
|
54
|
+
Boolean: () => 20,
|
|
55
|
+
Filter: () => 7,
|
|
56
|
+
Identifier: () => 3,
|
|
57
|
+
Not: () => 30,
|
|
58
|
+
Null: () => 21,
|
|
59
|
+
Number: () => 19,
|
|
60
|
+
ObjectLiteral: () => 22,
|
|
61
|
+
ObjectProperty: () => 24,
|
|
62
|
+
Or: () => 32,
|
|
63
|
+
PropertyFilter: () => 15,
|
|
64
|
+
PropertyPath: () => 16,
|
|
65
|
+
Query: () => 1,
|
|
66
|
+
Relation: () => 33,
|
|
67
|
+
String: () => 11,
|
|
68
|
+
Tag: () => 9,
|
|
69
|
+
TagFilter: () => 8,
|
|
70
|
+
TextFilter: () => 10,
|
|
71
|
+
TypeFilter: () => 12,
|
|
72
|
+
TypeKeyword: () => 13,
|
|
73
|
+
Value: () => 18
|
|
74
|
+
});
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/parser/gen/index.ts
|
|
77
|
+
var QueryDSL;
|
|
78
|
+
(function(_QueryDSL) {
|
|
79
|
+
_QueryDSL.Parser = parser;
|
|
80
|
+
_QueryDSL.Node = query_terms_exports;
|
|
81
|
+
_QueryDSL.Tokens = [
|
|
82
|
+
"type:",
|
|
83
|
+
"AND",
|
|
84
|
+
"OR",
|
|
85
|
+
"NOT"
|
|
86
|
+
];
|
|
87
|
+
})(QueryDSL || (QueryDSL = {}));
|
|
88
|
+
//#endregion
|
|
89
|
+
//#region src/parser/query-builder.ts
|
|
90
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/core/echo/echo-query/src/parser/query-builder.ts";
|
|
91
|
+
/**
|
|
92
|
+
* Stateless query builder that parses DSL trees into filters.
|
|
93
|
+
*
|
|
94
|
+
* NOTE: QueryBuilder was largely developed using Claude Sonnet 4.5 (in Windsurf)..
|
|
95
|
+
* To modify the functionality, create a minimal breaking test and direct the LLM to fix either the grammar or builder.
|
|
96
|
+
*/
|
|
97
|
+
var QueryBuilder = class {
|
|
98
|
+
_tags;
|
|
99
|
+
_parser = QueryDSL.Parser.configure({ strict: true });
|
|
100
|
+
constructor(_tags) {
|
|
101
|
+
this._tags = _tags;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check valid input.
|
|
105
|
+
*/
|
|
106
|
+
validate(input) {
|
|
107
|
+
try {
|
|
108
|
+
return this._parser.parse(normalizeInput(input)).cursor().node.name === "Query";
|
|
109
|
+
} catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Build a query from the input string.
|
|
115
|
+
*/
|
|
116
|
+
build(input) {
|
|
117
|
+
try {
|
|
118
|
+
const normalized = normalizeInput(input);
|
|
119
|
+
const tree = this._parser.parse(normalized);
|
|
120
|
+
return this.buildQuery(tree, normalized);
|
|
121
|
+
} catch {
|
|
122
|
+
return {};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Build a query from a parsed DSL tree.
|
|
127
|
+
*/
|
|
128
|
+
buildQuery(tree, input) {
|
|
129
|
+
const cursor = tree.cursor();
|
|
130
|
+
if (cursor.node.name !== "Query") return {};
|
|
131
|
+
const children = [];
|
|
132
|
+
if (cursor.firstChild()) {
|
|
133
|
+
do
|
|
134
|
+
children.push({
|
|
135
|
+
name: cursor.node.name,
|
|
136
|
+
from: cursor.from,
|
|
137
|
+
to: cursor.to
|
|
138
|
+
});
|
|
139
|
+
while (cursor.nextSibling());
|
|
140
|
+
cursor.parent();
|
|
141
|
+
}
|
|
142
|
+
if (children.some((child) => child.name === "Assignment")) return this._parseAssignment(cursor, input);
|
|
143
|
+
const hasOperator = children.some((child) => child.name === "And" || child.name === "Or");
|
|
144
|
+
const hasMultipleExpressions = children.filter((child) => child.name === "Filter" || child.name === "Not" || child.name === "(").length > 1;
|
|
145
|
+
if (hasOperator || hasMultipleExpressions) return { filter: this._parseBinaryExpression(cursor, input) };
|
|
146
|
+
if (!cursor.firstChild()) return { filter: Filter.nothing() };
|
|
147
|
+
return { filter: this._parseExpression(cursor, input) };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Parse an assignment node.
|
|
151
|
+
*/
|
|
152
|
+
_parseAssignment(cursor, input) {
|
|
153
|
+
if (!cursor.firstChild()) return {};
|
|
154
|
+
let name;
|
|
155
|
+
let filter;
|
|
156
|
+
do
|
|
157
|
+
if (cursor.node.name === "Assignment") {
|
|
158
|
+
const assignmentText = this._getNodeText(cursor, input);
|
|
159
|
+
if (cursor.firstChild()) {
|
|
160
|
+
name = this._getNodeText(cursor, input);
|
|
161
|
+
const openParenIndex = assignmentText.indexOf("(");
|
|
162
|
+
const closeParenIndex = assignmentText.lastIndexOf(")");
|
|
163
|
+
if (openParenIndex !== -1 && closeParenIndex !== -1 && closeParenIndex > openParenIndex) {
|
|
164
|
+
const subInput = assignmentText.slice(openParenIndex + 1, closeParenIndex).trim();
|
|
165
|
+
const subTree = this._parser.parse(subInput);
|
|
166
|
+
filter = this.buildQuery(subTree, subInput).filter;
|
|
167
|
+
}
|
|
168
|
+
cursor.parent();
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
while (cursor.nextSibling());
|
|
173
|
+
cursor.parent();
|
|
174
|
+
return {
|
|
175
|
+
filter,
|
|
176
|
+
name
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Parse an expression node.
|
|
181
|
+
*/
|
|
182
|
+
_parseExpression(cursor, input) {
|
|
183
|
+
switch (cursor.node.name) {
|
|
184
|
+
case "Filter": return this._parseFilter(cursor, input);
|
|
185
|
+
case "Not": {
|
|
186
|
+
cursor.nextSibling();
|
|
187
|
+
const notFilter = this._parseExpression(cursor, input);
|
|
188
|
+
return notFilter ? Filter.not(notFilter) : void 0;
|
|
189
|
+
}
|
|
190
|
+
case "And":
|
|
191
|
+
case "Or":
|
|
192
|
+
cursor.parent();
|
|
193
|
+
return this._parseBinaryExpression(cursor, input);
|
|
194
|
+
case "(": {
|
|
195
|
+
cursor.nextSibling();
|
|
196
|
+
const parenFilter = this._parseExpression(cursor, input);
|
|
197
|
+
cursor.nextSibling();
|
|
198
|
+
return parenFilter;
|
|
199
|
+
}
|
|
200
|
+
default: {
|
|
201
|
+
const savedPos = cursor.from;
|
|
202
|
+
if (cursor.firstChild()) {
|
|
203
|
+
let hasOperator = false;
|
|
204
|
+
let expressionCount = 0;
|
|
205
|
+
do {
|
|
206
|
+
if (cursor.node.name === "And" || cursor.node.name === "Or") {
|
|
207
|
+
hasOperator = true;
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
if (cursor.node.name === "Filter" || cursor.node.name === "Not" || cursor.node.name === "(") expressionCount++;
|
|
211
|
+
} while (cursor.nextSibling());
|
|
212
|
+
hasOperator = hasOperator || expressionCount > 1;
|
|
213
|
+
cursor.parent();
|
|
214
|
+
cursor.firstChild();
|
|
215
|
+
while (cursor.from !== savedPos && cursor.nextSibling());
|
|
216
|
+
if (hasOperator) {
|
|
217
|
+
cursor.parent();
|
|
218
|
+
return this._parseBinaryExpression(cursor, input);
|
|
219
|
+
} else {
|
|
220
|
+
const result = this._parseExpression(cursor, input);
|
|
221
|
+
cursor.parent();
|
|
222
|
+
return result;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return Filter.nothing();
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Parse a binary expression (AND/OR).
|
|
231
|
+
*/
|
|
232
|
+
_parseBinaryExpression(cursor, input) {
|
|
233
|
+
const filters = [];
|
|
234
|
+
let operator = null;
|
|
235
|
+
if (cursor.firstChild()) {
|
|
236
|
+
do {
|
|
237
|
+
const nodeName = cursor.node.name;
|
|
238
|
+
if (nodeName === "And" || nodeName === "Or") operator = nodeName.toLowerCase();
|
|
239
|
+
else if (nodeName === "(") {
|
|
240
|
+
const savedPos = cursor.from;
|
|
241
|
+
cursor.nextSibling();
|
|
242
|
+
let hasBinaryOp = false;
|
|
243
|
+
do
|
|
244
|
+
if (cursor.node.name === "And" || cursor.node.name === "Or") {
|
|
245
|
+
hasBinaryOp = true;
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
while (cursor.nextSibling() && cursor.node.name !== ")");
|
|
249
|
+
cursor.parent();
|
|
250
|
+
cursor.firstChild();
|
|
251
|
+
while (cursor.from !== savedPos && cursor.nextSibling());
|
|
252
|
+
cursor.nextSibling();
|
|
253
|
+
if (hasBinaryOp) {
|
|
254
|
+
let depth = 1;
|
|
255
|
+
const exprStart = cursor.from;
|
|
256
|
+
let exprEnd = cursor.to;
|
|
257
|
+
while (cursor.nextSibling() && depth > 0) if (cursor.node.name === "(") depth++;
|
|
258
|
+
else if (cursor.node.name === ")") {
|
|
259
|
+
depth--;
|
|
260
|
+
if (depth === 0) exprEnd = cursor.from;
|
|
261
|
+
}
|
|
262
|
+
const subInput = input.slice(exprStart, exprEnd);
|
|
263
|
+
const subTree = this._parser.parse(subInput);
|
|
264
|
+
const subResult = this.buildQuery(subTree, subInput);
|
|
265
|
+
if (subResult.filter) filters.push(subResult.filter);
|
|
266
|
+
} else {
|
|
267
|
+
const subFilter = this._parseExpression(cursor, input);
|
|
268
|
+
if (subFilter) filters.push(subFilter);
|
|
269
|
+
while (cursor.nextSibling() && cursor.node.name !== ")");
|
|
270
|
+
}
|
|
271
|
+
} else if (nodeName !== ")") {
|
|
272
|
+
const subFilter = this._parseExpression(cursor, input);
|
|
273
|
+
if (subFilter) filters.push(subFilter);
|
|
274
|
+
}
|
|
275
|
+
} while (cursor.nextSibling());
|
|
276
|
+
cursor.parent();
|
|
277
|
+
}
|
|
278
|
+
if (filters.length === 0) return Filter.nothing();
|
|
279
|
+
if (filters.length === 1) return filters[0];
|
|
280
|
+
return operator === "or" ? Filter.or(...filters) : Filter.and(...filters);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Parse a Filter node.
|
|
284
|
+
*/
|
|
285
|
+
_parseFilter(cursor, input) {
|
|
286
|
+
if (!cursor.firstChild()) return Filter.nothing();
|
|
287
|
+
let result = void 0;
|
|
288
|
+
switch (cursor.node.name) {
|
|
289
|
+
case "TagFilter":
|
|
290
|
+
if (this._tags) result = this._parseTagFilter(cursor, input);
|
|
291
|
+
break;
|
|
292
|
+
case "TextFilter":
|
|
293
|
+
result = this._parseTextFilter(cursor, input);
|
|
294
|
+
break;
|
|
295
|
+
case "TypeFilter":
|
|
296
|
+
result = this._parseTypeFilter(cursor, input);
|
|
297
|
+
break;
|
|
298
|
+
case "ObjectLiteral":
|
|
299
|
+
result = this._parseObjectLiteral(cursor, input);
|
|
300
|
+
break;
|
|
301
|
+
case "PropertyFilter":
|
|
302
|
+
result = this._parsePropertyFilter(cursor, input);
|
|
303
|
+
break;
|
|
304
|
+
default: result = Filter.nothing();
|
|
305
|
+
}
|
|
306
|
+
cursor.parent();
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Parse a TypeFilter node (type:typename).
|
|
311
|
+
*/
|
|
312
|
+
_parseTypeFilter(cursor, input) {
|
|
313
|
+
cursor.firstChild();
|
|
314
|
+
cursor.nextSibling();
|
|
315
|
+
cursor.nextSibling();
|
|
316
|
+
const typename = this._getNodeText(cursor, input);
|
|
317
|
+
cursor.parent();
|
|
318
|
+
const uri = /^[a-z][a-z0-9+.-]*:/i.test(typename) ? typename : `dxn:${typename}`;
|
|
319
|
+
return Filter.type(uri);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Parse a TextFilter node (quoted string).
|
|
323
|
+
*/
|
|
324
|
+
_parseTextFilter(cursor, input) {
|
|
325
|
+
cursor.firstChild();
|
|
326
|
+
const text = this._getNodeText(cursor, input);
|
|
327
|
+
cursor.parent();
|
|
328
|
+
return Filter.text(unescapeStringLiteral(text.slice(1, -1)));
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Parse an ObjectLiteral node.
|
|
332
|
+
*/
|
|
333
|
+
_parseObjectLiteral(cursor, input) {
|
|
334
|
+
const props = {};
|
|
335
|
+
if (cursor.firstChild()) {
|
|
336
|
+
do
|
|
337
|
+
if (cursor.node.name === "ObjectProperty") {
|
|
338
|
+
const { key, value } = this._parseObjectProperty(cursor, input);
|
|
339
|
+
if (key) props[key] = Filter.eq(value);
|
|
340
|
+
}
|
|
341
|
+
while (cursor.nextSibling());
|
|
342
|
+
cursor.parent();
|
|
343
|
+
}
|
|
344
|
+
return Filter.props(props);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Parse an ObjectProperty node.
|
|
348
|
+
*/
|
|
349
|
+
_parseObjectProperty(cursor, input) {
|
|
350
|
+
let key = null;
|
|
351
|
+
let value = null;
|
|
352
|
+
if (cursor.firstChild()) {
|
|
353
|
+
if (cursor.node.name === "Identifier") key = this._getNodeText(cursor, input);
|
|
354
|
+
cursor.nextSibling();
|
|
355
|
+
cursor.nextSibling();
|
|
356
|
+
if (cursor.node.name === "Value" && cursor.firstChild()) {
|
|
357
|
+
value = this._parseValue(cursor, input);
|
|
358
|
+
cursor.parent();
|
|
359
|
+
}
|
|
360
|
+
cursor.parent();
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
key,
|
|
364
|
+
value
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Parse a PropertyFilter node (property:value).
|
|
369
|
+
*/
|
|
370
|
+
_parsePropertyFilter(cursor, input) {
|
|
371
|
+
let path = null;
|
|
372
|
+
let value = null;
|
|
373
|
+
if (cursor.firstChild()) {
|
|
374
|
+
if (cursor.node.name === "PropertyPath") path = this._parsePropertyPath(cursor, input);
|
|
375
|
+
cursor.nextSibling();
|
|
376
|
+
cursor.nextSibling();
|
|
377
|
+
if (cursor.node.name === "Value" && cursor.firstChild()) {
|
|
378
|
+
value = this._parseValue(cursor, input);
|
|
379
|
+
cursor.parent();
|
|
380
|
+
}
|
|
381
|
+
cursor.parent();
|
|
382
|
+
}
|
|
383
|
+
if (!path) return Filter.nothing();
|
|
384
|
+
return Filter.props({ [path]: value });
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Parse a PropertyPath node (supports dot notation).
|
|
388
|
+
*/
|
|
389
|
+
_parsePropertyPath(cursor, input) {
|
|
390
|
+
const parts = [];
|
|
391
|
+
if (cursor.firstChild()) {
|
|
392
|
+
do
|
|
393
|
+
if (cursor.node.name === "Identifier") parts.push(this._getNodeText(cursor, input));
|
|
394
|
+
while (cursor.nextSibling());
|
|
395
|
+
cursor.parent();
|
|
396
|
+
}
|
|
397
|
+
return parts.join(".");
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Parse a TagFilter node (#tag).
|
|
401
|
+
*/
|
|
402
|
+
_parseTagFilter(cursor, input) {
|
|
403
|
+
invariant(this._tags, void 0, {
|
|
404
|
+
"~LogMeta": "~LogMeta",
|
|
405
|
+
F: __dxlog_file,
|
|
406
|
+
L: 476,
|
|
407
|
+
S: this,
|
|
408
|
+
A: ["this._tags", ""]
|
|
409
|
+
});
|
|
410
|
+
const str = this._getNodeText(cursor, input).slice(1).toLowerCase();
|
|
411
|
+
const [key] = Object.entries(this._tags).find(([, value]) => value.label.toLowerCase() === str) ?? [];
|
|
412
|
+
return key ? Filter.tag(key) : void 0;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Parse a Value node.
|
|
416
|
+
*/
|
|
417
|
+
_parseValue(cursor, input) {
|
|
418
|
+
switch (cursor.node.name) {
|
|
419
|
+
case "String": return unescapeStringLiteral(this._getNodeText(cursor, input).slice(1, -1));
|
|
420
|
+
case "Number": return Number(this._getNodeText(cursor, input));
|
|
421
|
+
case "Boolean": return this._getNodeText(cursor, input) === "true";
|
|
422
|
+
case "Null": return null;
|
|
423
|
+
case "ObjectLiteral": {
|
|
424
|
+
const props = {};
|
|
425
|
+
if (cursor.firstChild()) {
|
|
426
|
+
do
|
|
427
|
+
if (cursor.node.name === "ObjectProperty") {
|
|
428
|
+
const { key, value } = this._parseObjectProperty(cursor, input);
|
|
429
|
+
if (key) props[key] = value;
|
|
430
|
+
}
|
|
431
|
+
while (cursor.nextSibling());
|
|
432
|
+
cursor.parent();
|
|
433
|
+
}
|
|
434
|
+
return props;
|
|
435
|
+
}
|
|
436
|
+
case "ArrayLiteral": {
|
|
437
|
+
const array = [];
|
|
438
|
+
if (cursor.firstChild()) {
|
|
439
|
+
do
|
|
440
|
+
if (cursor.node.name === "Value" && cursor.firstChild()) {
|
|
441
|
+
array.push(this._parseValue(cursor, input));
|
|
442
|
+
cursor.parent();
|
|
443
|
+
}
|
|
444
|
+
while (cursor.nextSibling());
|
|
445
|
+
cursor.parent();
|
|
446
|
+
}
|
|
447
|
+
return array;
|
|
448
|
+
}
|
|
449
|
+
default: return null;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Get the text content of the current node.
|
|
454
|
+
*/
|
|
455
|
+
_getNodeText(cursor, input) {
|
|
456
|
+
return input.slice(cursor.from, cursor.to);
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
460
|
+
"AND",
|
|
461
|
+
"OR",
|
|
462
|
+
"NOT"
|
|
463
|
+
]);
|
|
464
|
+
var VALUE_LITERALS = /* @__PURE__ */ new Set([
|
|
465
|
+
"true",
|
|
466
|
+
"false",
|
|
467
|
+
"null"
|
|
468
|
+
]);
|
|
469
|
+
var SPECIAL_CHARS = /[\s(){}\[\],"']/;
|
|
470
|
+
var PROPERTY_KEY = /^[a-zA-Z_][a-zA-Z0-9_.]*$/;
|
|
471
|
+
var NUMBER_LITERAL = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
|
|
472
|
+
var URL_SCHEMES = /* @__PURE__ */ new Set([
|
|
473
|
+
"http",
|
|
474
|
+
"https",
|
|
475
|
+
"ftp",
|
|
476
|
+
"ftps",
|
|
477
|
+
"file",
|
|
478
|
+
"mailto",
|
|
479
|
+
"tel",
|
|
480
|
+
"sms",
|
|
481
|
+
"data",
|
|
482
|
+
"javascript",
|
|
483
|
+
"ws",
|
|
484
|
+
"wss",
|
|
485
|
+
"ssh",
|
|
486
|
+
"git"
|
|
487
|
+
]);
|
|
488
|
+
/**
|
|
489
|
+
* Normalize raw user input into a form the lezer grammar can parse.
|
|
490
|
+
* - Bare text fragments (e.g. `foo`) are wrapped in quotes so they parse as TextFilter.
|
|
491
|
+
* - Property values that aren't already quoted/numeric/boolean (e.g. `from:rich@dxos.org`) are quoted.
|
|
492
|
+
* - Tags, type filters, operators, parens, braces, quoted strings, and assignments pass through unchanged.
|
|
493
|
+
*/
|
|
494
|
+
var normalizeInput = (input) => {
|
|
495
|
+
const out = [];
|
|
496
|
+
let pos = 0;
|
|
497
|
+
while (pos < input.length) {
|
|
498
|
+
const currentChar = input[pos];
|
|
499
|
+
if (/\s/.test(currentChar)) {
|
|
500
|
+
out.push(currentChar);
|
|
501
|
+
pos++;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
const prevChar = pos > 0 ? input[pos - 1] : "";
|
|
505
|
+
if (currentChar === "\"" || currentChar === "'" && (pos === 0 || !/[a-zA-Z0-9_]/.test(prevChar))) {
|
|
506
|
+
const quoteChar = currentChar;
|
|
507
|
+
let scanIndex = pos + 1;
|
|
508
|
+
while (scanIndex < input.length && input[scanIndex] !== quoteChar) if (input[scanIndex] === "\\" && scanIndex + 1 < input.length) scanIndex += 2;
|
|
509
|
+
else scanIndex++;
|
|
510
|
+
out.push(input.slice(pos, Math.min(scanIndex + 1, input.length)));
|
|
511
|
+
pos = scanIndex + 1;
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
if (currentChar === "{" || currentChar === "[") {
|
|
515
|
+
const closeChar = currentChar === "{" ? "}" : "]";
|
|
516
|
+
let depth = 1;
|
|
517
|
+
let scanIndex = pos + 1;
|
|
518
|
+
while (scanIndex < input.length && depth > 0) {
|
|
519
|
+
const innerChar = input[scanIndex];
|
|
520
|
+
if (innerChar === "\"" || innerChar === "'") {
|
|
521
|
+
const quoteChar = innerChar;
|
|
522
|
+
scanIndex++;
|
|
523
|
+
while (scanIndex < input.length && input[scanIndex] !== quoteChar) if (input[scanIndex] === "\\" && scanIndex + 1 < input.length) scanIndex += 2;
|
|
524
|
+
else scanIndex++;
|
|
525
|
+
scanIndex++;
|
|
526
|
+
} else if (innerChar === currentChar) {
|
|
527
|
+
depth++;
|
|
528
|
+
scanIndex++;
|
|
529
|
+
} else if (innerChar === closeChar) {
|
|
530
|
+
depth--;
|
|
531
|
+
scanIndex++;
|
|
532
|
+
} else scanIndex++;
|
|
533
|
+
}
|
|
534
|
+
out.push(input.slice(pos, scanIndex));
|
|
535
|
+
pos = scanIndex;
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
if (currentChar === "(" || currentChar === ")" || currentChar === "=" || currentChar === "," || currentChar === "}" || currentChar === "]") {
|
|
539
|
+
out.push(currentChar);
|
|
540
|
+
pos++;
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
if (currentChar === "-" && input[pos + 1] === ">" || currentChar === "<" && input[pos + 1] === "-") {
|
|
544
|
+
out.push(input.slice(pos, pos + 2));
|
|
545
|
+
pos += 2;
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
if (currentChar === "!") {
|
|
549
|
+
out.push(currentChar);
|
|
550
|
+
pos++;
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
if (currentChar === "#") {
|
|
554
|
+
let scanIndex = pos + 1;
|
|
555
|
+
while (scanIndex < input.length && /[a-zA-Z0-9_-]/.test(input[scanIndex])) scanIndex++;
|
|
556
|
+
out.push(input.slice(pos, scanIndex));
|
|
557
|
+
pos = scanIndex;
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
let scanIndex = pos;
|
|
561
|
+
while (scanIndex < input.length) {
|
|
562
|
+
const innerChar = input[scanIndex];
|
|
563
|
+
if (innerChar === "\"") break;
|
|
564
|
+
if (innerChar === "'" && scanIndex > pos && !/[a-zA-Z0-9_]/.test(input[scanIndex - 1])) break;
|
|
565
|
+
if (innerChar === "'" && scanIndex === pos) break;
|
|
566
|
+
if (innerChar !== "'" && SPECIAL_CHARS.test(innerChar)) break;
|
|
567
|
+
if (innerChar === "-" && input[scanIndex + 1] === ">") break;
|
|
568
|
+
if (innerChar === "<" && input[scanIndex + 1] === "-") break;
|
|
569
|
+
scanIndex++;
|
|
570
|
+
}
|
|
571
|
+
if (scanIndex === pos) {
|
|
572
|
+
out.push(currentChar);
|
|
573
|
+
pos++;
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
const token = input.slice(pos, scanIndex);
|
|
577
|
+
pos = scanIndex;
|
|
578
|
+
if (KEYWORDS.has(token.toUpperCase())) {
|
|
579
|
+
out.push(token);
|
|
580
|
+
continue;
|
|
581
|
+
}
|
|
582
|
+
const colonIdx = token.indexOf(":");
|
|
583
|
+
if (colonIdx > 0) {
|
|
584
|
+
const key = token.slice(0, colonIdx);
|
|
585
|
+
const rest = token.slice(colonIdx + 1);
|
|
586
|
+
if (key === "type") {
|
|
587
|
+
out.push(token);
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
if (!(URL_SCHEMES.has(key.toLowerCase()) || rest.startsWith("//")) && PROPERTY_KEY.test(key)) {
|
|
591
|
+
if (rest.length === 0) {
|
|
592
|
+
out.push(token);
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
const firstValueChar = rest[0];
|
|
596
|
+
if (firstValueChar === "\"" || firstValueChar === "'") {
|
|
597
|
+
out.push(token);
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
if (firstValueChar === "{" || firstValueChar === "[") {
|
|
601
|
+
out.push(token);
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
if (VALUE_LITERALS.has(rest) || NUMBER_LITERAL.test(rest)) {
|
|
605
|
+
out.push(token);
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
out.push(`${key}:"${escapeStringLiteral(rest)}"`);
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
if (PROPERTY_KEY.test(token)) {
|
|
613
|
+
let lookahead = pos;
|
|
614
|
+
while (lookahead < input.length && /\s/.test(input[lookahead])) lookahead++;
|
|
615
|
+
if (input[lookahead] === "=") {
|
|
616
|
+
out.push(token);
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
out.push(`"${escapeStringLiteral(token)}"`);
|
|
621
|
+
}
|
|
622
|
+
return out.join("");
|
|
623
|
+
};
|
|
624
|
+
/** Escape a raw value into a string literal body (without surrounding quotes). */
|
|
625
|
+
var escapeStringLiteral = (value) => value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
626
|
+
/** Decode `\\` and `\"` escapes inside a string literal body. */
|
|
627
|
+
var unescapeStringLiteral = (literalBody) => {
|
|
628
|
+
let out = "";
|
|
629
|
+
for (let i = 0; i < literalBody.length; i++) {
|
|
630
|
+
const ch = literalBody[i];
|
|
631
|
+
if (ch === "\\" && i + 1 < literalBody.length) {
|
|
632
|
+
out += literalBody[i + 1];
|
|
633
|
+
i++;
|
|
634
|
+
} else out += ch;
|
|
635
|
+
}
|
|
636
|
+
return out;
|
|
637
|
+
};
|
|
638
|
+
//#endregion
|
|
639
|
+
export { QueryBuilder, QueryDSL, normalizeInput };
|
|
640
|
+
|
|
641
|
+
//# sourceMappingURL=index.mjs.map
|