@datarails-ai/dr-appspace-cli 0.12.4 → 0.12.6

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 (2) hide show
  1. package/dist/cli.js +45 -9
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import { fileURLToPath as fileURLToPath6 } from "url";
13
13
  // package.json
14
14
  var package_default = {
15
15
  name: "@datarails-ai/dr-appspace-cli",
16
- version: "0.12.4",
16
+ version: "0.12.6",
17
17
  description: "Datarails App Space CLI \u2014 build, try, push and publish App Space apps",
18
18
  type: "module",
19
19
  engines: {
@@ -57,7 +57,7 @@ var package_default = {
57
57
  };
58
58
 
59
59
  // src/buildInfo.ts
60
- var BUILD_TIME = "2026-10-12T12:52:52.625Z";
60
+ var BUILD_TIME = "2026-10-12T20:27:28.392Z";
61
61
  function formatBuildTime(iso) {
62
62
  if (iso === "") return "";
63
63
  const d = new Date(iso);
@@ -17277,7 +17277,7 @@ var contract_schema_default = {
17277
17277
  module: { type: "string", description: "dr-widgets, dr-insights, dr-fmt, echarts, ui-kit" },
17278
17278
  version: { type: "string", description: "1.1.1 for a vendor module, v3 for the ui-kit" },
17279
17279
  file: { type: "string" },
17280
- path: { type: "string", description: "the platform-root path, e.g. vendor/dr-widgets@1.1.1/widgets.js" },
17280
+ path: { type: "string", description: "the platform-root path, e.g. vendor/dr-widgets@1.2.1/widgets.js" },
17281
17281
  rel: { enum: ["script", "stylesheet"] },
17282
17282
  pages: { type: "array", items: { type: "string" } },
17283
17283
  order: { type: "integer", minimum: 0, description: "load order: where this module is first reached across the bundle" }
@@ -18034,6 +18034,7 @@ var LITERAL_OK = /* @__PURE__ */ new Set([
18034
18034
  ]);
18035
18035
  function validateContract(contract, catalog) {
18036
18036
  const problems = [];
18037
+ const warnings = [];
18037
18038
  const doc = isObject4(contract) ? contract : {};
18038
18039
  const app = obj(doc["app"]);
18039
18040
  const kind = kindOf(doc);
@@ -18051,6 +18052,7 @@ function validateContract(contract, catalog) {
18051
18052
  checkPeriodOverride(doc, problems);
18052
18053
  checkKinds(doc, problems);
18053
18054
  checkDrillTargets(doc, problems);
18055
+ checkAggOrAccountType(doc, warnings);
18054
18056
  checkPairing(doc, problems);
18055
18057
  checkTransforms(doc, problems);
18056
18058
  } else {
@@ -18063,7 +18065,7 @@ function validateContract(contract, catalog) {
18063
18065
  checkCustomDeclares(doc, problems);
18064
18066
  skipChartColumns(doc, skipped);
18065
18067
  }
18066
- return { problems: dedupe(problems), skipped: dedupeSkipped(skipped) };
18068
+ return { problems: dedupe(problems), skipped: dedupeSkipped(skipped), warnings: dedupe(warnings) };
18067
18069
  }
18068
18070
  function checkCustomDeclares(doc, problems) {
18069
18071
  for (const problem5 of declaresProblems2(doc)) {
@@ -18883,7 +18885,7 @@ function checkDrillTargets(doc, problems) {
18883
18885
  const row = raw;
18884
18886
  if (row["data"] !== void 0 && row["data"] !== null) continue;
18885
18887
  const drill = list2(row["drill"]).filter((name) => typeof name === "string");
18886
- if (drill.length === 0) continue;
18888
+ if (drill.length === 0 || !menuless(row)) continue;
18887
18889
  const offered = new Set(drill.map((name) => name.toLowerCase()));
18888
18890
  const listed = JSON.stringify(drill);
18889
18891
  if (row["kind"] === "breakdown") {
@@ -18893,7 +18895,7 @@ function checkDrillTargets(doc, problems) {
18893
18895
  problems.push({
18894
18896
  code: "drill-needs-dimension",
18895
18897
  pointer: pointer("data", "widgets", id, "drill"),
18896
- message: `this breakdown is cut by ${JSON.stringify(dimension)} and its drill list ${listed} does not name it, so no legend row answers a click \u2014 the card looks drillable and is not.`,
18898
+ message: `this breakdown gets no point menu, so a click on it is the drill itself; it is cut by ${JSON.stringify(dimension)} and its drill list ${listed} does not name it, so no legend row answers a click \u2014 the card looks drillable and is not.`,
18897
18899
  fix: `Put ${JSON.stringify(dimension)} first in drill \u2014 ${JSON.stringify([dimension, ...drill])}: the clicked slice is a value of the card's own dimension, and the levels after it are where the grid goes next.`
18898
18900
  });
18899
18901
  continue;
@@ -18905,11 +18907,43 @@ function checkDrillTargets(doc, problems) {
18905
18907
  problems.push({
18906
18908
  code: "drill-needs-dimension",
18907
18909
  pointer: pointer("data", "widgets", id, "drill"),
18908
- message: `this table's drill list ${listed} names none of its columns (${keys2.map((key) => JSON.stringify(key)).join(", ")}), and a cell drills only when its column key is in drill \u2014 so no cell answers a click.`,
18910
+ message: `this table gets no point menu, so a click on it is the drill itself; its drill list ${listed} names none of its columns (${keys2.map((key) => JSON.stringify(key)).join(", ")}), and a cell drills only when its column key is in drill \u2014 so no cell answers a click.`,
18909
18911
  fix: `Add the column a reader clicks to drill \u2014 e.g. ${JSON.stringify([keys2[0], ...drill])} \u2014 naming the grid's own dimension column first.`
18910
18912
  });
18911
18913
  }
18912
18914
  }
18915
+ function menuless(row) {
18916
+ if (row["compute"] || row["transform"] !== void 0 && row["transform"] !== null) return true;
18917
+ const source = row["source"];
18918
+ if (!isObject4(source) || "app_table" in source || "call" in source) return true;
18919
+ if ("metric_id" in source) return Boolean(source["drill_rows"]) && typeof row["value_field"] !== "string";
18920
+ if (!addressesTable(source)) return true;
18921
+ const measures = list2(source["measures"]).length > 0 ? list2(source["measures"]) : source["measure"] ? [source["measure"]] : [];
18922
+ const fields = measures.map((one) => obj(one)["field"]);
18923
+ const named12 = typeof row["value_field"] === "string" && fields.includes(row["value_field"]);
18924
+ return !(named12 || fields.length === 1);
18925
+ }
18926
+ function addressesTable(source) {
18927
+ return source["address"] === "id" || source["address"] === "alias" || Boolean(source["table_alias"]) || source["table_id"] !== void 0 && source["table_id"] !== null;
18928
+ }
18929
+ function checkAggOrAccountType(doc, warnings) {
18930
+ const widgets = obj(obj(doc["data"])["widgets"]);
18931
+ const declared = (value) => typeof value === "string" && value.trim() !== "";
18932
+ for (const [id, raw] of Object.entries(widgets)) {
18933
+ if (id.startsWith("_") || !isObject4(raw)) continue;
18934
+ const row = raw;
18935
+ if (row["kind"] !== "kpi" && row["kind"] !== "series") continue;
18936
+ if (!isObject4(row["source"])) continue;
18937
+ if (["data", "compute", "transform", "shape"].some((key) => row[key] !== void 0 && row[key] !== null)) continue;
18938
+ if (declared(row["agg"]) || declared(row["account_type"])) continue;
18939
+ warnings.push({
18940
+ code: "agg-or-account-type",
18941
+ pointer: pointer("data", "widgets", id),
18942
+ message: `this ${row["kind"]} declares neither "agg" nor "account_type", so its figure sums its months \u2014 a quarter or a year of a balance (cash, assets, liabilities, equity, receivables, payables, inventory) would show three or twelve balances added up.`,
18943
+ fix: 'If it is a balance, add "account_type": "asset" (or "liability", "equity"), or "agg": "last", so a quarter or year shows the closing month; if it is a flow (revenue, expenses), add "account_type": "revenue" (or "expense") to say so and silence this.'
18944
+ });
18945
+ }
18946
+ }
18913
18947
  function checkPairing(doc, problems) {
18914
18948
  const data = doc["data"];
18915
18949
  if (!isObject4(data) || !isObject4(data["widgets"])) return;
@@ -27102,7 +27136,7 @@ var kit_default = {
27102
27136
  fmt: "dr-fmt@1.0.0",
27103
27137
  markdown: "dr-md@1.0.0",
27104
27138
  uiKit: "ui-kit/v3",
27105
- widgets: "dr-widgets@1.1.2"
27139
+ widgets: "dr-widgets@1.2.1"
27106
27140
  };
27107
27141
 
27108
27142
  // ../flows/appspace-builder/kit/kit.json
@@ -27263,10 +27297,11 @@ async function runCompile(dir, opts) {
27263
27297
  } finally {
27264
27298
  client?.cleanup();
27265
27299
  }
27266
- const { problems, skipped } = validateContract(contract, catalog);
27300
+ const { problems, skipped, warnings } = validateContract(contract, catalog);
27267
27301
  report.validate = {
27268
27302
  problems,
27269
27303
  checks_skipped: skipped,
27304
+ warnings,
27270
27305
  catalog: {
27271
27306
  source: catalog.source,
27272
27307
  server: catalog.server ?? null,
@@ -27365,6 +27400,7 @@ async function afterWrite(dir, target, kind, contract, built, report, kit, skipp
27365
27400
  }
27366
27401
  report.verify = runVerify(target, kind, report.app_id, kit);
27367
27402
  report.verify.warnings = [
27403
+ ...(report.validate.warnings ?? []).map((one) => `${one.code} ${one.pointer}: ${one.message} ${one.fix}`),
27368
27404
  ...(built.warnings ?? []).map((one) => `${one.code} ${one.pointer ?? "/"}: ${one.message}`),
27369
27405
  ...report.verify.warnings ?? []
27370
27406
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarails-ai/dr-appspace-cli",
3
- "version": "0.12.4",
3
+ "version": "0.12.6",
4
4
  "description": "Datarails App Space CLI — build, try, push and publish App Space apps",
5
5
  "type": "module",
6
6
  "engines": {