zinkee 0.1.19 → 0.1.20

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.
@@ -0,0 +1,47 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm test *)",
5
+ "Bash(npm run *)",
6
+ "Bash(pnpm typecheck *)",
7
+ "Bash(pnpm test *)",
8
+ "Bash(npx tsc *)",
9
+ "Read(//home/guillermo/dev/z2-backend/api/src/main/java/com/zinkee/api/domain/model/v2/log/**)",
10
+ "Read(//home/guillermo/dev/z2-backend/**)",
11
+ "Bash(grep *)",
12
+ "Bash(npx vitest *)",
13
+ "Bash(npx tsx *)",
14
+ "Bash(node dist/index.js --help)",
15
+ "Bash(gh repo *)",
16
+ "WebFetch(domain:github.com)",
17
+ "Bash(git config *)",
18
+ "Read(//home/guillermo/.config/**)",
19
+ "Read(//home/guillermo/**)",
20
+ "Bash(curl *)",
21
+ "Bash(node dist/index.js --show-completion zsh)",
22
+ "Bash(node *)",
23
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee\" COMP_CWORD=1 node *)",
24
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas\" COMP_CWORD=2 node *)",
25
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas fields\" COMP_CWORD=3 node dist/index.js)",
26
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas fields cr\" COMP_CWORD=3 node dist/index.js)",
27
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas list --j\" COMP_CWORD=3 node dist/index.js)",
28
+ "Bash(rm -rf /tmp/zinkee-install)",
29
+ "Bash(mkdir -p /tmp/zinkee-install)",
30
+ "Bash(HOME=/tmp/zinkee-install SHELL=/bin/zsh node dist/index.js --install-completion)",
31
+ "Read(//tmp/**)",
32
+ "Read(//tmp/zinkee-install/**)",
33
+ "Bash(rm -rf /tmp/zinkee-install-bash)",
34
+ "Bash(mkdir -p /tmp/zinkee-install-bash)",
35
+ "Bash(HOME=/tmp/zinkee-install-bash SHELL=/bin/bash node dist/index.js --install-completion)",
36
+ "Bash(rm -rf /tmp/zinkee-install-fish)",
37
+ "Bash(mkdir -p /tmp/zinkee-install-fish)",
38
+ "Bash(_ZINKEE_COMPLETE=zsh_complete node dist/index.js)",
39
+ "Bash(echo \"exit: $?\")",
40
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee schemas\" COMP_CWORD=abc node dist/index.js)",
41
+ "Bash(_ZINKEE_COMPLETE=zsh_complete COMP_WORDS=\"zinkee config show --foo --bar baz quux ?\" COMP_CWORD=10 node dist/index.js)",
42
+ "Bash(git -C /home/guillermo/dev/cli status)",
43
+ "Bash(git -C /home/guillermo/dev/cli branch --show-current)",
44
+ "Bash(git -C /home/guillermo/dev/cli diff --stat)"
45
+ ]
46
+ }
47
+ }
package/README.md CHANGED
@@ -480,17 +480,25 @@ zinkee displays layout update <display-uuid> --template freeform --freeform-layo
480
480
  }'
481
481
  ```
482
482
 
483
- ### KPI with filters
483
+ ### Widget filters
484
484
 
485
- The `--filter` flag doesn't work on KPI widgets. Pass filters in `--raw`:
485
+ Pass `--filter "<field>:<comparator>:<value>"` (repeatable) and the CLI turns it into the structured `query.filters[]` payload the API expects. Field accepts UUID or slug. Supported comparators: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `contains`, `in` (comma-separated values), `is_empty`, `is_not_empty`.
486
486
 
487
487
  ```bash
488
- --raw '{"query":{"filters":[{"fieldId":"<field-uuid>","operator":"EQUALS","value":"2"}]}}'
488
+ zinkee --json displays widgets update <display-uuid> <widget-uuid> \
489
+ --filter "status:eq:2" \
490
+ --filter "amount:gte:500"
491
+ ```
492
+
493
+ For comparators the parser does not cover yet (e.g. `NOT_CONTAINS`, `RANGE`) keep using `--raw`:
494
+
495
+ ```bash
496
+ --raw '{"query":{"filters":[{"origin":{"fieldId":"<field>"},"comparisonOperator":"RANGE","values":["2025-01-01","2025-12-31"]}]}}'
489
497
  ```
490
498
 
491
499
  ### Slug support
492
500
 
493
- Slugs are resolved to UUIDs in: `--field`, `--source-schema`, `--source-field`, `--x-axis-field`, `kpi.fieldCalc`, `chart.xAxisFieldId`, `chart.yAxisSeries[].fieldCalc`, `bindings.variableMap` values.
501
+ Slugs are resolved to UUIDs in: `--field`, `--source-schema`, `--source-field`, `--x-axis-field`, `--filter` field reference, `kpi.fieldCalc`, `chart.xAxisFieldId`, `chart.yAxisSeries[].fieldCalc`, `bindings.variableMap` values.
494
502
 
495
503
  Display UUIDs are required for `displays widgets create/update` and `displays variables create`.
496
504
 
package/dist/index.js CHANGED
@@ -3513,29 +3513,38 @@ var specificExamples = {
3513
3513
  }`
3514
3514
  },
3515
3515
  {
3516
- description: "Add query filters that match the full comparisonOperator contract (requires --raw because --filter only accepts free-form expressions).",
3517
- command: `zinkee --json displays widgets update 0f6f062f-1478-4df2-96a1-c495d037d260 11111111-1111-4111-a111-111111111111 --raw '{"query":{"filters":[{"origin":{"schemaId":"contacts","fieldId":"status"},"comparisonOperator":"EQUAL","values":["2"]},{"origin":{"schemaId":"contacts","fieldId":"amount"},"comparisonOperator":"GREATER_OR_EQUAL","values":["500"]}]}}'`,
3516
+ description: "Add query filters with --filter. The CLI parses the expression and emits the structured comparisonOperator payload the API expects.",
3517
+ command: `zinkee --json displays widgets update 0f6f062f-1478-4df2-96a1-c495d037d260 11111111-1111-4111-a111-111111111111 --filter "status:eq:2" --filter "amount:gte:500"`,
3518
3518
  raw: `{
3519
3519
  "query": {
3520
3520
  "filters": [
3521
3521
  {
3522
- "origin": {
3523
- "schemaId": "contacts",
3524
- "fieldId": "status"
3525
- },
3522
+ "origin": { "fieldId": "status" },
3526
3523
  "comparisonOperator": "EQUAL",
3527
3524
  "values": ["2"]
3528
3525
  },
3529
3526
  {
3530
- "origin": {
3531
- "schemaId": "contacts",
3532
- "fieldId": "amount"
3533
- },
3527
+ "origin": { "fieldId": "amount" },
3534
3528
  "comparisonOperator": "GREATER_OR_EQUAL",
3535
3529
  "values": ["500"]
3536
3530
  }
3537
3531
  ]
3538
3532
  }
3533
+ }`
3534
+ },
3535
+ {
3536
+ description: "Fall back to --raw for comparators the parser does not cover yet (e.g. NOT_CONTAINS, RANGE).",
3537
+ command: `zinkee --json displays widgets update 0f6f062f-1478-4df2-96a1-c495d037d260 11111111-1111-4111-a111-111111111111 --raw '{"query":{"filters":[{"origin":{"fieldId":"due-date"},"comparisonOperator":"RANGE","values":["2025-01-01","2025-12-31"]}]}}'`,
3538
+ raw: `{
3539
+ "query": {
3540
+ "filters": [
3541
+ {
3542
+ "origin": { "fieldId": "due-date" },
3543
+ "comparisonOperator": "RANGE",
3544
+ "values": ["2025-01-01", "2025-12-31"]
3545
+ }
3546
+ ]
3547
+ }
3539
3548
  }`
3540
3549
  },
3541
3550
  {
@@ -7886,6 +7895,86 @@ var DisplaysApi = class {
7886
7895
  }
7887
7896
  };
7888
7897
 
7898
+ // src/parsers/expressions.ts
7899
+ var supportedComparators = /* @__PURE__ */ new Set([
7900
+ "eq",
7901
+ "neq",
7902
+ "gt",
7903
+ "gte",
7904
+ "lt",
7905
+ "lte",
7906
+ "contains",
7907
+ "in",
7908
+ "is_empty",
7909
+ "is_not_empty"
7910
+ ]);
7911
+ var noValueComparators = /* @__PURE__ */ new Set(["is_empty", "is_not_empty"]);
7912
+ function parseColonExpression(input) {
7913
+ const parts = input.split(":");
7914
+ if (parts.length < 2) {
7915
+ throw new Error(`Expected a field:comparator[:value] expression, got "${input}".`);
7916
+ }
7917
+ const field = parts[0]?.trim();
7918
+ const comparator = parts[1]?.trim();
7919
+ if (!field) {
7920
+ throw new Error(`Expected a field before ":", got "${input}".`);
7921
+ }
7922
+ if (!comparator) {
7923
+ throw new Error(`Expected a comparator after "${field}:", got "${input}".`);
7924
+ }
7925
+ return [field, comparator, parts.slice(2).join(":").trim()];
7926
+ }
7927
+ function parseSpaceExpression(input) {
7928
+ const parts = input.trim().split(/\s+/);
7929
+ if (parts.length < 2) {
7930
+ throw new Error(`Expected a field comparator expression, got "${input}".`);
7931
+ }
7932
+ const field = parts[0];
7933
+ const comparator = parts[1];
7934
+ if (!field) {
7935
+ throw new Error(`Expected a field comparator expression, got "${input}".`);
7936
+ }
7937
+ if (!comparator) {
7938
+ throw new Error(`Expected a comparator after "${field}", got "${input}".`);
7939
+ }
7940
+ return [field.trim(), comparator.trim(), parts.slice(2).join(" ").trim()];
7941
+ }
7942
+ function normalizeValue(comparator, rawValue) {
7943
+ if (noValueComparators.has(comparator)) {
7944
+ if (rawValue.length > 0) {
7945
+ throw new Error(`Comparator "${comparator}" does not accept a value.`);
7946
+ }
7947
+ return null;
7948
+ }
7949
+ if (comparator === "in") {
7950
+ const values = rawValue.split(",").map((value) => value.trim()).filter(Boolean);
7951
+ if (values.length === 0) {
7952
+ throw new Error(`Comparator "${comparator}" requires at least one value.`);
7953
+ }
7954
+ return values;
7955
+ }
7956
+ if (rawValue.length === 0) {
7957
+ throw new Error(`Comparator "${comparator}" requires a value.`);
7958
+ }
7959
+ return rawValue;
7960
+ }
7961
+ function parseExpression(input) {
7962
+ const trimmed = input.trim();
7963
+ const [field, comparatorCandidate, rawValue] = trimmed.includes(":") && !trimmed.includes(" ") ? parseColonExpression(trimmed) : parseSpaceExpression(trimmed);
7964
+ if (!supportedComparators.has(comparatorCandidate)) {
7965
+ throw new Error(
7966
+ `Unsupported comparator "${comparatorCandidate}" in expression "${input}".`
7967
+ );
7968
+ }
7969
+ const comparator = comparatorCandidate;
7970
+ return {
7971
+ field,
7972
+ comparator,
7973
+ value: normalizeValue(comparator, rawValue),
7974
+ raw: trimmed
7975
+ };
7976
+ }
7977
+
7889
7978
  // src/commands/displays.ts
7890
7979
  function getCommandIo4(stdout) {
7891
7980
  return stdout ?? process.stdout;
@@ -7950,6 +8039,37 @@ function parseUuidOrSlugSelector3(input) {
7950
8039
  throw new InvalidArgumentError3(message);
7951
8040
  }
7952
8041
  }
8042
+ var COMPARATOR_TO_DISPLAY_OPERATOR = {
8043
+ eq: "EQUAL",
8044
+ neq: "NOT_EQUAL",
8045
+ gt: "GREATER",
8046
+ gte: "GREATER_OR_EQUAL",
8047
+ lt: "LESS",
8048
+ lte: "LESS_OR_EQUAL",
8049
+ contains: "CONTAINS",
8050
+ in: "ANY_OF",
8051
+ is_empty: "IS_EMPTY",
8052
+ is_not_empty: "IS_NOT_EMPTY"
8053
+ };
8054
+ function toDisplayFilter(parsed) {
8055
+ const values = parsed.value === null ? [] : Array.isArray(parsed.value) ? [...parsed.value] : [parsed.value];
8056
+ return {
8057
+ origin: { fieldId: parsed.field },
8058
+ comparisonOperator: COMPARATOR_TO_DISPLAY_OPERATOR[parsed.comparator],
8059
+ values
8060
+ };
8061
+ }
8062
+ function parseFilterExpression(input) {
8063
+ try {
8064
+ return parseExpression(input);
8065
+ } catch (error) {
8066
+ const message = error instanceof Error ? error.message : "Invalid filter expression.";
8067
+ throw new InvalidArgumentError3(message);
8068
+ }
8069
+ }
8070
+ function collectFilters(value, previous = []) {
8071
+ return [...previous, parseFilterExpression(value)];
8072
+ }
7953
8073
  function readRawObject2(raw, rawFile) {
7954
8074
  if (raw && rawFile) {
7955
8075
  throw new CliError("invalid_cli_usage", 'Use either "--raw" or "--raw-file", not both.');
@@ -8016,7 +8136,7 @@ function buildVariableBody(options) {
8016
8136
  };
8017
8137
  }
8018
8138
  if (options.filter && options.filter.length > 0) {
8019
- body.filters = options.filter.map((entry) => ({ raw: entry }));
8139
+ body.filters = options.filter.map(toDisplayFilter);
8020
8140
  }
8021
8141
  if (options.dateMode || options.dateDynamicOption || options.dateSpecific || options.dateRangeStart || options.dateRangeEnd) {
8022
8142
  body.date = {
@@ -8065,15 +8185,19 @@ function buildWidgetBody(options) {
8065
8185
  layout
8066
8186
  };
8067
8187
  }
8068
- if (options.field?.length || options.sort?.length || options.filter?.length) {
8188
+ if (options.field && options.field.length > 0) {
8069
8189
  body.view = {
8070
8190
  ...typeof body.view === "object" && body.view ? body.view : {},
8071
8191
  fields: options.field
8072
8192
  };
8193
+ }
8194
+ const queryMerge = {};
8195
+ if (options.sort && options.sort.length > 0) queryMerge.sorts = options.sort;
8196
+ if (options.filter && options.filter.length > 0) queryMerge.filters = options.filter.map(toDisplayFilter);
8197
+ if (Object.keys(queryMerge).length > 0) {
8073
8198
  body.query = {
8074
8199
  ...typeof body.query === "object" && body.query ? body.query : {},
8075
- sorts: options.sort,
8076
- filters: options.filter?.map((entry) => ({ raw: entry }))
8200
+ ...queryMerge
8077
8201
  };
8078
8202
  }
8079
8203
  if (options.widgetReadOnly !== void 0 || options.hideAddButton !== void 0 || options.hideDeleteButton !== void 0 || options.hideSortButton !== void 0 || options.hideFilterButton !== void 0 || options.hideSeeButton !== void 0) {
@@ -8288,7 +8412,7 @@ function registerDisplaysCommands(program, options = {}) {
8288
8412
  }
8289
8413
  printTable([match], void 0, stdout);
8290
8414
  });
8291
- variables.command("create").description("Create variable").argument("<display>", "display uuid or slug", parseUuidOrSlugSelector3).option("--type <type>").option("--name <name>").option("--allow-multiple").option("--static").option("--default <value>").option("--default-value <value>", "repeatable default value", (v, p = []) => [...p, v], []).option("--source-schema <id>").option("--source-field <id>").option("--filter <expr>", "repeatable filter", (v, p = []) => [...p, v], []).option("--date-mode <mode>").option("--date-dynamic-option <option>").option("--date-specific <iso>").option("--date-range-start <iso>").option("--date-range-end <iso>").option("--raw <json>").option("--raw-file <path>").action(async function action(display, commandOptions) {
8415
+ variables.command("create").description("Create variable").argument("<display>", "display uuid or slug", parseUuidOrSlugSelector3).option("--type <type>").option("--name <name>").option("--allow-multiple").option("--static").option("--default <value>").option("--default-value <value>", "repeatable default value", (v, p = []) => [...p, v], []).option("--source-schema <id>").option("--source-field <id>").option("--filter <expr>", "repeatable filter", collectFilters, []).option("--date-mode <mode>").option("--date-dynamic-option <option>").option("--date-specific <iso>").option("--date-range-start <iso>").option("--date-range-end <iso>").option("--raw <json>").option("--raw-file <path>").action(async function action(display, commandOptions) {
8292
8416
  const { api, json, readOnly } = createDisplaysApi(this, filePath);
8293
8417
  ensureWritable3("displays variables create", readOnly, "write");
8294
8418
  const data = await api.createVariable(display, buildVariableBody(commandOptions));
@@ -8298,7 +8422,7 @@ function registerDisplaysCommands(program, options = {}) {
8298
8422
  }
8299
8423
  writeLine4(stdout, `Created variable on display "${display.value}".`);
8300
8424
  });
8301
- variables.command("update").description("Update variable").argument("<display>", "display uuid or slug", parseUuidOrSlugSelector3).argument("<variable>", "variable id").option("--type <type>").option("--name <name>").option("--allow-multiple").option("--static").option("--default <value>").option("--default-value <value>", "repeatable default value", (v, p = []) => [...p, v], []).option("--source-schema <id>").option("--source-field <id>").option("--filter <expr>", "repeatable filter", (v, p = []) => [...p, v], []).option("--date-mode <mode>").option("--date-dynamic-option <option>").option("--date-specific <iso>").option("--date-range-start <iso>").option("--date-range-end <iso>").option("--raw <json>").option("--raw-file <path>").action(async function action(display, variableId, commandOptions) {
8425
+ variables.command("update").description("Update variable").argument("<display>", "display uuid or slug", parseUuidOrSlugSelector3).argument("<variable>", "variable id").option("--type <type>").option("--name <name>").option("--allow-multiple").option("--static").option("--default <value>").option("--default-value <value>", "repeatable default value", (v, p = []) => [...p, v], []).option("--source-schema <id>").option("--source-field <id>").option("--filter <expr>", "repeatable filter", collectFilters, []).option("--date-mode <mode>").option("--date-dynamic-option <option>").option("--date-specific <iso>").option("--date-range-start <iso>").option("--date-range-end <iso>").option("--raw <json>").option("--raw-file <path>").action(async function action(display, variableId, commandOptions) {
8302
8426
  const { api, json, readOnly } = createDisplaysApi(this, filePath);
8303
8427
  ensureWritable3("displays variables update", readOnly, "write");
8304
8428
  const data = await api.updateVariable(display, variableId, buildVariableBody(commandOptions));
@@ -8338,7 +8462,7 @@ function registerDisplaysCommands(program, options = {}) {
8338
8462
  }
8339
8463
  printTable([data], void 0, stdout);
8340
8464
  });
8341
- widgets.command("create").description("Create widget").argument("<display>", "display uuid or slug", parseUuidOrSlugSelector3).requiredOption("--type <type>", "widget type").option("--name <name>").option("--description <text>").option("--icon <icon>").option("--color <color>").option("--origin-resource <uuid>").option("--origin-subschema").option("--tab <tabId>").option("--slot <slotId>").option("--layout <json>").option("--layout-file <path>").option("--field <field>", "repeatable field", (v, p = []) => [...p, v], []).option("--sort <sort>", "repeatable sort", (v, p = []) => [...p, v], []).option("--filter <expr>", "repeatable filter", (v, p = []) => [...p, v], []).option("--widget-read-only").option("--hide-add-button").option("--hide-delete-button").option("--hide-sort-button").option("--hide-filter-button").option("--hide-see-button").option("--calc <type>").option("--calc-field <uuid>").option("--kpi-config <json>").option("--chart-type <type>").option("--x-axis-field <uuid>").option("--x-axis-date-format <granularity>").option("--x-axis-time-series").option("--y-axis-serie <json>", "repeatable y axis serie", (v, p = []) => [...p, v], []).option("--legend <json>").option("--raw <json>").option("--raw-file <path>").action(async function action(display, commandOptions) {
8465
+ widgets.command("create").description("Create widget").argument("<display>", "display uuid or slug", parseUuidOrSlugSelector3).requiredOption("--type <type>", "widget type").option("--name <name>").option("--description <text>").option("--icon <icon>").option("--color <color>").option("--origin-resource <uuid>").option("--origin-subschema").option("--tab <tabId>").option("--slot <slotId>").option("--layout <json>").option("--layout-file <path>").option("--field <field>", "repeatable field", (v, p = []) => [...p, v], []).option("--sort <sort>", "repeatable sort", (v, p = []) => [...p, v], []).option("--filter <expr>", "repeatable filter", collectFilters, []).option("--widget-read-only").option("--hide-add-button").option("--hide-delete-button").option("--hide-sort-button").option("--hide-filter-button").option("--hide-see-button").option("--calc <type>").option("--calc-field <uuid>").option("--kpi-config <json>").option("--chart-type <type>").option("--x-axis-field <uuid>").option("--x-axis-date-format <granularity>").option("--x-axis-time-series").option("--y-axis-serie <json>", "repeatable y axis serie", (v, p = []) => [...p, v], []).option("--legend <json>").option("--raw <json>").option("--raw-file <path>").action(async function action(display, commandOptions) {
8342
8466
  const { api, json, readOnly } = createDisplaysApi(this, filePath);
8343
8467
  ensureWritable3("displays widgets create", readOnly, "write");
8344
8468
  const data = await api.createWidget(display, buildWidgetBody(commandOptions));
@@ -8348,7 +8472,7 @@ function registerDisplaysCommands(program, options = {}) {
8348
8472
  }
8349
8473
  writeLine4(stdout, `Created widget on display "${display.value}".`);
8350
8474
  });
8351
- widgets.command("update").description("Update widget").argument("<display>", "display uuid or slug", parseUuidOrSlugSelector3).argument("<widget>", "widget id").option("--type <type>").option("--name <name>").option("--description <text>").option("--icon <icon>").option("--color <color>").option("--origin-resource <uuid>").option("--origin-subschema").option("--tab <tabId>").option("--slot <slotId>").option("--layout <json>").option("--layout-file <path>").option("--field <field>", "repeatable field", (v, p = []) => [...p, v], []).option("--sort <sort>", "repeatable sort", (v, p = []) => [...p, v], []).option("--filter <expr>", "repeatable filter", (v, p = []) => [...p, v], []).option("--widget-read-only").option("--hide-add-button").option("--hide-delete-button").option("--hide-sort-button").option("--hide-filter-button").option("--hide-see-button").option("--calc <type>").option("--calc-field <uuid>").option("--kpi-config <json>").option("--chart-type <type>").option("--x-axis-field <uuid>").option("--x-axis-date-format <granularity>").option("--x-axis-time-series").option("--y-axis-serie <json>", "repeatable y axis serie", (v, p = []) => [...p, v], []).option("--legend <json>").option("--raw <json>").option("--raw-file <path>").action(async function action(display, widgetId, commandOptions) {
8475
+ widgets.command("update").description("Update widget").argument("<display>", "display uuid or slug", parseUuidOrSlugSelector3).argument("<widget>", "widget id").option("--type <type>").option("--name <name>").option("--description <text>").option("--icon <icon>").option("--color <color>").option("--origin-resource <uuid>").option("--origin-subschema").option("--tab <tabId>").option("--slot <slotId>").option("--layout <json>").option("--layout-file <path>").option("--field <field>", "repeatable field", (v, p = []) => [...p, v], []).option("--sort <sort>", "repeatable sort", (v, p = []) => [...p, v], []).option("--filter <expr>", "repeatable filter", collectFilters, []).option("--widget-read-only").option("--hide-add-button").option("--hide-delete-button").option("--hide-sort-button").option("--hide-filter-button").option("--hide-see-button").option("--calc <type>").option("--calc-field <uuid>").option("--kpi-config <json>").option("--chart-type <type>").option("--x-axis-field <uuid>").option("--x-axis-date-format <granularity>").option("--x-axis-time-series").option("--y-axis-serie <json>", "repeatable y axis serie", (v, p = []) => [...p, v], []).option("--legend <json>").option("--raw <json>").option("--raw-file <path>").action(async function action(display, widgetId, commandOptions) {
8352
8476
  const { api, json, readOnly } = createDisplaysApi(this, filePath);
8353
8477
  ensureWritable3("displays widgets update", readOnly, "write");
8354
8478
  const data = await api.updateWidget(display, widgetId, buildWidgetBody(commandOptions));
@@ -9369,86 +9493,6 @@ var SchemasApi = class {
9369
9493
  }
9370
9494
  };
9371
9495
 
9372
- // src/parsers/expressions.ts
9373
- var supportedComparators = /* @__PURE__ */ new Set([
9374
- "eq",
9375
- "neq",
9376
- "gt",
9377
- "gte",
9378
- "lt",
9379
- "lte",
9380
- "contains",
9381
- "in",
9382
- "is_empty",
9383
- "is_not_empty"
9384
- ]);
9385
- var noValueComparators = /* @__PURE__ */ new Set(["is_empty", "is_not_empty"]);
9386
- function parseColonExpression(input) {
9387
- const parts = input.split(":");
9388
- if (parts.length < 2) {
9389
- throw new Error(`Expected a field:comparator[:value] expression, got "${input}".`);
9390
- }
9391
- const field = parts[0]?.trim();
9392
- const comparator = parts[1]?.trim();
9393
- if (!field) {
9394
- throw new Error(`Expected a field before ":", got "${input}".`);
9395
- }
9396
- if (!comparator) {
9397
- throw new Error(`Expected a comparator after "${field}:", got "${input}".`);
9398
- }
9399
- return [field, comparator, parts.slice(2).join(":").trim()];
9400
- }
9401
- function parseSpaceExpression(input) {
9402
- const parts = input.trim().split(/\s+/);
9403
- if (parts.length < 2) {
9404
- throw new Error(`Expected a field comparator expression, got "${input}".`);
9405
- }
9406
- const field = parts[0];
9407
- const comparator = parts[1];
9408
- if (!field) {
9409
- throw new Error(`Expected a field comparator expression, got "${input}".`);
9410
- }
9411
- if (!comparator) {
9412
- throw new Error(`Expected a comparator after "${field}", got "${input}".`);
9413
- }
9414
- return [field.trim(), comparator.trim(), parts.slice(2).join(" ").trim()];
9415
- }
9416
- function normalizeValue(comparator, rawValue) {
9417
- if (noValueComparators.has(comparator)) {
9418
- if (rawValue.length > 0) {
9419
- throw new Error(`Comparator "${comparator}" does not accept a value.`);
9420
- }
9421
- return null;
9422
- }
9423
- if (comparator === "in") {
9424
- const values = rawValue.split(",").map((value) => value.trim()).filter(Boolean);
9425
- if (values.length === 0) {
9426
- throw new Error(`Comparator "${comparator}" requires at least one value.`);
9427
- }
9428
- return values;
9429
- }
9430
- if (rawValue.length === 0) {
9431
- throw new Error(`Comparator "${comparator}" requires a value.`);
9432
- }
9433
- return rawValue;
9434
- }
9435
- function parseExpression(input) {
9436
- const trimmed = input.trim();
9437
- const [field, comparatorCandidate, rawValue] = trimmed.includes(":") && !trimmed.includes(" ") ? parseColonExpression(trimmed) : parseSpaceExpression(trimmed);
9438
- if (!supportedComparators.has(comparatorCandidate)) {
9439
- throw new Error(
9440
- `Unsupported comparator "${comparatorCandidate}" in expression "${input}".`
9441
- );
9442
- }
9443
- const comparator = comparatorCandidate;
9444
- return {
9445
- field,
9446
- comparator,
9447
- value: normalizeValue(comparator, rawValue),
9448
- raw: trimmed
9449
- };
9450
- }
9451
-
9452
9496
  // src/commands/records.ts
9453
9497
  function getCommandIo9(stdout) {
9454
9498
  return stdout ?? process.stdout;