@bitcobblers/wod-wiki-wql 0.7.38 → 0.9.40
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/index.cjs +343 -140
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +90 -37
- package/dist/index.d.ts +90 -37
- package/dist/index.mjs +339 -140
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var wodWikiCore = require('@bitcobblers/wod-wiki-core');
|
|
3
4
|
var lr = require('@lezer/lr');
|
|
4
5
|
var language = require('@codemirror/language');
|
|
5
6
|
var autocomplete = require('@codemirror/autocomplete');
|
|
6
7
|
var highlight = require('@lezer/highlight');
|
|
7
|
-
var wodWikiCore = require('@bitcobblers/wod-wiki-core');
|
|
8
8
|
|
|
9
9
|
var __defProp = Object.defineProperty;
|
|
10
10
|
var __export = (target, all) => {
|
|
11
11
|
for (var name in all)
|
|
12
12
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
13
|
};
|
|
14
|
-
|
|
15
|
-
// src/vocabulary.ts
|
|
16
14
|
var WQL_METRIC_FAMILIES = ["reps", "distance", "resistance", "elapsed", "power", "pace"];
|
|
17
15
|
var WQL_METRIC_AGGREGATES = ["totalVolume", "totalDistance", "tis", "sessionLoad"];
|
|
18
16
|
var WQL_AGGREGATORS = ["sum", "avg", "min", "max", "count", "last", "delta"];
|
|
@@ -57,7 +55,10 @@ var WQL_CALC_TARGETS = [
|
|
|
57
55
|
var WQL_INTENSITY_TIERS = ["low", "moderate", "high"];
|
|
58
56
|
var WQL_GRAINS = ["summary", "event"];
|
|
59
57
|
var WQL_FIND_TARGETS = ["note", "block", "effort"];
|
|
60
|
-
var
|
|
58
|
+
var WQL_SOURCE_VALUES = ["journal", "collections", "feeds", "all"];
|
|
59
|
+
var WQL_RESULT_PLANES = wodWikiCore.KNOWN_OUTPUT_TYPES;
|
|
60
|
+
var WQL_ROWS_TARGETS = [...WQL_FIND_TARGETS, ...WQL_RESULT_PLANES, "all"];
|
|
61
|
+
var WQL_ROWS_SCOPE_KEYS = ["result", "block", "note"];
|
|
61
62
|
var WQL_CONTENT_FILTER_KEYS = ["type", "text", "has", "source", "catalog", ...WQL_TAG_KEYS];
|
|
62
63
|
var WQL_SOURCES = ["journal", "collections", "feeds", "notes", "blocks", "efforts", "metrics"];
|
|
63
64
|
var WQL_ROLLUP_PERIODS = ["1d", "1w"];
|
|
@@ -153,6 +154,7 @@ var DISPLAY_UNIT_RE = /\s+in\s+([a-zA-Z0-9_-]+)\s*$/;
|
|
|
153
154
|
var ROLLUP_RE = /\.rollup\((\d+)?([a-zA-Z]*)\)\s*$/;
|
|
154
155
|
var BY_RE = /\s+by\s+\{([^}]*)\}\s*$/;
|
|
155
156
|
var LAST_RE = /\s+last\s+(\d+)([dw])\s*$/i;
|
|
157
|
+
var FROM_TO_RE = /\s+from\s+(\d{4}-\d{2}-\d{2})(?:\s+to\s+(\d{4}-\d{2}-\d{2}))?\s*$/i;
|
|
156
158
|
var IN_SCOPE_RE = /\s+in\s+(\w+)\s*$/;
|
|
157
159
|
function parseWqlSuffixes(raw) {
|
|
158
160
|
const { primary, where } = splitAtWhere(raw);
|
|
@@ -160,8 +162,8 @@ function parseWqlSuffixes(raw) {
|
|
|
160
162
|
let displayUnit;
|
|
161
163
|
let rollup;
|
|
162
164
|
let groupBy;
|
|
163
|
-
let
|
|
164
|
-
let
|
|
165
|
+
let window;
|
|
166
|
+
let legacyScope;
|
|
165
167
|
const conflicts = [];
|
|
166
168
|
const isFind = text.startsWith("find:");
|
|
167
169
|
const isRows = /^rows(?=[:{]|\s|$)/.test(text);
|
|
@@ -180,18 +182,40 @@ function parseWqlSuffixes(raw) {
|
|
|
180
182
|
);
|
|
181
183
|
}
|
|
182
184
|
};
|
|
185
|
+
const froms = stripRepeated(FROM_TO_RE);
|
|
186
|
+
const lasts = stripRepeated(LAST_RE);
|
|
187
|
+
{
|
|
188
|
+
const windows = [
|
|
189
|
+
...froms.map((m) => ({
|
|
190
|
+
kind: "range",
|
|
191
|
+
start: m[1],
|
|
192
|
+
end: m[2],
|
|
193
|
+
raw: m[0].trim(),
|
|
194
|
+
at: m.index
|
|
195
|
+
})),
|
|
196
|
+
...lasts.map((m) => ({
|
|
197
|
+
kind: "relative",
|
|
198
|
+
size: parseInt(m[1], 10),
|
|
199
|
+
unit: m[2].toLowerCase(),
|
|
200
|
+
raw: m[0].trim(),
|
|
201
|
+
at: m.index
|
|
202
|
+
}))
|
|
203
|
+
].sort((a, b) => a.at - b.at);
|
|
204
|
+
if (windows.length > 1) {
|
|
205
|
+
conflicts.push(
|
|
206
|
+
`Duplicate 'window' clause: '${windows[0].raw}' conflicts with '${windows[windows.length - 1].raw}'`
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
if (windows.length === 1) {
|
|
210
|
+
const w = windows[0];
|
|
211
|
+
window = w.kind === "range" ? { kind: "range", start: w.start, end: w.end, raw: w.raw } : { kind: "relative", size: w.size, unit: w.unit, raw: w.raw };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
183
214
|
if (isFind || isRows) {
|
|
184
|
-
const
|
|
185
|
-
conflictFrom("
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
last = { size: parseInt(m[1], 10), unit: m[2].toLowerCase(), raw: m[0].trim() };
|
|
189
|
-
}
|
|
190
|
-
if (isFind) {
|
|
191
|
-
const scopes = stripRepeated(IN_SCOPE_RE);
|
|
192
|
-
conflictFrom("scope", scopes);
|
|
193
|
-
if (scopes.length) scope = scopes[scopes.length - 1][1];
|
|
194
|
-
} else {
|
|
215
|
+
const scopes = stripRepeated(IN_SCOPE_RE);
|
|
216
|
+
conflictFrom("scope", scopes);
|
|
217
|
+
if (scopes.length) legacyScope = scopes[scopes.length - 1][1];
|
|
218
|
+
if (isRows) {
|
|
195
219
|
const rollups = stripRepeated(ROLLUP_RE);
|
|
196
220
|
conflictFrom(".rollup", rollups);
|
|
197
221
|
if (rollups.length) {
|
|
@@ -225,8 +249,8 @@ function parseWqlSuffixes(raw) {
|
|
|
225
249
|
displayUnit,
|
|
226
250
|
rollup,
|
|
227
251
|
groupBy,
|
|
228
|
-
|
|
229
|
-
|
|
252
|
+
window,
|
|
253
|
+
legacyScope,
|
|
230
254
|
conflicts: conflicts.length ? conflicts : void 0,
|
|
231
255
|
primaryText: text
|
|
232
256
|
};
|
|
@@ -254,7 +278,10 @@ function parseJoinClause(where) {
|
|
|
254
278
|
if (where.trimStart().startsWith("find:")) {
|
|
255
279
|
const fp = parseFindQuery(where);
|
|
256
280
|
if (fp.error) return { error: fp.error };
|
|
257
|
-
|
|
281
|
+
if (fp.window?.kind === "range") {
|
|
282
|
+
return { error: "Range windows are not supported on join halves \u2014 use last <n>d|w" };
|
|
283
|
+
}
|
|
284
|
+
return { find: { target: fp.target, filters: fp.filters, last: fp.window?.kind === "relative" ? { size: fp.window.size, unit: fp.window.unit } : void 0 } };
|
|
258
285
|
}
|
|
259
286
|
const m = CMP_RE.exec(where.trim());
|
|
260
287
|
if (!m) return { error: cannotParseJoin(where) };
|
|
@@ -271,27 +298,112 @@ function parseJoinClause(where) {
|
|
|
271
298
|
};
|
|
272
299
|
}
|
|
273
300
|
function parseQuery(raw) {
|
|
274
|
-
const
|
|
301
|
+
const norm = normalizeWql(raw);
|
|
302
|
+
const trimmed = norm.query.trimStart();
|
|
303
|
+
let result;
|
|
275
304
|
if (trimmed.startsWith("find:")) {
|
|
276
|
-
|
|
305
|
+
result = parseFindQuery(norm.query);
|
|
306
|
+
} else if (/^rows(?=[:{]|\s|$)/.test(trimmed)) {
|
|
307
|
+
result = parseRowsQuery(norm.query);
|
|
308
|
+
} else {
|
|
309
|
+
result = parseAnalyticsQuery(norm.query);
|
|
277
310
|
}
|
|
278
|
-
if (
|
|
279
|
-
|
|
311
|
+
if (norm.advisories.length) {
|
|
312
|
+
result.advisories = [...result.advisories ?? [], ...norm.advisories];
|
|
280
313
|
}
|
|
281
|
-
|
|
314
|
+
result.raw = raw;
|
|
315
|
+
return result;
|
|
316
|
+
}
|
|
317
|
+
function normalizeWql(raw) {
|
|
318
|
+
const advisories = [];
|
|
319
|
+
let text = raw.trim();
|
|
320
|
+
if (/^rows:?\s*[{]/.test(text)) {
|
|
321
|
+
text = text.replace(/^rows:?\s*[{]/, "rows:all{");
|
|
322
|
+
advisories.push("Bare 'rows:{...}' syntax is deprecated; use 'rows:all{...}' instead.");
|
|
323
|
+
}
|
|
324
|
+
const { primary, where } = splitAtWhere(text);
|
|
325
|
+
const isFind = primary.startsWith("find:");
|
|
326
|
+
const isRows = /^rows(?=[:{]|\s|$)/.test(primary);
|
|
327
|
+
if (isFind || isRows) {
|
|
328
|
+
const suffixes = parseWqlSuffixes(primary);
|
|
329
|
+
if (suffixes.legacyScope && !suffixes.conflicts?.length) {
|
|
330
|
+
advisories.push("Legacy 'in <scope>' syntax is deprecated; use 'source:<scope>' filter instead.");
|
|
331
|
+
const scope = suffixes.legacyScope;
|
|
332
|
+
let head = suffixes.primaryText.trim();
|
|
333
|
+
const braceOpen = head.indexOf("{");
|
|
334
|
+
const braceClose = head.lastIndexOf("}");
|
|
335
|
+
if (braceOpen !== -1 && braceClose !== -1 && braceClose > braceOpen) {
|
|
336
|
+
const beforeBrace = head.slice(0, braceOpen + 1);
|
|
337
|
+
const inside = head.slice(braceOpen + 1, braceClose).trim();
|
|
338
|
+
const afterBrace = head.slice(braceClose);
|
|
339
|
+
const newInside = inside ? `${inside},source:${scope}` : `source:${scope}`;
|
|
340
|
+
head = `${beforeBrace}${newInside}${afterBrace}`;
|
|
341
|
+
} else {
|
|
342
|
+
head = `${head}{source:${scope}}`;
|
|
343
|
+
}
|
|
344
|
+
const parts = [head];
|
|
345
|
+
if (suffixes.window) {
|
|
346
|
+
parts.push(suffixes.window.raw);
|
|
347
|
+
}
|
|
348
|
+
if (where) {
|
|
349
|
+
parts.push(`where ${where}`);
|
|
350
|
+
}
|
|
351
|
+
text = parts.join(" ");
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return { query: text, advisories };
|
|
282
355
|
}
|
|
283
356
|
function cannotParseRows(text) {
|
|
284
|
-
return `Cannot parse "${text}". Expected rows:{result:\u2026|block:\u2026|note:\u2026} or rows:segment{\u2026} last 8w`;
|
|
357
|
+
return `Cannot parse "${text}". Expected rows:all{result:\u2026|block:\u2026|note:\u2026}, rows:<plane>{\u2026}, or rows:segment{\u2026} last 8w`;
|
|
285
358
|
}
|
|
359
|
+
function validateRowsFilters(filters) {
|
|
360
|
+
const scopeKeys = new Set(WQL_ROWS_SCOPE_KEYS);
|
|
361
|
+
const allowedKeys = /* @__PURE__ */ new Set([...WQL_ROWS_SCOPE_KEYS, "source"]);
|
|
362
|
+
const unsupported = filters.filter(
|
|
363
|
+
(f) => !allowedKeys.has(f.key) || f.negate || f.values.some((v) => v.wildcard)
|
|
364
|
+
);
|
|
365
|
+
if (unsupported.length > 0) {
|
|
366
|
+
return `Unsupported rows filter(s): ${unsupported.map((f) => (f.negate ? "!" : "") + f.key).join(", ")}. Rows queries support exact ${WQL_ROWS_SCOPE_KEYS.map((k) => `${k}:`).join(", ")} values.`;
|
|
367
|
+
}
|
|
368
|
+
if (!filters.some((f) => scopeKeys.has(f.key))) {
|
|
369
|
+
return `Rows query needs a scope: ${WQL_ROWS_SCOPE_KEYS.map((k) => `${k}:`).join(", ")}.`;
|
|
370
|
+
}
|
|
371
|
+
return void 0;
|
|
372
|
+
}
|
|
373
|
+
function validateSourceFilter(filters) {
|
|
374
|
+
const validSources = new Set(WQL_SOURCE_VALUES);
|
|
375
|
+
for (const f of filters) {
|
|
376
|
+
if (f.key !== "source") continue;
|
|
377
|
+
for (const v of f.values) {
|
|
378
|
+
const val = v.value;
|
|
379
|
+
if (validSources.has(val) || val === "collection" || val === "feed" || val.startsWith("collection:") || val.startsWith("feed:")) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
return `Unknown source "${val}". Try: ${WQL_SOURCE_VALUES.join(", ")}`;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return void 0;
|
|
386
|
+
}
|
|
387
|
+
var BARE_ROWS_RETIRED = 'Bare "rows:" is retired \u2014 name a target: rows:all{\u2026} for every output type, or a plane like rows:segment{\u2026}.';
|
|
286
388
|
function parseRowsQuery(raw) {
|
|
287
389
|
const suffixes = parseWqlSuffixes(raw);
|
|
288
|
-
const { where: whereText,
|
|
390
|
+
const { where: whereText, window: windowSuffix, legacyScope, groupBy, rollup, primaryText } = suffixes;
|
|
391
|
+
const win = toQueryWindow(windowSuffix);
|
|
392
|
+
const advisories = [];
|
|
393
|
+
if (legacyScope) {
|
|
394
|
+
advisories.push("Legacy 'in <scope>' syntax is deprecated; use 'source:<scope>' filter instead.");
|
|
395
|
+
}
|
|
289
396
|
const result = {
|
|
290
|
-
raw,
|
|
291
397
|
family: "rows",
|
|
398
|
+
raw,
|
|
292
399
|
filters: [],
|
|
293
|
-
|
|
400
|
+
window: win.window,
|
|
401
|
+
...advisories.length ? { advisories } : {}
|
|
294
402
|
};
|
|
403
|
+
if (win.error) {
|
|
404
|
+
result.error = win.error;
|
|
405
|
+
return result;
|
|
406
|
+
}
|
|
295
407
|
if (suffixes.conflicts?.length) {
|
|
296
408
|
result.error = suffixes.conflicts.join("; ");
|
|
297
409
|
return result;
|
|
@@ -301,44 +413,84 @@ function parseRowsQuery(raw) {
|
|
|
301
413
|
return result;
|
|
302
414
|
}
|
|
303
415
|
const text = primaryText.trim();
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
} else {
|
|
416
|
+
if (/^rows:?\s*[{]?$/.test(text) || /^rows:?\s*[{]/.test(text)) {
|
|
417
|
+
result.error = BARE_ROWS_RETIRED;
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
420
|
+
const tree = parser.parse(text);
|
|
421
|
+
let syntaxError = false;
|
|
422
|
+
tree.iterate({ enter(node) {
|
|
423
|
+
if (node.type.isError) syntaxError = true;
|
|
424
|
+
} });
|
|
425
|
+
if (syntaxError) {
|
|
315
426
|
result.error = cannotParseRows(text);
|
|
316
427
|
return result;
|
|
317
428
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
result.
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
429
|
+
const query = tree.topNode;
|
|
430
|
+
const head = query.getChild(Head);
|
|
431
|
+
const aggNode = head?.getChild(Aggregator);
|
|
432
|
+
const metricNode = head?.getChild(Metric);
|
|
433
|
+
if (!head || !aggNode || !metricNode) {
|
|
434
|
+
result.error = BARE_ROWS_RETIRED;
|
|
435
|
+
return result;
|
|
436
|
+
}
|
|
437
|
+
const aggText = text.slice(aggNode.from, aggNode.to);
|
|
438
|
+
if (aggText !== "rows") {
|
|
439
|
+
result.error = cannotParseRows(text);
|
|
440
|
+
return result;
|
|
441
|
+
}
|
|
442
|
+
const target = text.slice(metricNode.from, metricNode.to);
|
|
443
|
+
if (!WQL_ROWS_TARGETS.includes(target)) {
|
|
444
|
+
result.error = `Unknown rows target "${target}". Try: ${WQL_ROWS_TARGETS.join(", ")}`;
|
|
445
|
+
return result;
|
|
446
|
+
}
|
|
447
|
+
if (target !== "all") result.outputType = target;
|
|
448
|
+
result.filters = extractFilters(query, text);
|
|
449
|
+
if (legacyScope) {
|
|
450
|
+
result.filters.push({
|
|
451
|
+
key: "source",
|
|
452
|
+
negate: false,
|
|
453
|
+
values: [{ value: legacyScope, wildcard: false }]
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
const sourceError = validateSourceFilter(result.filters);
|
|
457
|
+
if (sourceError) {
|
|
458
|
+
result.error = sourceError;
|
|
459
|
+
return result;
|
|
460
|
+
}
|
|
461
|
+
const grainError = retiredGrainRollup(result.filters);
|
|
462
|
+
if (grainError) {
|
|
463
|
+
result.error = grainError;
|
|
464
|
+
return result;
|
|
465
|
+
}
|
|
466
|
+
const filterError = validateRowsFilters(result.filters);
|
|
467
|
+
if (filterError) {
|
|
468
|
+
result.error = filterError;
|
|
469
|
+
return result;
|
|
339
470
|
}
|
|
340
471
|
return result;
|
|
341
472
|
}
|
|
473
|
+
function isCivilDate(s) {
|
|
474
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
|
|
475
|
+
if (!m) return false;
|
|
476
|
+
const y = Number(m[1]);
|
|
477
|
+
const mo = Number(m[2]);
|
|
478
|
+
const d = Number(m[3]);
|
|
479
|
+
const dt = new Date(y, mo - 1, d);
|
|
480
|
+
return dt.getFullYear() === y && dt.getMonth() === mo - 1 && dt.getDate() === d;
|
|
481
|
+
}
|
|
482
|
+
function toQueryWindow(w) {
|
|
483
|
+
if (!w) return {};
|
|
484
|
+
if (w.kind === "relative") {
|
|
485
|
+
return { window: { kind: "relative", size: w.size, unit: w.unit } };
|
|
486
|
+
}
|
|
487
|
+
for (const d of [w.start, w.end]) {
|
|
488
|
+
if (d !== void 0 && !isCivilDate(d)) {
|
|
489
|
+
return { error: `Invalid window date "${d}" \u2014 expected a real calendar date YYYY-MM-DD` };
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return { window: { kind: "range", start: w.start, end: w.end } };
|
|
493
|
+
}
|
|
342
494
|
function retiredGrainRollup(filters) {
|
|
343
495
|
if (filters.some((f) => f.key === "grain" && f.values.some((v) => v.value === "rollup"))) {
|
|
344
496
|
return "grain:rollup is retired \u2014 rollup grains are never stored; compute them with the .rollup suffix";
|
|
@@ -374,7 +526,8 @@ function extractFilters(query, text) {
|
|
|
374
526
|
}
|
|
375
527
|
function parseAnalyticsQuery(raw) {
|
|
376
528
|
const suffixes = parseWqlSuffixes(raw);
|
|
377
|
-
const { where: whereText, displayUnit, groupBy, rollup, primaryText: text } = suffixes;
|
|
529
|
+
const { where: whereText, displayUnit, groupBy, rollup, window: windowSuffix, primaryText: text } = suffixes;
|
|
530
|
+
const win = toQueryWindow(windowSuffix);
|
|
378
531
|
const base = {
|
|
379
532
|
family: "aggregate",
|
|
380
533
|
raw,
|
|
@@ -383,8 +536,13 @@ function parseAnalyticsQuery(raw) {
|
|
|
383
536
|
filters: [],
|
|
384
537
|
groupBy: groupBy ?? [],
|
|
385
538
|
displayUnit,
|
|
386
|
-
rollup: rollup ? { size: rollup.size, unit: rollup.unit } : void 0
|
|
539
|
+
rollup: rollup ? { size: rollup.size, unit: rollup.unit } : void 0,
|
|
540
|
+
window: win.window
|
|
387
541
|
};
|
|
542
|
+
if (win.error) {
|
|
543
|
+
base.error = win.error;
|
|
544
|
+
return base;
|
|
545
|
+
}
|
|
388
546
|
if (suffixes.conflicts?.length) {
|
|
389
547
|
base.error = suffixes.conflicts.join("; ");
|
|
390
548
|
return base;
|
|
@@ -438,19 +596,28 @@ function parseAnalyticsQuery(raw) {
|
|
|
438
596
|
return base;
|
|
439
597
|
}
|
|
440
598
|
function cannotParseFind(text) {
|
|
441
|
-
return `Cannot parse "${text}". Expected find:target{filters}
|
|
599
|
+
return `Cannot parse "${text}". Expected find:target{filters} last 8w`;
|
|
442
600
|
}
|
|
443
601
|
function parseFindQuery(raw) {
|
|
444
602
|
const suffixes = parseWqlSuffixes(raw);
|
|
445
|
-
const { where: whereText,
|
|
603
|
+
const { where: whereText, window: windowSuffix, legacyScope, primaryText: text } = suffixes;
|
|
604
|
+
const win = toQueryWindow(windowSuffix);
|
|
605
|
+
const advisories = [];
|
|
606
|
+
if (legacyScope) {
|
|
607
|
+
advisories.push("Legacy 'in <scope>' syntax is deprecated; use 'source:<scope>' filter instead.");
|
|
608
|
+
}
|
|
446
609
|
const result = {
|
|
447
610
|
family: "find",
|
|
448
611
|
raw,
|
|
449
612
|
target: "",
|
|
450
613
|
filters: [],
|
|
451
|
-
|
|
452
|
-
|
|
614
|
+
window: win.window,
|
|
615
|
+
...advisories.length ? { advisories } : {}
|
|
453
616
|
};
|
|
617
|
+
if (win.error) {
|
|
618
|
+
result.error = win.error;
|
|
619
|
+
return result;
|
|
620
|
+
}
|
|
454
621
|
if (suffixes.conflicts?.length) {
|
|
455
622
|
result.error = suffixes.conflicts.join("; ");
|
|
456
623
|
return result;
|
|
@@ -478,7 +645,23 @@ function parseFindQuery(raw) {
|
|
|
478
645
|
return result;
|
|
479
646
|
}
|
|
480
647
|
result.target = text.slice(metricNode.from, metricNode.to);
|
|
648
|
+
if (!WQL_FIND_TARGETS.includes(result.target)) {
|
|
649
|
+
result.error = `Unknown find target "${result.target}". Try: ${WQL_FIND_TARGETS.join(", ")}`;
|
|
650
|
+
return result;
|
|
651
|
+
}
|
|
481
652
|
result.filters = extractFilters(query, text);
|
|
653
|
+
if (legacyScope) {
|
|
654
|
+
result.filters.push({
|
|
655
|
+
key: "source",
|
|
656
|
+
negate: false,
|
|
657
|
+
values: [{ value: legacyScope, wildcard: false }]
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
const sourceError = validateSourceFilter(result.filters);
|
|
661
|
+
if (sourceError) {
|
|
662
|
+
result.error = sourceError;
|
|
663
|
+
return result;
|
|
664
|
+
}
|
|
482
665
|
const findGrainError = retiredGrainRollup(result.filters);
|
|
483
666
|
if (findGrainError) {
|
|
484
667
|
result.error = findGrainError;
|
|
@@ -603,6 +786,8 @@ function wqlCompletionSource(options_ = {}) {
|
|
|
603
786
|
return options(WQL_GRAINS);
|
|
604
787
|
case "metric":
|
|
605
788
|
return metricOptions();
|
|
789
|
+
case "source":
|
|
790
|
+
return options(WQL_SOURCE_VALUES);
|
|
606
791
|
default:
|
|
607
792
|
return null;
|
|
608
793
|
}
|
|
@@ -1095,8 +1280,12 @@ function staticTagIndexFromBlocks(blocks) {
|
|
|
1095
1280
|
|
|
1096
1281
|
// src/QueryService.ts
|
|
1097
1282
|
var DAY = 864e5;
|
|
1283
|
+
var ROWS_CONTENT_PLANES = new Set(WQL_FIND_TARGETS);
|
|
1098
1284
|
function localDateString(ts) {
|
|
1099
|
-
|
|
1285
|
+
const d = new Date(ts);
|
|
1286
|
+
const mm = String(d.getMonth() + 1).padStart(2, "0");
|
|
1287
|
+
const dd = String(d.getDate()).padStart(2, "0");
|
|
1288
|
+
return `${d.getFullYear()}-${mm}-${dd}`;
|
|
1100
1289
|
}
|
|
1101
1290
|
function catalogOfItem(item) {
|
|
1102
1291
|
if (item.catalog) return item.catalog;
|
|
@@ -1106,9 +1295,13 @@ function catalogOfItem(item) {
|
|
|
1106
1295
|
return clean.split("/")[0];
|
|
1107
1296
|
}
|
|
1108
1297
|
function sourceMatches(sourceId, kind) {
|
|
1298
|
+
if (kind === "all") return true;
|
|
1109
1299
|
if (kind === "journal") return !sourceId || sourceId === "journal";
|
|
1110
|
-
if (kind === "collection" || kind === "
|
|
1111
|
-
return !!sourceId && sourceId.startsWith(
|
|
1300
|
+
if (kind === "collection" || kind === "collections") {
|
|
1301
|
+
return !!sourceId && sourceId.startsWith("collection:");
|
|
1302
|
+
}
|
|
1303
|
+
if (kind === "feed" || kind === "feeds") {
|
|
1304
|
+
return !!sourceId && sourceId.startsWith("feed:");
|
|
1112
1305
|
}
|
|
1113
1306
|
return sourceId === kind;
|
|
1114
1307
|
}
|
|
@@ -1123,12 +1316,26 @@ function applySourceFilter(items, filters) {
|
|
|
1123
1316
|
}
|
|
1124
1317
|
return items;
|
|
1125
1318
|
}
|
|
1126
|
-
function
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1319
|
+
function civilMidnight(iso) {
|
|
1320
|
+
const [y, m, d] = iso.split("-").map(Number);
|
|
1321
|
+
return new Date(y, m - 1, d).getTime();
|
|
1322
|
+
}
|
|
1323
|
+
function nextCivilMidnight(iso) {
|
|
1324
|
+
const [y, m, d] = iso.split("-").map(Number);
|
|
1325
|
+
return new Date(y, m - 1, d + 1).getTime();
|
|
1326
|
+
}
|
|
1327
|
+
function windowRange(w, anchorNow) {
|
|
1328
|
+
if (!w) return void 0;
|
|
1329
|
+
if (w.kind === "relative") {
|
|
1330
|
+
return { start: (anchorNow ?? Date.now()) - w.size * (w.unit === "w" ? 7 : 1) * DAY, end: Number.MAX_SAFE_INTEGER };
|
|
1131
1331
|
}
|
|
1332
|
+
const start = civilMidnight(w.start);
|
|
1333
|
+
const end = w.end !== void 0 ? nextCivilMidnight(w.end) - 1 : Number.MAX_SAFE_INTEGER;
|
|
1334
|
+
return { start, end };
|
|
1335
|
+
}
|
|
1336
|
+
function effectiveTimeWindow(createdAt, window, range, anchorNow) {
|
|
1337
|
+
const resolved = range ?? windowRange(window, anchorNow);
|
|
1338
|
+
if (resolved) return createdAt >= resolved.start && createdAt <= resolved.end;
|
|
1132
1339
|
return true;
|
|
1133
1340
|
}
|
|
1134
1341
|
function latestActivity(rows) {
|
|
@@ -1138,7 +1345,7 @@ function latestActivity(rows) {
|
|
|
1138
1345
|
}
|
|
1139
1346
|
function windowAnchor(selected, parsed, options2) {
|
|
1140
1347
|
if (options2.anchorNow !== void 0) return options2.anchorNow;
|
|
1141
|
-
if (options2.anchor === "latest-activity" && parsed.
|
|
1348
|
+
if (options2.anchor === "latest-activity" && parsed.window?.kind === "relative") return latestActivity(selected);
|
|
1142
1349
|
return void 0;
|
|
1143
1350
|
}
|
|
1144
1351
|
var defaultEventStore = {
|
|
@@ -1208,9 +1415,11 @@ function matchesFilters(row, filters, noteTags) {
|
|
|
1208
1415
|
const negate = group[0].negate;
|
|
1209
1416
|
const raw = factTagValue(row, key, noteTags);
|
|
1210
1417
|
const rowValues = Array.isArray(raw) ? raw : raw !== void 0 ? [raw] : [];
|
|
1211
|
-
const hit =
|
|
1212
|
-
(
|
|
1213
|
-
(
|
|
1418
|
+
const hit = rowValues.some(
|
|
1419
|
+
(value) => group.some(
|
|
1420
|
+
(f) => f.values.some(
|
|
1421
|
+
(a) => a.wildcard ? value.startsWith(a.value) : value === a.value
|
|
1422
|
+
)
|
|
1214
1423
|
)
|
|
1215
1424
|
);
|
|
1216
1425
|
return negate ? !hit : hit;
|
|
@@ -1220,8 +1429,8 @@ function dimValue(row, dim, noteTags) {
|
|
|
1220
1429
|
if (dim === "day") return localDateString(row.timestamp);
|
|
1221
1430
|
if (dim === "week") {
|
|
1222
1431
|
const d = new Date(row.timestamp);
|
|
1223
|
-
const monday = new Date(
|
|
1224
|
-
return
|
|
1432
|
+
const monday = new Date(d.getFullYear(), d.getMonth(), d.getDate() - (d.getDay() + 6) % 7);
|
|
1433
|
+
return localDateString(monday.getTime());
|
|
1225
1434
|
}
|
|
1226
1435
|
if (dim === "session") return row.resultId;
|
|
1227
1436
|
const raw = factTagValue(row, dim, noteTags);
|
|
@@ -1320,29 +1529,20 @@ var QueryService = class {
|
|
|
1320
1529
|
return this.run(parsed, options2);
|
|
1321
1530
|
}
|
|
1322
1531
|
/**
|
|
1323
|
-
* Execute a rows query (rows
|
|
1324
|
-
*
|
|
1325
|
-
*
|
|
1532
|
+
* Execute a rows query (rows:<target>{…}, #949/C4) — the session results
|
|
1533
|
+
* table plane. Filter rules are validated at parse; this executes only.
|
|
1534
|
+
* Reads event rows directly over the unified store: outputType narrowing
|
|
1535
|
+
* hits the promoted column; content-plane targets scope by content.
|
|
1326
1536
|
*/
|
|
1327
1537
|
async runRows(parsed, options2 = {}) {
|
|
1328
1538
|
const empty = { parsed, runs: [] };
|
|
1329
1539
|
if (parsed.error) return { ...empty, error: parsed.error };
|
|
1330
|
-
const ROWS_SCOPE_KEYS = /* @__PURE__ */ new Set(["result", "block", "note"]);
|
|
1331
|
-
const unsupported = parsed.filters.filter(
|
|
1332
|
-
(f) => !ROWS_SCOPE_KEYS.has(f.key) || f.negate || f.values.some((v) => v.wildcard)
|
|
1333
|
-
);
|
|
1334
|
-
if (unsupported.length > 0) {
|
|
1335
|
-
return {
|
|
1336
|
-
...empty,
|
|
1337
|
-
error: `Unsupported rows filter(s): ${unsupported.map((f) => (f.negate ? "!" : "") + f.key).join(", ")}. Rows queries support exact result:, block:, note: values.`
|
|
1338
|
-
};
|
|
1339
|
-
}
|
|
1340
1540
|
const scopeValues = (key) => parsed.filters.filter((f) => f.key === key).flatMap((f) => f.values.map((v) => v.value));
|
|
1341
1541
|
const resultIds = scopeValues("result");
|
|
1342
1542
|
const blockIds = scopeValues("block");
|
|
1343
1543
|
const noteIds = scopeValues("note");
|
|
1344
1544
|
if (resultIds.length + blockIds.length + noteIds.length === 0) {
|
|
1345
|
-
return { ...empty,
|
|
1545
|
+
return { ...empty, runs: [] };
|
|
1346
1546
|
}
|
|
1347
1547
|
const byResult = /* @__PURE__ */ new Map();
|
|
1348
1548
|
const collect = (rows) => {
|
|
@@ -1356,9 +1556,9 @@ var QueryService = class {
|
|
|
1356
1556
|
for (const blockContentId of blockIds) collect(await this.store.getEventsByContent(blockContentId));
|
|
1357
1557
|
for (const noteId of noteIds) collect(await this.store.getEventsForNote(noteId));
|
|
1358
1558
|
let groups = [...byResult.entries()].filter(([, rows]) => rows.length > 0);
|
|
1359
|
-
if (parsed.
|
|
1559
|
+
if (parsed.window) {
|
|
1360
1560
|
groups = groups.filter(
|
|
1361
|
-
([, rows]) => effectiveTimeWindow(rows[0].timestamp, parsed.
|
|
1561
|
+
([, rows]) => effectiveTimeWindow(rows[0].timestamp, parsed.window, void 0, options2.anchorNow)
|
|
1362
1562
|
);
|
|
1363
1563
|
}
|
|
1364
1564
|
groups.sort((a, b) => b[1][0].timestamp - a[1][0].timestamp);
|
|
@@ -1366,7 +1566,7 @@ var QueryService = class {
|
|
|
1366
1566
|
resultId,
|
|
1367
1567
|
noteId: rows[0].noteId,
|
|
1368
1568
|
timestamp: rows[0].timestamp,
|
|
1369
|
-
events: parsed.outputType ? rows.filter((row) => row.outputType === parsed.outputType) : rows
|
|
1569
|
+
events: parsed.outputType && !ROWS_CONTENT_PLANES.has(parsed.outputType) ? rows.filter((row) => row.outputType === parsed.outputType) : rows
|
|
1370
1570
|
})).filter((run) => run.events.length > 0);
|
|
1371
1571
|
return { parsed, runs };
|
|
1372
1572
|
}
|
|
@@ -1386,15 +1586,9 @@ var QueryService = class {
|
|
|
1386
1586
|
return this.runFindEffort(parsed);
|
|
1387
1587
|
}
|
|
1388
1588
|
let notes = [];
|
|
1389
|
-
|
|
1390
|
-
if (
|
|
1391
|
-
notes = notes.concat(await this.
|
|
1392
|
-
}
|
|
1393
|
-
if (scope === "collections" || scope === "feeds" || scope === "all") {
|
|
1394
|
-
let sNotes = this.staticNoteStore ? await this.staticNoteStore.getAllNotes() : [];
|
|
1395
|
-
if (scope === "collections") sNotes = sNotes.filter((n) => n.sourceId?.startsWith("collection:"));
|
|
1396
|
-
if (scope === "feeds") sNotes = sNotes.filter((n) => n.sourceId?.startsWith("feed:"));
|
|
1397
|
-
notes = notes.concat(sNotes);
|
|
1589
|
+
notes = notes.concat(await this.noteStore.getAllNotes());
|
|
1590
|
+
if (this.staticNoteStore) {
|
|
1591
|
+
notes = notes.concat(await this.staticNoteStore.getAllNotes());
|
|
1398
1592
|
}
|
|
1399
1593
|
const selectedCount = notes.length;
|
|
1400
1594
|
const anchorNow = windowAnchor(notes, parsed, options2);
|
|
@@ -1440,8 +1634,8 @@ var QueryService = class {
|
|
|
1440
1634
|
});
|
|
1441
1635
|
}
|
|
1442
1636
|
}
|
|
1443
|
-
if (parsed.
|
|
1444
|
-
notes = notes.filter((n) => effectiveTimeWindow(n.createdAt, parsed.
|
|
1637
|
+
if (parsed.window || options2.range) {
|
|
1638
|
+
notes = notes.filter((n) => effectiveTimeWindow(n.createdAt, parsed.window, options2.range, anchorNow));
|
|
1445
1639
|
}
|
|
1446
1640
|
if (parsed.join) {
|
|
1447
1641
|
const joined = await this.applyMetricJoin(parsed, notes, []);
|
|
@@ -1454,15 +1648,9 @@ var QueryService = class {
|
|
|
1454
1648
|
*/
|
|
1455
1649
|
async runFindBlock(parsed, options2 = {}) {
|
|
1456
1650
|
let blocks = [];
|
|
1457
|
-
|
|
1458
|
-
if (
|
|
1459
|
-
blocks = blocks.concat(await this.
|
|
1460
|
-
}
|
|
1461
|
-
if (scope === "collections" || scope === "feeds" || scope === "all") {
|
|
1462
|
-
let sBlocks = this.staticBlockStore ? await this.staticBlockStore.getAllBlocks() : [];
|
|
1463
|
-
if (scope === "collections") sBlocks = sBlocks.filter((b) => b.sourceId?.startsWith("collection:"));
|
|
1464
|
-
if (scope === "feeds") sBlocks = sBlocks.filter((b) => b.sourceId?.startsWith("feed:"));
|
|
1465
|
-
blocks = blocks.concat(sBlocks);
|
|
1651
|
+
blocks = blocks.concat(await this.blockStore.getAllBlocks());
|
|
1652
|
+
if (this.staticBlockStore) {
|
|
1653
|
+
blocks = blocks.concat(await this.staticBlockStore.getAllBlocks());
|
|
1466
1654
|
}
|
|
1467
1655
|
const selectedCount = blocks.length;
|
|
1468
1656
|
const anchorNow = windowAnchor(blocks, parsed, options2);
|
|
@@ -1502,8 +1690,8 @@ var QueryService = class {
|
|
|
1502
1690
|
blocks = blocks.filter((b) => matchingNoteIds.has(b.noteId));
|
|
1503
1691
|
}
|
|
1504
1692
|
}
|
|
1505
|
-
if (parsed.
|
|
1506
|
-
blocks = blocks.filter((b) => effectiveTimeWindow(b.createdAt, parsed.
|
|
1693
|
+
if (parsed.window || options2.range) {
|
|
1694
|
+
blocks = blocks.filter((b) => effectiveTimeWindow(b.createdAt, parsed.window, options2.range, anchorNow));
|
|
1507
1695
|
}
|
|
1508
1696
|
if (parsed.join) {
|
|
1509
1697
|
const joined = await this.applyMetricJoin(parsed, [], blocks);
|
|
@@ -1556,10 +1744,8 @@ var QueryService = class {
|
|
|
1556
1744
|
};
|
|
1557
1745
|
if (parsed.error) return empty;
|
|
1558
1746
|
if (parsed.join) return this.runJoined(parsed, options2);
|
|
1559
|
-
const
|
|
1560
|
-
const
|
|
1561
|
-
const end = options2.rangeEnd ?? Number.MAX_SAFE_INTEGER;
|
|
1562
|
-
const eventRows = windowed ? await this.store.getEventsByTimeRange(start, end) : await this.store.scanAll();
|
|
1747
|
+
const range = options2.rangeStart !== void 0 || options2.rangeEnd !== void 0 ? { start: options2.rangeStart ?? 0, end: options2.rangeEnd ?? Number.MAX_SAFE_INTEGER } : windowRange(parsed.window);
|
|
1748
|
+
const eventRows = range ? await this.store.getEventsByTimeRange(range.start, range.end) : await this.store.scanAll();
|
|
1563
1749
|
const candidates = eventRows.flatMap(projectEventToFacts).filter((row) => row.metricKey === parsed.metric);
|
|
1564
1750
|
const touchesTags = parsed.filters.some((f) => f.key === "tags") || parsed.groupBy.includes("tags");
|
|
1565
1751
|
const noteTags = await this.loadNoteTags(candidates, touchesTags);
|
|
@@ -1577,8 +1763,24 @@ var QueryService = class {
|
|
|
1577
1763
|
const timeDim = parsed.groupBy.find((d) => d === "day" || d === "week");
|
|
1578
1764
|
const tagDims = parsed.groupBy.filter((d) => d !== "day" && d !== "week");
|
|
1579
1765
|
const bucketMs = timeDim ? (timeDim === "week" ? 7 : 1) * DAY : parsed.rollup ? parsed.rollup.size * (parsed.rollup.unit === "w" ? 7 : 1) * DAY : null;
|
|
1580
|
-
const
|
|
1766
|
+
const civilDay = (ts) => {
|
|
1767
|
+
const d = new Date(ts);
|
|
1768
|
+
return Math.floor(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()) / DAY);
|
|
1769
|
+
};
|
|
1770
|
+
const bucketKey = (ts) => {
|
|
1771
|
+
if (timeDim === "day") return civilDay(ts);
|
|
1772
|
+
if (timeDim === "week") {
|
|
1773
|
+
const d = new Date(ts);
|
|
1774
|
+
return civilDay(ts) - (d.getDay() + 6) % 7;
|
|
1775
|
+
}
|
|
1776
|
+
return bucketMs ? Math.floor(ts / bucketMs) : 0;
|
|
1777
|
+
};
|
|
1581
1778
|
const bucketCount = bucketMs ? new Set(matched.map((p) => bucketKey(p.timestamp))).size : matched.length ? 1 : 0;
|
|
1779
|
+
const civilBucketInstant = (anchor, dim) => {
|
|
1780
|
+
const d = new Date(anchor);
|
|
1781
|
+
const back = dim === "week" ? (d.getDay() + 6) % 7 : 0;
|
|
1782
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate() - back, 12).getTime();
|
|
1783
|
+
};
|
|
1582
1784
|
const { unit: targetUnit, convert: shouldConvert } = resolveDisplayUnit(matched, {
|
|
1583
1785
|
directive: parsed.displayUnit,
|
|
1584
1786
|
preferred: options2.preferredUnit
|
|
@@ -1603,7 +1805,7 @@ var QueryService = class {
|
|
|
1603
1805
|
(m) => toDisplayValue(m.value, m.unit ?? m.metricUnit, shouldConvert ? targetUnit : void 0)
|
|
1604
1806
|
);
|
|
1605
1807
|
return {
|
|
1606
|
-
ts: bucketMs ? b * bucketMs + bucketMs / 2 : Math.min(...members.map((m) => m.timestamp)),
|
|
1808
|
+
ts: timeDim ? civilBucketInstant(members[0].timestamp, timeDim) : bucketMs ? b * bucketMs + bucketMs / 2 : Math.min(...members.map((m) => m.timestamp)),
|
|
1607
1809
|
value: Math.round(aggregate(values, parsed.agg, members, shouldConvert ? targetUnit : void 0) * 100) / 100
|
|
1608
1810
|
};
|
|
1609
1811
|
});
|
|
@@ -1637,17 +1839,14 @@ var QueryService = class {
|
|
|
1637
1839
|
raw: "",
|
|
1638
1840
|
target: join.target,
|
|
1639
1841
|
filters: join.filters,
|
|
1640
|
-
|
|
1641
|
-
last: join.last
|
|
1842
|
+
window: join.last ? { kind: "relative", size: join.last.size, unit: join.last.unit } : void 0
|
|
1642
1843
|
});
|
|
1643
1844
|
const contentIds = await this.contentIdsFromFindResult(findResult);
|
|
1644
1845
|
if (contentIds.size === 0) return empty;
|
|
1645
1846
|
let facts = await this.deriveMetricFacts(contentIds, parsed.metric);
|
|
1646
|
-
|
|
1647
|
-
if (
|
|
1648
|
-
|
|
1649
|
-
const end = options2.rangeEnd ?? Number.MAX_SAFE_INTEGER;
|
|
1650
|
-
facts = facts.filter((f) => f.timestamp >= start && f.timestamp <= end);
|
|
1847
|
+
const joinRange = options2.rangeStart !== void 0 || options2.rangeEnd !== void 0 ? { start: options2.rangeStart ?? 0, end: options2.rangeEnd ?? Number.MAX_SAFE_INTEGER } : windowRange(parsed.window);
|
|
1848
|
+
if (joinRange) {
|
|
1849
|
+
facts = facts.filter((f) => f.timestamp >= joinRange.start && f.timestamp <= joinRange.end);
|
|
1651
1850
|
}
|
|
1652
1851
|
const touchesTags = parsed.filters.some((f) => f.key === "tags") || parsed.groupBy.includes("tags");
|
|
1653
1852
|
const noteTags = await this.loadNoteTags(facts, touchesTags);
|
|
@@ -2052,13 +2251,13 @@ sum:$metric{} rollup:1w
|
|
|
2052
2251
|
}
|
|
2053
2252
|
|
|
2054
2253
|
// src/version.ts
|
|
2055
|
-
var VERSION = "0.
|
|
2056
|
-
var GIT_SHA = "
|
|
2057
|
-
var BUILD_TIME = "2026-08-
|
|
2254
|
+
var VERSION = "0.9.40";
|
|
2255
|
+
var GIT_SHA = "2462ec9";
|
|
2256
|
+
var BUILD_TIME = "2026-08-26T01:04:47.412Z";
|
|
2058
2257
|
var SEMVER = {
|
|
2059
|
-
version: "0.
|
|
2060
|
-
gitSha: "
|
|
2061
|
-
buildTime: "2026-08-
|
|
2258
|
+
version: "0.9.40",
|
|
2259
|
+
gitSha: "2462ec9",
|
|
2260
|
+
buildTime: "2026-08-26T01:04:47.412Z"
|
|
2062
2261
|
};
|
|
2063
2262
|
|
|
2064
2263
|
exports.BUILD_TIME = BUILD_TIME;
|
|
@@ -2085,9 +2284,12 @@ exports.WQL_INTENSITY_TIERS = WQL_INTENSITY_TIERS;
|
|
|
2085
2284
|
exports.WQL_KEYWORDS = WQL_KEYWORDS;
|
|
2086
2285
|
exports.WQL_METRIC_AGGREGATES = WQL_METRIC_AGGREGATES;
|
|
2087
2286
|
exports.WQL_METRIC_FAMILIES = WQL_METRIC_FAMILIES;
|
|
2287
|
+
exports.WQL_RESULT_PLANES = WQL_RESULT_PLANES;
|
|
2088
2288
|
exports.WQL_ROLLUP_PERIODS = WQL_ROLLUP_PERIODS;
|
|
2089
|
-
exports.
|
|
2289
|
+
exports.WQL_ROWS_SCOPE_KEYS = WQL_ROWS_SCOPE_KEYS;
|
|
2290
|
+
exports.WQL_ROWS_TARGETS = WQL_ROWS_TARGETS;
|
|
2090
2291
|
exports.WQL_SOURCES = WQL_SOURCES;
|
|
2292
|
+
exports.WQL_SOURCE_VALUES = WQL_SOURCE_VALUES;
|
|
2091
2293
|
exports.WQL_TAG_KEYS = WQL_TAG_KEYS;
|
|
2092
2294
|
exports.WQL_VIRTUAL_DIMS = WQL_VIRTUAL_DIMS;
|
|
2093
2295
|
exports.buildDashboardDocument = buildDashboardDocument;
|
|
@@ -2109,6 +2311,7 @@ exports.isFindQuery = isFindQuery;
|
|
|
2109
2311
|
exports.isProposedMetric = isProposedMetric;
|
|
2110
2312
|
exports.isRowsQuery = isRowsQuery;
|
|
2111
2313
|
exports.normalizeSummaryFacts = normalizeSummaryFacts;
|
|
2314
|
+
exports.normalizeWql = normalizeWql;
|
|
2112
2315
|
exports.parseDashboardNote = parseDashboardNote;
|
|
2113
2316
|
exports.parseFlatProperties = parseFlatProperties;
|
|
2114
2317
|
exports.parseFrontmatter = parseFrontmatter;
|