@bitcobblers/wod-wiki-wql 0.9.40 → 0.10.42

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 CHANGED
@@ -281,7 +281,10 @@ function parseJoinClause(where) {
281
281
  if (fp.window?.kind === "range") {
282
282
  return { error: "Range windows are not supported on join halves \u2014 use last <n>d|w" };
283
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 } };
284
+ return {
285
+ find: { target: fp.target, filters: fp.filters, last: fp.window?.kind === "relative" ? { size: fp.window.size, unit: fp.window.unit } : void 0 },
286
+ advisories: fp.advisories
287
+ };
285
288
  }
286
289
  const m = CMP_RE.exec(where.trim());
287
290
  if (!m) return { error: cannotParseJoin(where) };
@@ -342,6 +345,12 @@ function normalizeWql(raw) {
342
345
  head = `${head}{source:${scope}}`;
343
346
  }
344
347
  const parts = [head];
348
+ if (suffixes.groupBy) {
349
+ parts.push(`by {${suffixes.groupBy.join(", ")}}`);
350
+ }
351
+ if (suffixes.rollup) {
352
+ parts.push(`.rollup(${suffixes.rollup.raw})`);
353
+ }
345
354
  if (suffixes.window) {
346
355
  parts.push(suffixes.window.raw);
347
356
  }
@@ -363,7 +372,8 @@ function validateRowsFilters(filters) {
363
372
  (f) => !allowedKeys.has(f.key) || f.negate || f.values.some((v) => v.wildcard)
364
373
  );
365
374
  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.`;
375
+ const allowed = [...WQL_ROWS_SCOPE_KEYS, "source"];
376
+ return `Unsupported rows filter(s): ${unsupported.map((f) => (f.negate ? "!" : "") + f.key).join(", ")}. Rows queries support exact ${allowed.map((k) => `${k}:`).join(", ")} values.`;
367
377
  }
368
378
  if (!filters.some((f) => scopeKeys.has(f.key))) {
369
379
  return `Rows query needs a scope: ${WQL_ROWS_SCOPE_KEYS.map((k) => `${k}:`).join(", ")}.`;
@@ -379,7 +389,7 @@ function validateSourceFilter(filters) {
379
389
  if (validSources.has(val) || val === "collection" || val === "feed" || val.startsWith("collection:") || val.startsWith("feed:")) {
380
390
  continue;
381
391
  }
382
- return `Unknown source "${val}". Try: ${WQL_SOURCE_VALUES.join(", ")}`;
392
+ return `Unknown source "${val}". Try: ${WQL_SOURCE_VALUES.join(", ")} (or collection:<id>, feed:<id>)`;
383
393
  }
384
394
  }
385
395
  return void 0;
@@ -587,6 +597,9 @@ function parseAnalyticsQuery(raw) {
587
597
  base.error = join.error;
588
598
  return base;
589
599
  }
600
+ if (join.advisories?.length) {
601
+ base.advisories = [...base.advisories ?? [], ...join.advisories];
602
+ }
590
603
  if (!join.find) {
591
604
  base.error = `Cross-store join on an analytics query must be find:\u2026, got "${whereText}"`;
592
605
  return base;
@@ -682,6 +695,64 @@ function parseFindQuery(raw) {
682
695
  return result;
683
696
  }
684
697
 
698
+ // src/serialize.ts
699
+ function serializeValue(value) {
700
+ if (/^[a-zA-Z0-9_-]+(:[a-zA-Z0-9_-]+)?$/.test(value)) return value;
701
+ return `"${value}"`;
702
+ }
703
+ function serializeFilters(filters) {
704
+ return filters.map((f) => `${f.negate ? "!" : ""}${f.key}:${f.values.map((v) => serializeValue(v.value) + (v.wildcard ? "*" : "")).join("|")}`).join(",");
705
+ }
706
+ function serializeAggHead(agg, metric, filters) {
707
+ return `${agg}:${metric}{${serializeFilters(filters)}}`;
708
+ }
709
+ function serializeAggregateHead(a) {
710
+ return serializeAggHead(a.agg, a.metric, a.filters);
711
+ }
712
+ function serializeFindHalf(target, filters, last) {
713
+ const head = `find:${target}${filters.length ? `{${serializeFilters(filters)}}` : ""}`;
714
+ return last ? `${head} last ${last.size}${last.unit}` : head;
715
+ }
716
+ function serializeMetricHalf(j) {
717
+ return `${serializeAggHead(j.agg, j.metric, j.filters)} ${j.operator} ${j.threshold}`;
718
+ }
719
+ function serializeFindHead(f) {
720
+ return serializeFindHalf(f.target, f.filters);
721
+ }
722
+ function serializeRowsHead(r) {
723
+ return `rows:${r.outputType ?? "all"}{${serializeFilters(r.filters)}}`;
724
+ }
725
+ function serializeWindow(w) {
726
+ if (!w) return "";
727
+ if (w.kind === "relative") return `last ${w.size}${w.unit}`;
728
+ return w.end ? `from ${w.start} to ${w.end}` : `from ${w.start}`;
729
+ }
730
+ function serialize(parsed) {
731
+ if (parsed.error) return parsed.raw;
732
+ if (parsed.family === "aggregate") {
733
+ const a = parsed;
734
+ let text = serializeAggregateHead(a);
735
+ if (a.groupBy.length) text += ` by {${a.groupBy.join(", ")}}`;
736
+ if (a.rollup) text += `.rollup(${a.rollup.size}${a.rollup.unit})`;
737
+ if (a.displayUnit) text += ` in ${a.displayUnit}`;
738
+ const win = serializeWindow(a.window);
739
+ if (win) text += ` ${win}`;
740
+ if (a.join) text += ` where ${serializeFindHalf(a.join.target, a.join.filters, a.join.last)}`;
741
+ return text;
742
+ }
743
+ if (parsed.family === "find") {
744
+ const parts = [serializeFindHead(parsed), serializeWindow(parsed.window)];
745
+ if (parsed.join) parts.push(`where ${serializeMetricHalf(parsed.join)}`);
746
+ return parts.filter(Boolean).join(" ");
747
+ }
748
+ if (parsed.family === "rows") {
749
+ const win = serializeWindow(parsed.window);
750
+ return [serializeRowsHead(parsed), win].filter(Boolean).join(" ");
751
+ }
752
+ const unhandled = parsed;
753
+ return unhandled.raw ?? "";
754
+ }
755
+
685
756
  // src/disciplines.ts
686
757
  var EFFORT_DISCIPLINES = [
687
758
  "bodyweight",
@@ -1590,9 +1661,9 @@ var QueryService = class {
1590
1661
  if (this.staticNoteStore) {
1591
1662
  notes = notes.concat(await this.staticNoteStore.getAllNotes());
1592
1663
  }
1664
+ notes = applySourceFilter(notes, parsed.filters);
1593
1665
  const selectedCount = notes.length;
1594
1666
  const anchorNow = windowAnchor(notes, parsed, options2);
1595
- notes = applySourceFilter(notes, parsed.filters);
1596
1667
  for (const filter of parsed.filters) {
1597
1668
  if (filter.key === "tags" && !filter.negate) {
1598
1669
  const matchingIds = /* @__PURE__ */ new Set();
@@ -1652,9 +1723,9 @@ var QueryService = class {
1652
1723
  if (this.staticBlockStore) {
1653
1724
  blocks = blocks.concat(await this.staticBlockStore.getAllBlocks());
1654
1725
  }
1726
+ blocks = applySourceFilter(blocks, parsed.filters);
1655
1727
  const selectedCount = blocks.length;
1656
1728
  const anchorNow = windowAnchor(blocks, parsed, options2);
1657
- blocks = applySourceFilter(blocks, parsed.filters);
1658
1729
  for (const filter of parsed.filters) {
1659
1730
  if (filter.key === "text" && !filter.negate) {
1660
1731
  const search = filter.values.map((v) => v.value).join(" ").toLowerCase();
@@ -2251,13 +2322,13 @@ sum:$metric{} rollup:1w
2251
2322
  }
2252
2323
 
2253
2324
  // src/version.ts
2254
- var VERSION = "0.9.40";
2255
- var GIT_SHA = "2462ec9";
2256
- var BUILD_TIME = "2026-08-26T01:04:47.412Z";
2325
+ var VERSION = "0.10.42";
2326
+ var GIT_SHA = "79c6d18";
2327
+ var BUILD_TIME = "2026-08-26T04:44:54.356Z";
2257
2328
  var SEMVER = {
2258
- version: "0.9.40",
2259
- gitSha: "2462ec9",
2260
- buildTime: "2026-08-26T01:04:47.412Z"
2329
+ version: "0.10.42",
2330
+ gitSha: "79c6d18",
2331
+ buildTime: "2026-08-26T04:44:54.356Z"
2261
2332
  };
2262
2333
 
2263
2334
  exports.BUILD_TIME = BUILD_TIME;
@@ -2326,6 +2397,7 @@ exports.referencedTokens = referencedTokens;
2326
2397
  exports.resolveCanonicalMetricKey = resolveCanonicalMetricKey;
2327
2398
  exports.resolveDisplayUnit = resolveDisplayUnit;
2328
2399
  exports.resolveWidgetType = resolveWidgetType;
2400
+ exports.serialize = serialize;
2329
2401
  exports.serializeFrontmatter = serializeFrontmatter;
2330
2402
  exports.setDashboardTokenValue = setDashboardTokenValue;
2331
2403
  exports.splitAtWhere = splitAtWhere;