@graphenedata/cli 0.0.16 → 0.0.18

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.
Files changed (38) hide show
  1. package/README.md +65 -29
  2. package/dist/cli/{bigQuery-I3F46SC6.js → bigQuery-YIWXZPY6.js} +2 -2
  3. package/dist/cli/{chunk-QAXEOZ43.js → chunk-SQVXTHE5.js} +2 -2
  4. package/dist/cli/chunk-SQVXTHE5.js.map +7 -0
  5. package/dist/cli/{chunk-OVWODUTJ.js → chunk-UTV3ERGI.js} +279 -150
  6. package/dist/cli/chunk-UTV3ERGI.js.map +7 -0
  7. package/dist/cli/cli.js +33 -6
  8. package/dist/cli/{clickhouse-ZN5AN2UL.js → clickhouse-S3BJSKND.js} +3 -2
  9. package/dist/cli/clickhouse-S3BJSKND.js.map +7 -0
  10. package/dist/cli/{duckdb-IYBIO5KJ.js → duckdb-V6PJEA7H.js} +2 -2
  11. package/dist/cli/{serve2-TNN5EROW.js → serve2-CGQSM7TD.js} +7 -6
  12. package/dist/cli/{serve2-TNN5EROW.js.map → serve2-CGQSM7TD.js.map} +2 -2
  13. package/dist/cli/{snowflake-MOQB5GA4.js → snowflake-HVSTYBLB.js} +2 -2
  14. package/dist/index.d.ts +4 -4
  15. package/dist/lang/index.d.ts +4 -4
  16. package/dist/skills/graphene/SKILL.md +10 -3
  17. package/dist/skills/graphene/references/gsql.md +26 -23
  18. package/dist/skills/graphene/references/model-gsql.md +19 -21
  19. package/dist/ui/component-utilities/enrich.ts +88 -23
  20. package/dist/ui/component-utilities/format.ts +36 -21
  21. package/dist/ui/component-utilities/theme.ts +0 -1
  22. package/dist/ui/components/AreaChart.svelte +1 -1
  23. package/dist/ui/components/BarChart.svelte +1 -1
  24. package/dist/ui/components/LineChart.svelte +1 -1
  25. package/dist/ui/internal/LocalApp.svelte +29 -27
  26. package/dist/ui/internal/PageNavGroup.svelte +2 -2
  27. package/dist/ui/internal/Sidebar.svelte +7 -7
  28. package/dist/ui/internal/queryEngine.ts +13 -15
  29. package/dist/ui/internal/runSocket.ts +2 -5
  30. package/dist/ui/internal/sidebar.svelte.js +11 -1
  31. package/dist/ui/web.js +4 -2
  32. package/package.json +5 -1
  33. package/dist/cli/chunk-OVWODUTJ.js.map +0 -7
  34. package/dist/cli/chunk-QAXEOZ43.js.map +0 -7
  35. package/dist/cli/clickhouse-ZN5AN2UL.js.map +0 -7
  36. /package/dist/cli/{bigQuery-I3F46SC6.js.map → bigQuery-YIWXZPY6.js.map} +0 -0
  37. /package/dist/cli/{duckdb-IYBIO5KJ.js.map → duckdb-V6PJEA7H.js.map} +0 -0
  38. /package/dist/cli/{snowflake-MOQB5GA4.js.map → snowflake-HVSTYBLB.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  config
3
- } from "./chunk-QAXEOZ43.js";
3
+ } from "./chunk-SQVXTHE5.js";
4
4
 
5
5
  // ../lang/types.ts
6
6
  var SCALAR_TYPE_ALIASES = {
@@ -211,11 +211,41 @@ function multiGrainMessage(paths) {
211
211
  function normalizeTemporalPart(rawPart) {
212
212
  return String(rawPart || "").trim().replace(/^['"]|['"]$/g, "").toLowerCase();
213
213
  }
214
- function inferTemporalPart(rawPart) {
214
+ function inferGrain(rawPart) {
215
215
  let normalized = normalizeTemporalPart(rawPart);
216
216
  if (!normalized) return;
217
- if (/^week(?:\([a-z]+\))?$/.test(normalized)) return "week";
218
- let parts = {
217
+ if (/^week(?:\([a-z]+\))?$/.test(normalized) || normalized == "isoweek") return { timeGrain: "week", defaultName: "week" };
218
+ if (normalized == "isoyear") return { timeGrain: "year", defaultName: "year" };
219
+ switch (normalized) {
220
+ case "year":
221
+ case "quarter":
222
+ case "month":
223
+ case "day":
224
+ case "hour":
225
+ case "minute":
226
+ case "second":
227
+ return { timeGrain: normalized, defaultName: normalized };
228
+ }
229
+ }
230
+ function inferTimeOrdinal(rawPart, dialect) {
231
+ let normalized = normalizeTemporalPart(rawPart);
232
+ if (normalized == "year" || normalized == "isoyear") return { timeGrain: "year", defaultName: "year" };
233
+ let timeOrdinal;
234
+ if (normalized == "hour") timeOrdinal = "hour_of_day";
235
+ if (normalized == "day" || normalized == "dayofmonth") timeOrdinal = "day_of_month";
236
+ if (normalized == "dayofyear" || normalized == "doy") timeOrdinal = "day_of_year";
237
+ if (normalized == "week" || normalized == "weekofyear" || normalized == "isoweek" || /^week(?:\([a-z]+\))?$/.test(normalized)) timeOrdinal = "week_of_year";
238
+ if (normalized == "month") timeOrdinal = "month_of_year";
239
+ if (normalized == "quarter") timeOrdinal = "quarter_of_year";
240
+ if (normalized == "isodow" || normalized == "dayofweekiso" || normalized == "iso_dayofweek") timeOrdinal = "dow_1m";
241
+ if (normalized == "dayofweek" || normalized == "dow" || normalized == "weekday") {
242
+ if (dialect == "bigquery") timeOrdinal = "dow_1s";
243
+ else if (dialect == "clickhouse") timeOrdinal = "dow_1m";
244
+ else timeOrdinal = "dow_0s";
245
+ }
246
+ if (!timeOrdinal) return;
247
+ if (/^week(?:\([a-z]+\))?$/.test(normalized)) return { timeOrdinal, defaultName: "week" };
248
+ let defaultNames = {
219
249
  dow: "dayofweek",
220
250
  weekday: "dayofweek",
221
251
  dayofmonth: "day",
@@ -224,52 +254,7 @@ function inferTemporalPart(rawPart) {
224
254
  dayofweekiso: "isodow",
225
255
  iso_dayofweek: "isodow"
226
256
  };
227
- return parts[normalized] || normalized;
228
- }
229
- function inferTemporalGrain(rawPart) {
230
- let normalized = normalizeTemporalPart(rawPart);
231
- if (!normalized) return;
232
- if (/^week(?:\([a-z]+\))?$/.test(normalized) || normalized == "isoweek") return "week";
233
- if (normalized == "isoyear") return "year";
234
- let grains = {
235
- year: "year",
236
- quarter: "quarter",
237
- month: "month",
238
- day: "day",
239
- hour: "hour",
240
- minute: "minute",
241
- second: "second"
242
- };
243
- return grains[normalized];
244
- }
245
- function inferTemporalGrainMetadata(rawPart) {
246
- let timeGrain = inferTemporalGrain(rawPart);
247
- return timeGrain ? { timeGrain, defaultName: timeGrain } : void 0;
248
- }
249
- function inferTemporalOrdinal(rawPart, dialect) {
250
- let normalized = normalizeTemporalPart(rawPart);
251
- if (!normalized) return;
252
- if (normalized == "hour") return "hour_of_day";
253
- if (normalized == "day" || normalized == "dayofmonth") return "day_of_month";
254
- if (normalized == "dayofyear" || normalized == "doy") return "day_of_year";
255
- if (normalized == "week" || normalized == "weekofyear" || normalized == "isoweek") return "week_of_year";
256
- if (normalized == "month") return "month_of_year";
257
- if (normalized == "quarter") return "quarter_of_year";
258
- if (normalized == "isodow" || normalized == "dayofweekiso" || normalized == "iso_dayofweek") return "dow_1m";
259
- if (normalized == "dayofweek" || normalized == "dow" || normalized == "weekday") {
260
- if (dialect == "bigquery") return "dow_1s";
261
- if (dialect == "clickhouse") return "dow_1m";
262
- return "dow_0s";
263
- }
264
- }
265
- function inferTemporalExtractionMetadata(rawPart, dialect) {
266
- let timePart = inferTemporalPart(rawPart);
267
- let timeOrdinal = inferTemporalOrdinal(rawPart, dialect);
268
- if (!timePart && !timeOrdinal) return;
269
- return {
270
- ...timePart ? { timePart, defaultName: timePart } : {},
271
- ...timeOrdinal ? { timeOrdinal } : {}
272
- };
257
+ return { timeOrdinal, defaultName: defaultNames[normalized] || normalized };
273
258
  }
274
259
 
275
260
  // ../lang/util.ts
@@ -2296,7 +2281,7 @@ var bigQueryFunctions = [
2296
2281
  { name: "date_part", type: "kw", description: "The date part to truncate to." }
2297
2282
  ],
2298
2283
  returns: "T",
2299
- metadata: (args) => inferTemporalGrainMetadata(args[1]?.sql),
2284
+ metadata: (args) => inferGrain(args[1]?.sql),
2300
2285
  sqlTemplate: "DATE_TRUNC(${date_expression}, ${date_part})"
2301
2286
  },
2302
2287
  {
@@ -2499,7 +2484,7 @@ var bigQueryFunctions = [
2499
2484
  { name: "part", type: "string", description: "The part to truncate to." }
2500
2485
  ],
2501
2486
  returns: "datetime",
2502
- metadata: (args) => inferTemporalGrainMetadata(args[1]?.sql)
2487
+ metadata: (args) => inferGrain(args[1]?.sql)
2503
2488
  },
2504
2489
  {
2505
2490
  name: "format_datetime",
@@ -2657,7 +2642,7 @@ var bigQueryFunctions = [
2657
2642
  { name: "part", type: "string", description: "The part to truncate to." }
2658
2643
  ],
2659
2644
  returns: "time",
2660
- metadata: (args) => inferTemporalGrainMetadata(args[1]?.sql)
2645
+ metadata: (args) => inferGrain(args[1]?.sql)
2661
2646
  },
2662
2647
  {
2663
2648
  name: "format_time",
@@ -2811,7 +2796,7 @@ var bigQueryFunctions = [
2811
2796
  { name: "time_zone", type: "string?", description: "The time zone to use." }
2812
2797
  ],
2813
2798
  returns: "timestamp",
2814
- metadata: (args) => inferTemporalGrainMetadata(args[1]?.sql)
2799
+ metadata: (args) => inferGrain(args[1]?.sql)
2815
2800
  },
2816
2801
  {
2817
2802
  name: "format_timestamp",
@@ -4646,7 +4631,7 @@ var clickHouseFunctions = [
4646
4631
  { name: "datetime", type: ["date", "timestamp"] }
4647
4632
  ],
4648
4633
  returns: "timestamp",
4649
- metadata: (args) => inferTemporalGrainMetadata(args[0]?.sql),
4634
+ metadata: (args) => inferGrain(args[0]?.sql),
4650
4635
  sqlTemplate: "DATE_TRUNC(${date_part}, ${datetime})"
4651
4636
  },
4652
4637
  {
@@ -4736,7 +4721,7 @@ var clickHouseFunctions = [
4736
4721
  url: `${click}/functions/date-time-functions#todayofmonth`,
4737
4722
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4738
4723
  returns: "number",
4739
- metadata: inferTemporalExtractionMetadata("day", "clickhouse"),
4724
+ metadata: inferTimeOrdinal("day", "clickhouse"),
4740
4725
  sqlName: "toDayOfMonth",
4741
4726
  aliases: ["to_day_of_month"]
4742
4727
  },
@@ -4750,7 +4735,7 @@ var clickHouseFunctions = [
4750
4735
  url: `${click}/functions/date-time-functions#todayofyear`,
4751
4736
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4752
4737
  returns: "number",
4753
- metadata: inferTemporalExtractionMetadata("dayofyear", "clickhouse"),
4738
+ metadata: inferTimeOrdinal("dayofyear", "clickhouse"),
4754
4739
  sqlName: "toDayOfYear",
4755
4740
  aliases: ["to_day_of_year"]
4756
4741
  },
@@ -4764,7 +4749,7 @@ var clickHouseFunctions = [
4764
4749
  url: `${click}/functions/date-time-functions#todayofweek`,
4765
4750
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4766
4751
  returns: "number",
4767
- metadata: inferTemporalExtractionMetadata("dayofweek", "clickhouse"),
4752
+ metadata: inferTimeOrdinal("dayofweek", "clickhouse"),
4768
4753
  sqlName: "toDayOfWeek",
4769
4754
  aliases: ["to_day_of_week"]
4770
4755
  },
@@ -4778,7 +4763,7 @@ var clickHouseFunctions = [
4778
4763
  url: `${click}/functions/date-time-functions#tohour`,
4779
4764
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4780
4765
  returns: "number",
4781
- metadata: inferTemporalExtractionMetadata("hour", "clickhouse"),
4766
+ metadata: inferTimeOrdinal("hour", "clickhouse"),
4782
4767
  sqlName: "toHour",
4783
4768
  aliases: ["to_hour"]
4784
4769
  },
@@ -4792,7 +4777,7 @@ var clickHouseFunctions = [
4792
4777
  url: `${click}/functions/date-time-functions#tominute`,
4793
4778
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4794
4779
  returns: "number",
4795
- metadata: inferTemporalExtractionMetadata("minute", "clickhouse"),
4780
+ metadata: inferTimeOrdinal("minute", "clickhouse"),
4796
4781
  sqlName: "toMinute",
4797
4782
  aliases: ["to_minute"]
4798
4783
  },
@@ -4806,7 +4791,7 @@ var clickHouseFunctions = [
4806
4791
  url: `${click}/functions/date-time-functions#tomonth`,
4807
4792
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4808
4793
  returns: "number",
4809
- metadata: inferTemporalExtractionMetadata("month", "clickhouse"),
4794
+ metadata: inferTimeOrdinal("month", "clickhouse"),
4810
4795
  sqlName: "toMonth",
4811
4796
  aliases: ["to_month"]
4812
4797
  },
@@ -4820,7 +4805,7 @@ var clickHouseFunctions = [
4820
4805
  url: `${click}/functions/date-time-functions#toquarter`,
4821
4806
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4822
4807
  returns: "number",
4823
- metadata: inferTemporalExtractionMetadata("quarter", "clickhouse"),
4808
+ metadata: inferTimeOrdinal("quarter", "clickhouse"),
4824
4809
  sqlName: "toQuarter",
4825
4810
  aliases: ["to_quarter"]
4826
4811
  },
@@ -4834,7 +4819,7 @@ var clickHouseFunctions = [
4834
4819
  url: `${click}/functions/date-time-functions#tosecond`,
4835
4820
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4836
4821
  returns: "number",
4837
- metadata: inferTemporalExtractionMetadata("second", "clickhouse"),
4822
+ metadata: inferTimeOrdinal("second", "clickhouse"),
4838
4823
  sqlName: "toSecond",
4839
4824
  aliases: ["to_second"]
4840
4825
  },
@@ -4848,7 +4833,7 @@ var clickHouseFunctions = [
4848
4833
  url: `${click}/functions/date-time-functions#toweek`,
4849
4834
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4850
4835
  returns: "number",
4851
- metadata: inferTemporalExtractionMetadata("week", "clickhouse"),
4836
+ metadata: inferTimeOrdinal("week", "clickhouse"),
4852
4837
  sqlName: "toWeek",
4853
4838
  aliases: ["to_week"]
4854
4839
  },
@@ -4932,7 +4917,7 @@ var clickHouseFunctions = [
4932
4917
  url: `${click}/functions/date-time-functions#toyear`,
4933
4918
  args: [{ name: "datetime", type: ["date", "timestamp"] }],
4934
4919
  returns: "number",
4935
- metadata: inferTemporalExtractionMetadata("year", "clickhouse"),
4920
+ metadata: inferTimeOrdinal("year", "clickhouse"),
4936
4921
  sqlName: "toYear",
4937
4922
  aliases: ["to_year"]
4938
4923
  }
@@ -6707,7 +6692,7 @@ var duckDbFunctions = [
6707
6692
  { name: "date", type: ["date", "timestamp"] }
6708
6693
  ],
6709
6694
  returns: "number",
6710
- metadata: (args) => inferTemporalExtractionMetadata(args[0]?.sql, "duckdb")
6695
+ metadata: (args) => inferTimeOrdinal(args[0]?.sql, "duckdb")
6711
6696
  },
6712
6697
  {
6713
6698
  name: "year",
@@ -6719,7 +6704,7 @@ var duckDbFunctions = [
6719
6704
  url: `${duck}/datepart.html`,
6720
6705
  args: [{ name: "date", type: ["date", "timestamp"] }],
6721
6706
  returns: "number",
6722
- metadata: inferTemporalExtractionMetadata("year", "duckdb")
6707
+ metadata: inferTimeOrdinal("year", "duckdb")
6723
6708
  },
6724
6709
  {
6725
6710
  name: "quarter",
@@ -6731,7 +6716,7 @@ var duckDbFunctions = [
6731
6716
  url: `${duck}/datepart.html`,
6732
6717
  args: [{ name: "date", type: ["date", "timestamp"] }],
6733
6718
  returns: "number",
6734
- metadata: inferTemporalExtractionMetadata("quarter", "duckdb")
6719
+ metadata: inferTimeOrdinal("quarter", "duckdb")
6735
6720
  },
6736
6721
  {
6737
6722
  name: "month",
@@ -6743,7 +6728,7 @@ var duckDbFunctions = [
6743
6728
  url: `${duck}/datepart.html`,
6744
6729
  args: [{ name: "date", type: ["date", "timestamp"] }],
6745
6730
  returns: "number",
6746
- metadata: inferTemporalExtractionMetadata("month", "duckdb")
6731
+ metadata: inferTimeOrdinal("month", "duckdb")
6747
6732
  },
6748
6733
  {
6749
6734
  name: "week",
@@ -6755,7 +6740,7 @@ var duckDbFunctions = [
6755
6740
  url: `${duck}/datepart.html`,
6756
6741
  args: [{ name: "date", type: ["date", "timestamp"] }],
6757
6742
  returns: "number",
6758
- metadata: inferTemporalExtractionMetadata("week", "duckdb")
6743
+ metadata: inferTimeOrdinal("week", "duckdb")
6759
6744
  },
6760
6745
  {
6761
6746
  name: "weekofyear",
@@ -6767,7 +6752,7 @@ var duckDbFunctions = [
6767
6752
  url: `${duck}/datepart.html`,
6768
6753
  args: [{ name: "date", type: ["date", "timestamp"] }],
6769
6754
  returns: "number",
6770
- metadata: inferTemporalExtractionMetadata("weekofyear", "duckdb")
6755
+ metadata: inferTimeOrdinal("weekofyear", "duckdb")
6771
6756
  },
6772
6757
  {
6773
6758
  name: "day",
@@ -6779,7 +6764,7 @@ var duckDbFunctions = [
6779
6764
  url: `${duck}/datepart.html`,
6780
6765
  args: [{ name: "date", type: ["date", "timestamp"] }],
6781
6766
  returns: "number",
6782
- metadata: inferTemporalExtractionMetadata("day", "duckdb")
6767
+ metadata: inferTimeOrdinal("day", "duckdb")
6783
6768
  },
6784
6769
  {
6785
6770
  name: "dayofmonth",
@@ -6791,7 +6776,7 @@ var duckDbFunctions = [
6791
6776
  url: `${duck}/datepart.html`,
6792
6777
  args: [{ name: "date", type: ["date", "timestamp"] }],
6793
6778
  returns: "number",
6794
- metadata: inferTemporalExtractionMetadata("dayofmonth", "duckdb")
6779
+ metadata: inferTimeOrdinal("dayofmonth", "duckdb")
6795
6780
  },
6796
6781
  {
6797
6782
  name: "dayofweek",
@@ -6803,7 +6788,7 @@ var duckDbFunctions = [
6803
6788
  url: `${duck}/datepart.html`,
6804
6789
  args: [{ name: "date", type: ["date", "timestamp"] }],
6805
6790
  returns: "number",
6806
- metadata: inferTemporalExtractionMetadata("dayofweek", "duckdb")
6791
+ metadata: inferTimeOrdinal("dayofweek", "duckdb")
6807
6792
  },
6808
6793
  {
6809
6794
  name: "weekday",
@@ -6815,7 +6800,7 @@ var duckDbFunctions = [
6815
6800
  url: `${duck}/datepart.html`,
6816
6801
  args: [{ name: "date", type: ["date", "timestamp"] }],
6817
6802
  returns: "number",
6818
- metadata: inferTemporalExtractionMetadata("weekday", "duckdb")
6803
+ metadata: inferTimeOrdinal("weekday", "duckdb")
6819
6804
  },
6820
6805
  {
6821
6806
  name: "dayofyear",
@@ -6827,7 +6812,7 @@ var duckDbFunctions = [
6827
6812
  url: `${duck}/datepart.html`,
6828
6813
  args: [{ name: "date", type: ["date", "timestamp"] }],
6829
6814
  returns: "number",
6830
- metadata: inferTemporalExtractionMetadata("dayofyear", "duckdb")
6815
+ metadata: inferTimeOrdinal("dayofyear", "duckdb")
6831
6816
  },
6832
6817
  {
6833
6818
  name: "hour",
@@ -6839,7 +6824,7 @@ var duckDbFunctions = [
6839
6824
  url: `${duck}/datepart.html`,
6840
6825
  args: [{ name: "date", type: ["date", "timestamp"] }],
6841
6826
  returns: "number",
6842
- metadata: inferTemporalExtractionMetadata("hour", "duckdb")
6827
+ metadata: inferTimeOrdinal("hour", "duckdb")
6843
6828
  },
6844
6829
  {
6845
6830
  name: "minute",
@@ -6851,7 +6836,7 @@ var duckDbFunctions = [
6851
6836
  url: `${duck}/datepart.html`,
6852
6837
  args: [{ name: "date", type: ["date", "timestamp"] }],
6853
6838
  returns: "number",
6854
- metadata: inferTemporalExtractionMetadata("minute", "duckdb")
6839
+ metadata: inferTimeOrdinal("minute", "duckdb")
6855
6840
  },
6856
6841
  {
6857
6842
  name: "second",
@@ -6863,7 +6848,7 @@ var duckDbFunctions = [
6863
6848
  url: `${duck}/datepart.html`,
6864
6849
  args: [{ name: "date", type: ["date", "timestamp"] }],
6865
6850
  returns: "number",
6866
- metadata: inferTemporalExtractionMetadata("second", "duckdb")
6851
+ metadata: inferTimeOrdinal("second", "duckdb")
6867
6852
  },
6868
6853
  {
6869
6854
  name: "isodow",
@@ -6875,7 +6860,7 @@ var duckDbFunctions = [
6875
6860
  url: `${duck}/datepart.html`,
6876
6861
  args: [{ name: "date", type: ["date", "timestamp"] }],
6877
6862
  returns: "number",
6878
- metadata: inferTemporalExtractionMetadata("isodow", "duckdb")
6863
+ metadata: inferTimeOrdinal("isodow", "duckdb")
6879
6864
  },
6880
6865
  {
6881
6866
  name: "isoyear",
@@ -6887,7 +6872,7 @@ var duckDbFunctions = [
6887
6872
  url: `${duck}/datepart.html`,
6888
6873
  args: [{ name: "date", type: ["date", "timestamp"] }],
6889
6874
  returns: "number",
6890
- metadata: inferTemporalExtractionMetadata("isoyear", "duckdb")
6875
+ metadata: inferTimeOrdinal("isoyear", "duckdb")
6891
6876
  },
6892
6877
  {
6893
6878
  name: "date_sub",
@@ -7187,7 +7172,7 @@ var duckDbFunctions = [
7187
7172
  { name: "timestamp", type: ["date", "timestamp"] }
7188
7173
  ],
7189
7174
  returns: "timestamp",
7190
- metadata: (args) => inferTemporalGrainMetadata(args[0]?.sql),
7175
+ metadata: (args) => inferGrain(args[0]?.sql),
7191
7176
  sqlTemplate: "DATE_TRUNC(${part}, ${timestamp})"
7192
7177
  },
7193
7178
  {
@@ -9085,7 +9070,7 @@ var snowflakeFunctions = [
9085
9070
  { name: "date_expr", type: ["date", "timestamp"] }
9086
9071
  ],
9087
9072
  returns: "number",
9088
- metadata: (args) => inferTemporalExtractionMetadata(args[0]?.sql, "snowflake")
9073
+ metadata: (args) => inferTimeOrdinal(args[0]?.sql, "snowflake")
9089
9074
  },
9090
9075
  {
9091
9076
  name: "dateadd",
@@ -9225,7 +9210,7 @@ var snowflakeFunctions = [
9225
9210
  { name: "date_or_time_part", type: "string" }
9226
9211
  ],
9227
9212
  returns: "timestamp",
9228
- metadata: (args) => inferTemporalGrainMetadata(args[2]?.sql)
9213
+ metadata: (args) => inferGrain(args[2]?.sql)
9229
9214
  },
9230
9215
  {
9231
9216
  name: "timestamp_from_parts",
@@ -9272,7 +9257,7 @@ var snowflakeFunctions = [
9272
9257
  url: `${sf}/year`,
9273
9258
  args: [{ name: "date_expr", type: ["date", "timestamp"] }],
9274
9259
  returns: "number",
9275
- metadata: inferTemporalExtractionMetadata("year", "snowflake")
9260
+ metadata: inferTimeOrdinal("year", "snowflake")
9276
9261
  },
9277
9262
  {
9278
9263
  name: "month",
@@ -9284,7 +9269,7 @@ var snowflakeFunctions = [
9284
9269
  url: `${sf}/year`,
9285
9270
  args: [{ name: "date_expr", type: ["date", "timestamp"] }],
9286
9271
  returns: "number",
9287
- metadata: inferTemporalExtractionMetadata("month", "snowflake")
9272
+ metadata: inferTimeOrdinal("month", "snowflake")
9288
9273
  },
9289
9274
  {
9290
9275
  name: "day",
@@ -9298,7 +9283,7 @@ var snowflakeFunctions = [
9298
9283
  args: [{ name: "date_expr", type: ["date", "timestamp"] }],
9299
9284
  returns: "number",
9300
9285
  aliases: ["dayofmonth"],
9301
- metadata: inferTemporalExtractionMetadata("day", "snowflake")
9286
+ metadata: inferTimeOrdinal("day", "snowflake")
9302
9287
  },
9303
9288
  {
9304
9289
  name: "dayofweek",
@@ -9310,7 +9295,7 @@ var snowflakeFunctions = [
9310
9295
  url: `${sf}/year`,
9311
9296
  args: [{ name: "date_expr", type: ["date", "timestamp"] }],
9312
9297
  returns: "number",
9313
- metadata: inferTemporalExtractionMetadata("dayofweek", "snowflake")
9298
+ metadata: inferTimeOrdinal("dayofweek", "snowflake")
9314
9299
  },
9315
9300
  {
9316
9301
  name: "dayofyear",
@@ -9322,7 +9307,7 @@ var snowflakeFunctions = [
9322
9307
  url: `${sf}/year`,
9323
9308
  args: [{ name: "date_expr", type: ["date", "timestamp"] }],
9324
9309
  returns: "number",
9325
- metadata: inferTemporalExtractionMetadata("dayofyear", "snowflake")
9310
+ metadata: inferTimeOrdinal("dayofyear", "snowflake")
9326
9311
  },
9327
9312
  {
9328
9313
  name: "week",
@@ -9336,7 +9321,7 @@ var snowflakeFunctions = [
9336
9321
  args: [{ name: "date_expr", type: ["date", "timestamp"] }],
9337
9322
  returns: "number",
9338
9323
  aliases: ["weekofyear"],
9339
- metadata: inferTemporalExtractionMetadata("week", "snowflake")
9324
+ metadata: inferTimeOrdinal("week", "snowflake")
9340
9325
  },
9341
9326
  {
9342
9327
  name: "quarter",
@@ -9348,7 +9333,7 @@ var snowflakeFunctions = [
9348
9333
  url: `${sf}/year`,
9349
9334
  args: [{ name: "date_expr", type: ["date", "timestamp"] }],
9350
9335
  returns: "number",
9351
- metadata: inferTemporalExtractionMetadata("quarter", "snowflake")
9336
+ metadata: inferTimeOrdinal("quarter", "snowflake")
9352
9337
  },
9353
9338
  {
9354
9339
  name: "hour",
@@ -9360,7 +9345,7 @@ var snowflakeFunctions = [
9360
9345
  url: `${sf}/hour-minute-second`,
9361
9346
  args: [{ name: "time_expr", type: ["date", "timestamp"] }],
9362
9347
  returns: "number",
9363
- metadata: inferTemporalExtractionMetadata("hour", "snowflake")
9348
+ metadata: inferTimeOrdinal("hour", "snowflake")
9364
9349
  },
9365
9350
  {
9366
9351
  name: "minute",
@@ -9372,7 +9357,7 @@ var snowflakeFunctions = [
9372
9357
  url: `${sf}/hour-minute-second`,
9373
9358
  args: [{ name: "time_expr", type: ["date", "timestamp"] }],
9374
9359
  returns: "number",
9375
- metadata: inferTemporalExtractionMetadata("minute", "snowflake")
9360
+ metadata: inferTimeOrdinal("minute", "snowflake")
9376
9361
  },
9377
9362
  {
9378
9363
  name: "second",
@@ -9384,7 +9369,7 @@ var snowflakeFunctions = [
9384
9369
  url: `${sf}/hour-minute-second`,
9385
9370
  args: [{ name: "time_expr", type: ["date", "timestamp"] }],
9386
9371
  returns: "number",
9387
- metadata: inferTemporalExtractionMetadata("second", "snowflake")
9372
+ metadata: inferTimeOrdinal("second", "snowflake")
9388
9373
  },
9389
9374
  // ============================================================================
9390
9375
  // Conditional Functions
@@ -9630,7 +9615,7 @@ var snowflakeFunctions = [
9630
9615
  { name: "date_expr", type: ["date", "timestamp"] }
9631
9616
  ],
9632
9617
  returns: "timestamp",
9633
- metadata: (args) => inferTemporalGrainMetadata(args[0]?.sql),
9618
+ metadata: (args) => inferGrain(args[0]?.sql),
9634
9619
  sqlTemplate: "DATE_TRUNC(${part}, ${date_expr})"
9635
9620
  },
9636
9621
  {
@@ -10455,9 +10440,21 @@ function isFence(event) {
10455
10440
 
10456
10441
  // ../lang/metadata.ts
10457
10442
  var embeddedMetadataPair = /(^|\s)(#)([A-Za-z0-9_-]+)(?:\s*=\s*("(?:[^"\\]|\\.)*"|[^\s#]+)|(?=(?:\s*(?:#|--|$))))/g;
10458
- function extractLeadingMetadata(node) {
10443
+ var isoCurrencyCodes = new Set(Intl.supportedValuesOf("currency").map((code) => code.toLowerCase()));
10444
+ var metadataKeyRules = {
10445
+ ratio: { kind: "flag" },
10446
+ pct: { kind: "flag" },
10447
+ pii: { kind: "flag" },
10448
+ currency: { kind: "currency" },
10449
+ unit: { kind: "string" },
10450
+ timeGrain: { kind: "enum", values: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"] },
10451
+ timeOrdinal: { kind: "enum", values: ["hour_of_day", "day_of_month", "day_of_year", "week_of_year", "month_of_year", "quarter_of_year", "dow_0s", "dow_1s", "dow_1m"] },
10452
+ description: { kind: "string" }
10453
+ };
10454
+ var validMetadataKeys = Object.keys(metadataKeyRules);
10455
+ function extractLeadingMetadataDetails(node) {
10459
10456
  let src = getFile(node).contents;
10460
- if (!src) return {};
10457
+ if (!src) return { metadata: {}, entries: [] };
10461
10458
  let pos = node.from;
10462
10459
  let currentLineStart = src.lastIndexOf("\n", Math.max(0, pos - 1)) + 1;
10463
10460
  let endOfPrevLine = currentLineStart - 1;
@@ -10468,9 +10465,10 @@ function extractLeadingMetadata(node) {
10468
10465
  let cursor = endOfPrevLine;
10469
10466
  while (cursor >= 0) {
10470
10467
  let startOfLine = src.lastIndexOf("\n", Math.max(0, cursor - 1)) + 1;
10471
- let trimmed = src.slice(startOfLine, cursor).trim();
10468
+ let line = src.slice(startOfLine, cursor);
10469
+ let trimmed = line.trim();
10472
10470
  if (!trimmed) break;
10473
- let comment = parseCommentLine(trimmed);
10471
+ let comment = parseCommentLine(line, startOfLine);
10474
10472
  if (!comment) break;
10475
10473
  comments.push(comment);
10476
10474
  cursor = startOfLine - 1;
@@ -10479,63 +10477,161 @@ function extractLeadingMetadata(node) {
10479
10477
  comments.reverse();
10480
10478
  let metadata = {};
10481
10479
  let descriptionLines = [];
10482
- for (let comment of comments) consumeComment(comment, metadata, descriptionLines);
10480
+ let entries = [];
10481
+ for (let comment of comments) consumeComment(comment, metadata, descriptionLines, entries);
10483
10482
  let endPos = node.to;
10484
10483
  let endOfLine = src.indexOf("\n", endPos);
10485
10484
  if (endOfLine === -1) endOfLine = src.length;
10486
10485
  let after = src.slice(endPos, endOfLine);
10487
- let trailing = parseTrailingComment(after);
10488
- if (trailing) consumeComment(trailing, metadata, descriptionLines);
10486
+ let trailing = parseTrailingComment(after, endPos);
10487
+ if (trailing) consumeComment(trailing, metadata, descriptionLines, entries);
10489
10488
  if (descriptionLines.length) metadata.description = descriptionLines.join(" ");
10490
- return metadata;
10489
+ return { metadata, entries };
10490
+ }
10491
+ function validateMetadataEntries(entries) {
10492
+ let diagnostics = [];
10493
+ for (let entry of entries) {
10494
+ let rule = metadataKeyRules[entry.key];
10495
+ if (!rule) {
10496
+ diagnostics.push({
10497
+ message: `Unknown metadata key "#${entry.key}". Expected one of: ${validMetadataKeys.join(", ")}`,
10498
+ from: entry.from,
10499
+ to: entry.to
10500
+ });
10501
+ continue;
10502
+ }
10503
+ if (rule.kind == "flag") {
10504
+ if (!entry.hasValue || entry.rawValue == "true") continue;
10505
+ diagnostics.push({
10506
+ message: `Metadata "#${entry.key}" is a flag; use "#${entry.key}" or "#${entry.key}=true".`,
10507
+ from: entry.valueFrom ?? entry.from,
10508
+ to: entry.valueTo ?? entry.to
10509
+ });
10510
+ continue;
10511
+ }
10512
+ if (rule.kind == "string") {
10513
+ if (entry.hasValue && entry.value.trim()) continue;
10514
+ diagnostics.push({
10515
+ message: `Metadata "#${entry.key}" requires a value.`,
10516
+ from: entry.from,
10517
+ to: entry.to
10518
+ });
10519
+ continue;
10520
+ }
10521
+ if (rule.kind == "currency") {
10522
+ if (!entry.hasValue || !entry.value.trim()) {
10523
+ diagnostics.push({
10524
+ message: 'Metadata "#currency" requires a value.',
10525
+ from: entry.from,
10526
+ to: entry.to
10527
+ });
10528
+ continue;
10529
+ }
10530
+ if (isoCurrencyCodes.has(entry.value.toLowerCase())) continue;
10531
+ diagnostics.push({
10532
+ message: `Invalid value "${entry.value}" for "#currency". Expected an ISO 4217 currency code.`,
10533
+ from: entry.valueFrom ?? entry.from,
10534
+ to: entry.valueTo ?? entry.to
10535
+ });
10536
+ continue;
10537
+ }
10538
+ if (rule.values.includes(entry.value)) continue;
10539
+ diagnostics.push({
10540
+ message: `Invalid value "${entry.value}" for "#${entry.key}". Expected one of: ${rule.values.join(", ")}`,
10541
+ from: entry.valueFrom ?? entry.from,
10542
+ to: entry.valueTo ?? entry.to
10543
+ });
10544
+ }
10545
+ return diagnostics;
10491
10546
  }
10492
- function parseCommentLine(trimmed) {
10493
- if (trimmed.startsWith("--")) return { kind: "dash", text: trimmed.slice(2).trimStart() };
10494
- if (trimmed.startsWith("#")) return { kind: "hash", text: trimmed.slice(1).trimStart() };
10547
+ function parseCommentLine(line, lineStart) {
10548
+ let leading = line.match(/^\s*/)?.[0].length || 0;
10549
+ let markerFrom = lineStart + leading;
10550
+ let trimmed = line.slice(leading);
10551
+ if (trimmed.startsWith("--")) return withTrimmedText("dash", line, lineStart, markerFrom, leading + 2);
10552
+ if (trimmed.startsWith("#")) return withTrimmedText("hash", line, lineStart, markerFrom, leading + 1);
10495
10553
  }
10496
- function parseTrailingComment(after) {
10554
+ function parseTrailingComment(after, afterStart) {
10497
10555
  let dashIdx = after.indexOf("--");
10498
10556
  let hashIdx = after.indexOf("#");
10499
10557
  let commentIdx = minNonNegative(dashIdx, hashIdx);
10500
10558
  if (commentIdx === -1) return void 0;
10501
10559
  let between2 = after.slice(0, commentIdx);
10502
10560
  if (!/^[\s,]*$/.test(between2)) return void 0;
10503
- if (hashIdx !== -1 && hashIdx === commentIdx) return { kind: "hash", text: after.slice(hashIdx + 1).trimStart() };
10504
- return { kind: "dash", text: after.slice(dashIdx + 2).trimStart() };
10561
+ let markerFrom = afterStart + commentIdx;
10562
+ if (hashIdx !== -1 && hashIdx === commentIdx) return withTrimmedText("hash", after, afterStart, markerFrom, hashIdx + 1);
10563
+ return withTrimmedText("dash", after, afterStart, markerFrom, dashIdx + 2);
10505
10564
  }
10506
- function consumeComment(comment, metadata, descriptionLines) {
10565
+ function withTrimmedText(kind, raw, rawFrom, markerFrom, textStart) {
10566
+ let whitespace = raw.slice(textStart).match(/^\s*/)?.[0].length || 0;
10567
+ return { kind, text: raw.slice(textStart + whitespace), from: rawFrom + textStart + whitespace, markerFrom };
10568
+ }
10569
+ function consumeComment(comment, metadata, descriptionLines, entries) {
10507
10570
  if (comment.kind === "hash") {
10508
- let cleaned = extractHashMetadata(comment.text, metadata);
10571
+ let cleaned = extractHashMetadata(comment, metadata, entries);
10509
10572
  let trailingDescription = parseHashCommentDescription(cleaned);
10510
10573
  if (trailingDescription) descriptionLines.push(trailingDescription);
10511
10574
  return;
10512
10575
  }
10513
10576
  if (comment.text.startsWith("#")) return;
10514
- let description = extractMetadataPairs(comment.text, metadata);
10577
+ let description = extractMetadataPairs(comment.text, comment.from, metadata, entries);
10515
10578
  if (description) descriptionLines.push(description);
10516
10579
  }
10517
- function extractHashMetadata(text, metadata) {
10580
+ function extractHashMetadata(comment, metadata, entries) {
10581
+ let text = comment.text;
10518
10582
  let cursor = skipWhitespace2(text, 0);
10519
- let pair = matchMetadataToken(text, cursor, false);
10583
+ let pair = matchMetadataToken(text, cursor, false, comment.from, comment.markerFrom);
10520
10584
  if (!pair) return text.trim();
10521
- metadata[pair.key] = parseMetadataValue(pair.rawValue);
10585
+ consumePair(pair, metadata, entries);
10522
10586
  cursor = pair.end;
10523
10587
  while (true) {
10524
10588
  let nextStart = skipWhitespace2(text, cursor);
10525
10589
  if (text[nextStart] !== "#") return text.slice(nextStart).trim();
10526
- let nextPair = matchMetadataToken(text, nextStart, true);
10590
+ let nextPair = matchMetadataToken(text, nextStart, true, comment.from);
10527
10591
  if (!nextPair) return text.slice(nextStart).trim();
10528
- metadata[nextPair.key] = parseMetadataValue(nextPair.rawValue);
10592
+ consumePair(nextPair, metadata, entries);
10529
10593
  cursor = nextPair.end;
10530
10594
  }
10531
10595
  }
10532
- function extractMetadataPairs(text, metadata) {
10533
- let cleaned = text.replace(embeddedMetadataPair, (_match, leadingSpace, _hash, key, rawValue) => {
10534
- if (key) metadata[key] = parseMetadataValue(rawValue);
10596
+ function extractMetadataPairs(text, textFrom, metadata, entries) {
10597
+ let cleaned = text.replace(embeddedMetadataPair, (match, leadingSpace, _hash, key, rawValue, offset2) => {
10598
+ if (key) {
10599
+ let hashStart = textFrom + offset2 + leadingSpace.length;
10600
+ let valueOffset = rawValue ? match.indexOf(rawValue) : -1;
10601
+ consumePair(
10602
+ {
10603
+ key,
10604
+ rawValue,
10605
+ keyFrom: hashStart + 1,
10606
+ keyTo: hashStart + 1 + key.length,
10607
+ from: hashStart,
10608
+ to: hashStart + 1 + key.length,
10609
+ valueFrom: valueOffset >= 0 ? textFrom + offset2 + valueOffset : void 0,
10610
+ valueTo: valueOffset >= 0 ? textFrom + offset2 + valueOffset + rawValue.length : void 0,
10611
+ end: offset2 + match.length
10612
+ },
10613
+ metadata,
10614
+ entries
10615
+ );
10616
+ }
10535
10617
  return leadingSpace ? " " : "";
10536
10618
  });
10537
10619
  return cleaned.replace(/\s+/g, " ").trim();
10538
10620
  }
10621
+ function consumePair(pair, metadata, entries) {
10622
+ let value = parseMetadataValue(pair.rawValue);
10623
+ metadata[pair.key] = value;
10624
+ entries.push({
10625
+ key: pair.key,
10626
+ value,
10627
+ rawValue: pair.rawValue,
10628
+ from: pair.from,
10629
+ to: pair.to,
10630
+ valueFrom: pair.valueFrom,
10631
+ valueTo: pair.valueTo,
10632
+ hasValue: pair.rawValue != null
10633
+ });
10634
+ }
10539
10635
  function parseMetadataValue(rawValue) {
10540
10636
  if (!rawValue) return "true";
10541
10637
  if (!rawValue.startsWith('"')) return rawValue;
@@ -10546,21 +10642,24 @@ function parseHashCommentDescription(cleaned) {
10546
10642
  let description = cleaned.slice(2).trim();
10547
10643
  return description || void 0;
10548
10644
  }
10549
- function matchMetadataToken(text, start, hasHashPrefix) {
10645
+ function matchMetadataToken(text, start, hasHashPrefix, textFrom, firstHashFrom) {
10550
10646
  let cursor = hasHashPrefix ? start + 1 : start;
10551
10647
  let keyStart = cursor;
10552
10648
  while (/[A-Za-z0-9_-]/.test(text[cursor] || "")) cursor++;
10553
10649
  if (cursor === keyStart) return void 0;
10554
10650
  let key = text.slice(keyStart, cursor);
10651
+ let from2 = hasHashPrefix ? textFrom + start : firstHashFrom ?? textFrom + keyStart;
10652
+ let keyFrom = textFrom + keyStart;
10653
+ let keyTo = textFrom + cursor;
10555
10654
  let afterKey = skipWhitespace2(text, cursor);
10556
10655
  if (text[afterKey] === "=") {
10557
10656
  let valueStart = skipWhitespace2(text, afterKey + 1);
10558
10657
  let value = readMetadataValue(text, valueStart);
10559
10658
  if (!value) return void 0;
10560
- return { key, rawValue: value.rawValue, end: value.end };
10659
+ return { key, rawValue: value.rawValue, keyFrom, keyTo, from: from2, to: keyTo, valueFrom: textFrom + valueStart, valueTo: textFrom + value.end, end: value.end };
10561
10660
  }
10562
10661
  if (afterKey >= text.length || text[afterKey] === "#" || text.startsWith("--", afterKey)) {
10563
- return { key, rawValue: void 0, end: afterKey };
10662
+ return { key, rawValue: void 0, keyFrom, keyTo, from: from2, to: keyTo, end: afterKey };
10564
10663
  }
10565
10664
  }
10566
10665
  function readMetadataValue(text, start) {
@@ -10786,6 +10885,14 @@ var AnalysisSession = class {
10786
10885
  let suffix = scopeKey ? `:${scopeKey}` : "";
10787
10886
  return `${kind}:${location.file}:${location.from.offset}:${location.to.offset}${suffix}`;
10788
10887
  }
10888
+ extractMetadata(node) {
10889
+ let details = extractLeadingMetadataDetails(node);
10890
+ let file = getFile(node);
10891
+ for (let diagnostic of validateMetadataEntries(details.entries)) {
10892
+ this.diagRange(file, diagnostic.from, diagnostic.to, diagnostic.message);
10893
+ }
10894
+ return details.metadata;
10895
+ }
10789
10896
  renderTableHover(table2) {
10790
10897
  let desc2 = table2.metadata?.description ? `
10791
10898
 
@@ -10826,7 +10933,7 @@ ${field.metadata.description}` : "";
10826
10933
  let hasNamespace = name.includes(".");
10827
10934
  let tablePath = !hasNamespace && this.config.defaultNamespace ? `${this.config.defaultNamespace}.${name}` : name;
10828
10935
  let type = syntaxNode.getChild("QueryExpression") ? "view" : "table";
10829
- let table2 = { name, type, tablePath, filePath: fi.path, columns: [], joins: [], metadata: extractLeadingMetadata(syntaxNode), syntaxNode };
10936
+ let table2 = { name, type, tablePath, filePath: fi.path, columns: [], joins: [], metadata: this.extractMetadata(syntaxNode), syntaxNode };
10830
10937
  Object.assign(table2, this.addSymbol("table", refNode, name, { hover: this.renderTableHover(table2) }));
10831
10938
  syntaxNode.getChildren("ColumnDef").forEach((node) => this.addColumn(table2, node));
10832
10939
  syntaxNode.getChildren("JoinDef").forEach((node) => this.addJoin(table2, node));
@@ -10850,7 +10957,7 @@ ${field.metadata.description}` : "";
10850
10957
  if (parsed.error) return this.diag(node, parsed.error);
10851
10958
  if (!parsed.type) return this.diag(node, `Unsupported data type: ${txt(node.getChild("DataType"))}`);
10852
10959
  let type = parsed.type;
10853
- let col = { name, type, metadata: extractLeadingMetadata(node) };
10960
+ let col = { name, type, metadata: this.extractMetadata(node) };
10854
10961
  Object.assign(col, this.addSymbol("column", nameNode, name, { tableId: table2.symbolId, hover: this.renderFieldHover(table2, col) }));
10855
10962
  if (this.getField(name, table2)) return this.diag(node, `Table already has a field called "${name}"`);
10856
10963
  table2.columns.push(col);
@@ -10871,7 +10978,7 @@ ${field.metadata.description}` : "";
10871
10978
  addComputedColumn(table2, node) {
10872
10979
  let nameNode = node.getChild("Alias");
10873
10980
  let name = txt(nameNode);
10874
- let col = { name, type: scalarType("string"), exprNode: node.getChild("Expression"), metadata: extractLeadingMetadata(node) };
10981
+ let col = { name, type: scalarType("string"), exprNode: node.getChild("Expression"), metadata: this.extractMetadata(node) };
10875
10982
  Object.assign(col, this.addSymbol("column", nameNode, name, { tableId: table2.symbolId, hover: this.renderFieldHover(table2, col) }));
10876
10983
  if (this.getField(name, table2)) return this.diag(node, `Table already has a field called "${name}"`);
10877
10984
  table2.columns.push(col);
@@ -11524,7 +11631,7 @@ ${field.metadata.description}` : "";
11524
11631
  return {
11525
11632
  sql: `EXTRACT(${unit} FROM ${expr.sql})`,
11526
11633
  type: scalarType("number"),
11527
- metadata: inferTemporalExtractionMetadata(unit, this.config.dialect),
11634
+ metadata: inferTimeOrdinal(unit, this.config.dialect),
11528
11635
  isAgg: expr.isAgg,
11529
11636
  fanout: expr.fanout
11530
11637
  };
@@ -11620,11 +11727,11 @@ ${field.metadata.description}` : "";
11620
11727
  sameFieldMetadata(left2, right2) {
11621
11728
  if (!left2 && !right2) return true;
11622
11729
  if (!left2 || !right2) return false;
11623
- return left2.timeGrain == right2.timeGrain && left2.timePart == right2.timePart && left2.timeOrdinal == right2.timeOrdinal;
11730
+ return left2.timeGrain == right2.timeGrain && left2.timeOrdinal == right2.timeOrdinal;
11624
11731
  }
11625
11732
  withoutTimeGrain(metadata) {
11626
- if (!metadata?.timeGrain && !metadata?.timePart && !metadata?.timeOrdinal) return metadata;
11627
- let { timeGrain: _timeGrain, timePart: _timePart, timeOrdinal: _timeOrdinal, defaultName: _defaultName, ...next } = metadata;
11733
+ if (!metadata?.timeGrain && !metadata?.timeOrdinal) return metadata;
11734
+ let { timeGrain: _timeGrain, timeOrdinal: _timeOrdinal, defaultName: _defaultName, ...next } = metadata;
11628
11735
  return Object.keys(next).length ? next : void 0;
11629
11736
  }
11630
11737
  isPercentileFunctionCall(node) {
@@ -11932,11 +12039,14 @@ ${field.metadata.description}` : "";
11932
12039
  }
11933
12040
  diag(node, message, defaultReturn) {
11934
12041
  let file = getFile(node);
11935
- let from2 = getPosition(node.from, file);
11936
- let to = getPosition(node.to, file);
11937
- this.diagnostics.push({ severity: "error", message, file: toRelativePath(file.path), from: from2, to, frame: buildFrame(from2, to) });
12042
+ this.diagRange(file, node.from, node.to, message);
11938
12043
  return defaultReturn;
11939
12044
  }
12045
+ diagRange(file, fromOffset, toOffset, message) {
12046
+ let from2 = getPosition(fromOffset, file);
12047
+ let to = getPosition(toOffset, file);
12048
+ this.diagnostics.push({ severity: "error", message, file: toRelativePath(file.path), from: from2, to, frame: buildFrame(from2, to) });
12049
+ }
11940
12050
  checkTypes(expr, expected, node) {
11941
12051
  if (isScalarType(expr.type, "error") || isScalarType(expr.type, "null")) return;
11942
12052
  if (expected.some((kind) => kind == "array" ? isArrayType(expr.type) : isScalarType(expr.type, kind))) return;
@@ -11990,7 +12100,7 @@ function replaceParams(sql, params) {
11990
12100
 
11991
12101
  // ../lang/core.ts
11992
12102
  async function loadWorkspace(dir, includeMd, ignoredFiles = []) {
11993
- let ignore = ["node_modules/**", "**/.*/**", ...ignoredFiles];
12103
+ let ignore = ["node_modules/**", "**/.*/**", "**/agents.md", "**/claude.md", ...ignoredFiles];
11994
12104
  let paths = await glob(includeMd ? "**/*.{gsql,md}" : "**/*.gsql", { cwd: dir, ignore, follow: false, nocase: true });
11995
12105
  let files = [];
11996
12106
  for await (let file of paths) {
@@ -12409,7 +12519,7 @@ function normalizeState(state, fallback) {
12409
12519
  // telemetry/index.ts
12410
12520
  var DEFAULT_TELEMETRY_ENDPOINT = "https://app.graphenedata.com/cli-telemetry";
12411
12521
  var SAFE_FLAG_NAMES = {
12412
- run: { chart: ["--chart", "-c"], query: ["--query", "-q"] },
12522
+ run: { chart: ["--chart", "-c"], input: ["--input"], query: ["--query", "-q"] },
12413
12523
  serve: { bg: ["--bg"] }
12414
12524
  };
12415
12525
  var CliTelemetry = class {
@@ -12527,7 +12637,7 @@ async function pathExists(filePath) {
12527
12637
  import { readFileSync } from "fs";
12528
12638
  async function getConnection() {
12529
12639
  if (config.dialect === "bigquery") {
12530
- let mod = await importConnection(() => import("./bigQuery-I3F46SC6.js"), "@google-cloud/bigquery", "BigQuery");
12640
+ let mod = await importConnection(() => import("./bigQuery-YIWXZPY6.js"), "@google-cloud/bigquery", "BigQuery");
12531
12641
  let options = {};
12532
12642
  if (process.env.GOOGLE_CREDENTIALS_CONTENT) {
12533
12643
  let parsed = JSON.parse(process.env.GOOGLE_CREDENTIALS_CONTENT);
@@ -12538,10 +12648,10 @@ async function getConnection() {
12538
12648
  }
12539
12649
  return new mod.BigQueryConnection(options);
12540
12650
  } else if (config.dialect === "duckdb") {
12541
- let mod = await importConnection(() => import("./duckdb-IYBIO5KJ.js"), "@duckdb/node-api", "DuckDB");
12651
+ let mod = await importConnection(() => import("./duckdb-V6PJEA7H.js"), "@duckdb/node-api", "DuckDB");
12542
12652
  return new mod.DuckDBConnection({});
12543
12653
  } else if (config.dialect === "clickhouse") {
12544
- let mod = await importConnection(() => import("./clickhouse-ZN5AN2UL.js"), "@clickhouse/client", "ClickHouse");
12654
+ let mod = await importConnection(() => import("./clickhouse-S3BJSKND.js"), "@clickhouse/client", "ClickHouse");
12545
12655
  let url = config.clickhouse?.url || process.env.CLICKHOUSE_URL;
12546
12656
  let username = config.clickhouse?.username || process.env.CLICKHOUSE_USERNAME;
12547
12657
  let password = process.env.CLICKHOUSE_PASSWORD;
@@ -12550,10 +12660,11 @@ async function getConnection() {
12550
12660
  url,
12551
12661
  username,
12552
12662
  password,
12553
- database: config.clickhouse?.database || config.defaultNamespace || "default"
12663
+ database: config.clickhouse?.database || config.defaultNamespace || "default",
12664
+ requestTimeout: config.clickhouse?.requestTimeout
12554
12665
  });
12555
12666
  } else if (config.dialect === "snowflake") {
12556
- let mod = await importConnection(() => import("./snowflake-MOQB5GA4.js"), "snowflake-sdk", "Snowflake");
12667
+ let mod = await importConnection(() => import("./snowflake-HVSTYBLB.js"), "snowflake-sdk", "Snowflake");
12557
12668
  return new mod.SnowflakeConnection({
12558
12669
  privateKeyPath: process.env.SNOWFLAKE_PRI_KEY_PATH,
12559
12670
  privateKey: process.env.SNOWFLAKE_PRI_KEY,
@@ -12599,7 +12710,6 @@ async function runQuery(sql, params) {
12599
12710
  import fs5 from "fs-extra";
12600
12711
  import { readFileSync as readFileSync2 } from "node:fs";
12601
12712
  import { styleText as styleText2 } from "node:util";
12602
- import os2 from "os";
12603
12713
  import path7 from "path";
12604
12714
  import { WebSocketServer } from "ws";
12605
12715
 
@@ -12638,7 +12748,7 @@ async function runMdFile(options) {
12638
12748
  printDiagnostics(result.diagnostics, log);
12639
12749
  return false;
12640
12750
  }
12641
- let resp = await sendSocketRequest({ mdFile, action: "check", chart: options.chart, log });
12751
+ let resp = await sendSocketRequest({ mdFile, action: "check", chart: options.chart, inputs: options.inputs, log });
12642
12752
  if (!resp) return false;
12643
12753
  let errors = Array.from(resp.errors || []);
12644
12754
  let chartNotFound = !!options.chart && !resp.screenshot;
@@ -12657,9 +12767,11 @@ async function runMdFile(options) {
12657
12767
  log("Warning: Queries were still loading when the screenshot was taken");
12658
12768
  }
12659
12769
  if (resp?.screenshot) {
12660
- let filename = `graphene-screenshot-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.png`;
12661
- let screenshotPath = path7.join(os2.tmpdir(), filename);
12770
+ let filename = `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.png`;
12771
+ let screenshotDir = path7.join(getGrapheneCache(config.root), "screenshots");
12772
+ let screenshotPath = path7.join(screenshotDir, filename);
12662
12773
  let base64Data = resp.screenshot.replace(/^data:image\/png;base64,/, "");
12774
+ await fs5.ensureDir(screenshotDir);
12663
12775
  await fs5.writeFile(screenshotPath, base64Data, "base64");
12664
12776
  log("Screenshot saved to", screenshotPath);
12665
12777
  }
@@ -12686,9 +12798,9 @@ async function listMdFileQueries(mdArg, telemetry, log = console.log) {
12686
12798
  else componentIds.forEach((componentId) => log(componentId));
12687
12799
  return true;
12688
12800
  }
12689
- async function runNamedQueryFromMd(mdAbsolutePath, queryName, telemetry) {
12801
+ async function runNamedQueryFromMd(mdAbsolutePath, queryName, options = {}) {
12690
12802
  let files = await loadWorkspace(process.cwd(), false, config.ignoredFiles);
12691
- telemetry?.event("workspace_scanned", { command: "run", ...getWorkspaceScanCounts(files) });
12803
+ options.telemetry?.event("workspace_scanned", { command: "run", ...getWorkspaceScanCounts(files) });
12692
12804
  let mdRelativePath = path7.relative(process.cwd(), mdAbsolutePath);
12693
12805
  let mdContents = await fs5.promises.readFile(mdAbsolutePath, "utf-8");
12694
12806
  let result = analyzeWorkspace({ config, files: files.filter((file) => file.path != mdRelativePath).concat({ path: mdRelativePath, contents: mdContents, kind: "md" }) }, mdRelativePath);
@@ -12705,14 +12817,21 @@ async function runNamedQueryFromMd(mdAbsolutePath, queryName, telemetry) {
12705
12817
  }
12706
12818
  let input = getFile2(queryResult, "input.md");
12707
12819
  if (!input?.queries.length) return false;
12708
- let sql = toSql(input.queries[input.queries.length - 1]);
12820
+ let sql;
12821
+ try {
12822
+ sql = toSql(input.queries[input.queries.length - 1], options.inputs || {});
12823
+ } catch (err) {
12824
+ console.error(err instanceof Error ? err.message : String(err));
12825
+ return false;
12826
+ }
12709
12827
  let res = await runQuery(sql);
12710
12828
  printTable(res.rows);
12711
12829
  return true;
12712
12830
  }
12713
- async function sendSocketRequest({ mdFile, action, chart, log }) {
12831
+ async function sendSocketRequest({ mdFile, action, chart, inputs, log }) {
12714
12832
  let pageUrl = "/" + mdFile.replace(/\.md$/, "").replace(/^\//, "").replace(/\\/g, "/");
12715
12833
  if (pageUrl === "/index") pageUrl = "/";
12834
+ pageUrl = appendInputsToUrl(pageUrl, inputs);
12716
12835
  if (process.env.NODE_ENV !== "test" && !await isServerRunning()) {
12717
12836
  log("Starting Graphene server...");
12718
12837
  await runServeInBackground();
@@ -12739,6 +12858,16 @@ async function sendSocketRequest({ mdFile, action, chart, log }) {
12739
12858
  }
12740
12859
  return resp;
12741
12860
  }
12861
+ function appendInputsToUrl(pageUrl, inputs = {}) {
12862
+ let search = new URLSearchParams();
12863
+ Object.entries(inputs).forEach(([name, value]) => {
12864
+ if (Array.isArray(value)) value.forEach((item) => search.append(name, item));
12865
+ else search.append(name, value);
12866
+ });
12867
+ let rendered = search.toString();
12868
+ if (!rendered) return pageUrl;
12869
+ return `${pageUrl}?${rendered}`;
12870
+ }
12742
12871
  async function fetchSocketRequest({ host, pageUrl, action, chart }) {
12743
12872
  let abort = new AbortController();
12744
12873
  let timeout = setTimeout(() => abort.abort(), 3e4);
@@ -12777,7 +12906,7 @@ async function proxyRunRequest(req, res) {
12777
12906
  res.end(JSON.stringify({ error: "no_tab" }));
12778
12907
  return;
12779
12908
  }
12780
- conn.socket.send(JSON.stringify({ type: "check", action, chart, requestId: id }));
12909
+ conn.socket.send(JSON.stringify({ action, chart, requestId: id }));
12781
12910
  pendingRequests[id] = { response: res };
12782
12911
  }
12783
12912
  function toWorkspaceFiles(analysis) {
@@ -12846,4 +12975,4 @@ export {
12846
12975
  runNamedQueryFromMd,
12847
12976
  runVitePlugin
12848
12977
  };
12849
- //# sourceMappingURL=chunk-OVWODUTJ.js.map
12978
+ //# sourceMappingURL=chunk-UTV3ERGI.js.map