@bitcobblers/wod-wiki-wql 0.6.36 → 0.7.38

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
@@ -162,55 +162,62 @@ function parseWqlSuffixes(raw) {
162
162
  let groupBy;
163
163
  let last;
164
164
  let scope;
165
+ const conflicts = [];
165
166
  const isFind = text.startsWith("find:");
166
167
  const isRows = /^rows(?=[:{]|\s|$)/.test(text);
168
+ const stripRepeated = (re) => {
169
+ const matches = [];
170
+ for (let m = re.exec(text); m; m = re.exec(text)) {
171
+ matches.unshift(m);
172
+ text = text.slice(0, m.index).trim();
173
+ }
174
+ return matches;
175
+ };
176
+ const conflictFrom = (label, ms) => {
177
+ if (ms.length > 1) {
178
+ conflicts.push(
179
+ `Duplicate '${label}' clause: '${ms[0][0].trim()}' conflicts with '${ms[ms.length - 1][0].trim()}'`
180
+ );
181
+ }
182
+ };
167
183
  if (isFind || isRows) {
168
- const lastMatch = LAST_RE.exec(text);
169
- if (lastMatch) {
170
- last = {
171
- size: parseInt(lastMatch[1], 10),
172
- unit: lastMatch[2].toLowerCase(),
173
- raw: lastMatch[0].trim()
174
- };
175
- text = text.slice(0, lastMatch.index).trim();
184
+ const lasts = stripRepeated(LAST_RE);
185
+ conflictFrom("window", lasts);
186
+ if (lasts.length) {
187
+ const m = lasts[lasts.length - 1];
188
+ last = { size: parseInt(m[1], 10), unit: m[2].toLowerCase(), raw: m[0].trim() };
176
189
  }
177
190
  if (isFind) {
178
- const scopeMatch = IN_SCOPE_RE.exec(text);
179
- if (scopeMatch) {
180
- scope = scopeMatch[1];
181
- text = text.slice(0, scopeMatch.index).trim();
182
- }
191
+ const scopes = stripRepeated(IN_SCOPE_RE);
192
+ conflictFrom("scope", scopes);
193
+ if (scopes.length) scope = scopes[scopes.length - 1][1];
183
194
  } else {
184
- const rollupMatch = ROLLUP_RE.exec(text);
185
- if (rollupMatch) {
186
- const rawRollup = rollupMatch[1] + rollupMatch[2];
187
- rollup = { size: rollupMatch[1] ? parseInt(rollupMatch[1], 10) : 1, unit: rollupMatch[2] || "", raw: rawRollup };
188
- text = text.slice(0, rollupMatch.index).trim();
195
+ const rollups = stripRepeated(ROLLUP_RE);
196
+ conflictFrom(".rollup", rollups);
197
+ if (rollups.length) {
198
+ const m = rollups[rollups.length - 1];
199
+ rollup = { size: m[1] ? parseInt(m[1], 10) : 1, unit: m[2] || "", raw: m[1] + m[2] };
189
200
  }
190
- const byMatch = BY_RE.exec(text);
191
- if (byMatch) {
192
- groupBy = byMatch[1].split(",").map((d) => d.trim()).filter(Boolean);
193
- text = text.slice(0, byMatch.index).trim();
201
+ const bys = stripRepeated(BY_RE);
202
+ conflictFrom("by", bys);
203
+ if (bys.length) {
204
+ groupBy = bys[bys.length - 1][1].split(",").map((d) => d.trim()).filter(Boolean);
194
205
  }
195
206
  }
196
207
  } else {
197
- const unitMatch = DISPLAY_UNIT_RE.exec(text);
198
- if (unitMatch) {
199
- displayUnit = unitMatch[1];
200
- text = text.slice(0, unitMatch.index).trim();
201
- }
202
- const rollupMatch = ROLLUP_RE.exec(text);
203
- if (rollupMatch) {
204
- const rawRollup = rollupMatch[1] + rollupMatch[2];
205
- const size = rollupMatch[1] ? parseInt(rollupMatch[1], 10) : 1;
206
- const unit = rollupMatch[2] || "";
207
- rollup = { size, unit, raw: rawRollup };
208
- text = text.slice(0, rollupMatch.index).trim();
208
+ const units = stripRepeated(DISPLAY_UNIT_RE);
209
+ conflictFrom("display-unit", units);
210
+ if (units.length) displayUnit = units[units.length - 1][1];
211
+ const rollups = stripRepeated(ROLLUP_RE);
212
+ conflictFrom(".rollup", rollups);
213
+ if (rollups.length) {
214
+ const m = rollups[rollups.length - 1];
215
+ rollup = { size: m[1] ? parseInt(m[1], 10) : 1, unit: m[2] || "", raw: m[1] + m[2] };
209
216
  }
210
- const byMatch = BY_RE.exec(text);
211
- if (byMatch) {
212
- groupBy = byMatch[1].split(",").map((d) => d.trim()).filter(Boolean);
213
- text = text.slice(0, byMatch.index).trim();
217
+ const bys = stripRepeated(BY_RE);
218
+ conflictFrom("by", bys);
219
+ if (bys.length) {
220
+ groupBy = bys[bys.length - 1][1].split(",").map((d) => d.trim()).filter(Boolean);
214
221
  }
215
222
  }
216
223
  return {
@@ -220,17 +227,21 @@ function parseWqlSuffixes(raw) {
220
227
  groupBy,
221
228
  last,
222
229
  scope,
230
+ conflicts: conflicts.length ? conflicts : void 0,
223
231
  primaryText: text
224
232
  };
225
233
  }
226
234
 
227
235
  // src/wql.ts
228
236
  function isFindQuery(parsed) {
229
- return "target" in parsed;
237
+ return parsed.family === "find";
230
238
  }
231
239
  function isRowsQuery(parsed) {
232
240
  return parsed.family === "rows";
233
241
  }
242
+ function isAggregateQuery(parsed) {
243
+ return parsed.family === "aggregate";
244
+ }
234
245
  var AGGS = WQL_AGGREGATORS;
235
246
  function cannotParse(text) {
236
247
  return `Cannot parse "${text}". Expected agg:metric{filters} by {dims} .rollup(period)`;
@@ -281,6 +292,10 @@ function parseRowsQuery(raw) {
281
292
  filters: [],
282
293
  last: last ? { size: last.size, unit: last.unit } : void 0
283
294
  };
295
+ if (suffixes.conflicts?.length) {
296
+ result.error = suffixes.conflicts.join("; ");
297
+ return result;
298
+ }
284
299
  if (whereText || groupBy || rollup) {
285
300
  result.error = `Rows queries return raw statements \u2014 no where / by / rollup. Got "${primaryText.trim()}"`;
286
301
  return result;
@@ -361,6 +376,7 @@ function parseAnalyticsQuery(raw) {
361
376
  const suffixes = parseWqlSuffixes(raw);
362
377
  const { where: whereText, displayUnit, groupBy, rollup, primaryText: text } = suffixes;
363
378
  const base = {
379
+ family: "aggregate",
364
380
  raw,
365
381
  agg: "sum",
366
382
  metric: "",
@@ -369,6 +385,10 @@ function parseAnalyticsQuery(raw) {
369
385
  displayUnit,
370
386
  rollup: rollup ? { size: rollup.size, unit: rollup.unit } : void 0
371
387
  };
388
+ if (suffixes.conflicts?.length) {
389
+ base.error = suffixes.conflicts.join("; ");
390
+ return base;
391
+ }
372
392
  if (rollup && rollup.unit !== "d" && rollup.unit !== "w") {
373
393
  base.error = cannotParse(text);
374
394
  return base;
@@ -424,12 +444,17 @@ function parseFindQuery(raw) {
424
444
  const suffixes = parseWqlSuffixes(raw);
425
445
  const { where: whereText, last, scope, primaryText: text } = suffixes;
426
446
  const result = {
447
+ family: "find",
427
448
  raw,
428
449
  target: "",
429
450
  filters: [],
430
451
  scope,
431
452
  last: last ? { size: last.size, unit: last.unit } : void 0
432
453
  };
454
+ if (suffixes.conflicts?.length) {
455
+ result.error = suffixes.conflicts.join("; ");
456
+ return result;
457
+ }
433
458
  const tree = parser.parse(text);
434
459
  let syntaxError = false;
435
460
  tree.iterate({ enter(node) {
@@ -1278,7 +1303,7 @@ var QueryService = class {
1278
1303
  const parsed = parseQuery(raw);
1279
1304
  if (isFindQuery(parsed)) {
1280
1305
  return {
1281
- parsed: { raw, agg: "count", metric: parsed.target, filters: [], groupBy: [] },
1306
+ parsed: { family: "aggregate", raw, agg: "count", metric: parsed.target, filters: [], groupBy: [] },
1282
1307
  series: [],
1283
1308
  stages: { selected: 0, buckets: 0, aggregated: 0, groups: 0 },
1284
1309
  matched: []
@@ -1286,7 +1311,7 @@ var QueryService = class {
1286
1311
  }
1287
1312
  if (isRowsQuery(parsed)) {
1288
1313
  return {
1289
- parsed: { raw, agg: "count", metric: "rows", filters: [], groupBy: [] },
1314
+ parsed: { family: "aggregate", raw, agg: "count", metric: "rows", filters: [], groupBy: [] },
1290
1315
  series: [],
1291
1316
  stages: { selected: 0, buckets: 0, aggregated: 0, groups: 0 },
1292
1317
  matched: []
@@ -1608,6 +1633,7 @@ var QueryService = class {
1608
1633
  };
1609
1634
  const join = parsed.join;
1610
1635
  const findResult = await this.runFind({
1636
+ family: "find",
1611
1637
  raw: "",
1612
1638
  target: join.target,
1613
1639
  filters: join.filters,
@@ -2026,13 +2052,13 @@ sum:$metric{} rollup:1w
2026
2052
  }
2027
2053
 
2028
2054
  // src/version.ts
2029
- var VERSION = "0.6.36";
2030
- var GIT_SHA = "c5ad2b0";
2031
- var BUILD_TIME = "2026-08-24T20:14:33.951Z";
2055
+ var VERSION = "0.7.38";
2056
+ var GIT_SHA = "172cc75";
2057
+ var BUILD_TIME = "2026-08-25T23:00:14.937Z";
2032
2058
  var SEMVER = {
2033
- version: "0.6.36",
2034
- gitSha: "c5ad2b0",
2035
- buildTime: "2026-08-24T20:14:33.951Z"
2059
+ version: "0.7.38",
2060
+ gitSha: "172cc75",
2061
+ buildTime: "2026-08-25T23:00:14.937Z"
2036
2062
  };
2037
2063
 
2038
2064
  exports.BUILD_TIME = BUILD_TIME;
@@ -2075,6 +2101,7 @@ exports.extractFrontmatterTags = extractFrontmatterTags;
2075
2101
  exports.getList = getList;
2076
2102
  exports.getScalar = getScalar;
2077
2103
  exports.getUnitFamily = getUnitFamily;
2104
+ exports.isAggregateQuery = isAggregateQuery;
2078
2105
  exports.isDashboardMeta = isDashboardMeta;
2079
2106
  exports.isDashboardWidgetType = isDashboardWidgetType;
2080
2107
  exports.isEffortDiscipline = isEffortDiscipline;